diff --git a/.gitattributes b/.gitattributes index ed268a11ca73..c12898317936 100644 --- a/.gitattributes +++ b/.gitattributes @@ -21,7 +21,6 @@ utils/ export-ignore .php-cs-fixer.dist.php export-ignore .php-cs-fixer.no-header.php export-ignore .php-cs-fixer.tests.php export-ignore -.php-cs-fixer.user-guide.php export-ignore structarmed-baseline.php export-ignore structarmed.php export-ignore phpstan-baseline.php export-ignore @@ -35,8 +34,6 @@ rector.php export-ignore AGENTS.md export-ignore # source user guide -user_guide_src/ export-ignore docs/ export-ignore mkdocs.yml export-ignore -.nojekyll export-ignore phpdoc.dist.xml export-ignore diff --git a/.github/scripts/deploy-userguide b/.github/scripts/deploy-userguide index e664ac1b7ff5..acc4f079518e 100755 --- a/.github/scripts/deploy-userguide +++ b/.github/scripts/deploy-userguide @@ -33,9 +33,11 @@ echo "Merging files from $1 to $2" # Prepare the source cd $SOURCE git checkout master -cd user_guide_src -make html -make epub +export NO_MKDOCS_2_WARNING=1 +export SITE_URL=https://codeigniter.com/user_guide/ +mkdocs build --strict +python admin/llms.py +python admin/anchors.py # Prepare the target cd $TARGET @@ -49,11 +51,7 @@ cp -Rf ${SOURCE}/LICENSE ./ cp -Rf ${SOURCE}/admin/userguide/. ./ # Copy files -cp -Rf ${SOURCE}/user_guide_src/build/html ./docs -cp -Rf ${SOURCE}/user_guide_src/build/epub/CodeIgniter.epub ./CodeIgniter${VERSION}.epub - -# Ensure underscore prefixed files are published -touch ${TARGET}/docs/.nojekyll +cp -Rf ${SOURCE}/site ./docs # Commit the changes git add . diff --git a/.github/workflows/deploy-distributables.yml b/.github/workflows/deploy-distributables.yml index 38423b4e5229..ce58764cd57c 100644 --- a/.github/workflows/deploy-distributables.yml +++ b/.github/workflows/deploy-distributables.yml @@ -176,10 +176,10 @@ jobs: with: python-version: '3.12' - - name: Install Sphinx + - name: Install MkDocs run: | python -m pip install --upgrade pip - pip install -r ./source/user_guide_src/requirements.txt + pip install -r ./source/docs/requirements.txt - name: Chmod run: chmod +x ./source/.github/scripts/deploy-userguide diff --git a/.github/workflows/deploy-userguide-latest.yml b/.github/workflows/deploy-userguide-latest.yml index 65b1fe77b0be..98cf7a6b6c33 100644 --- a/.github/workflows/deploy-userguide-latest.yml +++ b/.github/workflows/deploy-userguide-latest.yml @@ -1,8 +1,6 @@ # When changes are pushed to the develop branch, -# build the current version of the User Guide -# with Sphinx and deploy it to the gh-pages branch. -# -# @todo Consolidate checkouts +# build the develop and the next minor versions of the User Guide +# with MkDocs and deploy them to GitHub Pages. name: Deploy User Guide (latest) on: @@ -10,74 +8,94 @@ on: branches: - 'develop' paths: - - 'user_guide_src/**' + - 'docs/**' + - 'mkdocs.yml' + - 'admin/anchors.py' + - 'admin/llms.py' + - '.github/workflows/deploy-userguide-latest.yml' + workflow_dispatch: + +concurrency: + group: pages + cancel-in-progress: false permissions: contents: read jobs: build: - name: Deploy to gh-pages - permissions: - # Allow push to branch gh-pages - contents: write + name: Build User Guide if: (github.repository == 'codeigniter4/CodeIgniter4') runs-on: ubuntu-24.04 steps: - - name: Checkout + - name: Checkout develop uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + path: develop persist-credentials: false - - name: Setup PHP - uses: shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962 # 2.40.0 + - name: Checkout next minor + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - php-version: '8.2' - coverage: none + ref: '4.8' + path: next + persist-credentials: false - name: Setup Python uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 with: python-version: '3.12' - - name: Install Sphinx + - name: Install MkDocs run: | python -m pip install --upgrade pip - pip install -r user_guide_src/requirements.txt + pip install -r develop/docs/requirements.txt - # Build the latest User Guide - - name: Build Docs with Sphinx - run: make html - working-directory: user_guide_src + - name: Setup Pages + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - - name: Add "Edit this page" links + - name: Build the sites + env: + NO_MKDOCS_2_WARNING: '1' + BASE_URL: https://codeigniter4.github.io/CodeIgniter4 run: | - cd user_guide_src - # Fix permissions - sudo chown -R runner:docker build/html/ - php add-edit-this-page build/html/ + mkdir pages + + for name in develop next; do + if [ ! -f "${name}/mkdocs.yml" ]; then + echo "::notice::The ${name} branch has no mkdocs.yml, so it is not deployed." + continue + fi + + ( + cd "${name}" + SITE_URL="${BASE_URL}/${name}/" mkdocs build --strict + python admin/llms.py + python admin/anchors.py + ) + + mv "${name}/site" "pages/${name}" + done + + cp develop/docs/overrides/assets/versions.json pages/versions.json + echo '' > pages/index.html - # Create an artifact of the html output - name: Upload artifact - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: - name: HTML Documentation - path: user_guide_src/build/html/ - - # Commit changes to the gh-pages branch - - name: Commit changes - run: | - git clone https://github.com/codeigniter4/CodeIgniter4.git --branch gh-pages --single-branch gh-pages - cp -r user_guide_src/build/html/* gh-pages/ - cd gh-pages - git config --local user.email "action@github.com" - git config --local user.name "${GITHUB_ACTOR}" - git add . - # Ignore failures due to lack of changes - git commit -m "Update User Guide" -a || true + path: pages - - name: Push changes - working-directory: gh-pages - env: - PUSH_TOKEN: ${{ secrets.ACCESS_TOKEN }} - run: bash ${GITHUB_WORKSPACE}/.github/scripts/secure-git-push https://github.com/codeigniter4/CodeIgniter4.git HEAD:gh-pages + deploy: + name: Deploy to GitHub Pages + needs: build + runs-on: ubuntu-24.04 + permissions: + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy + id: deployment + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.github/workflows/test-userguide.yml b/.github/workflows/test-userguide.yml index 6cbc34d341a8..73d4de4cbed5 100644 --- a/.github/workflows/test-userguide.yml +++ b/.github/workflows/test-userguide.yml @@ -1,13 +1,12 @@ # When a Pull Request is opened that modifies # the User Guide source, build the User Guide -# with Sphinx or MkDocs and let the contributor +# with MkDocs and let the contributor # know of any errors. name: Test User Guide on: pull_request: paths: - - 'user_guide_src/**' - 'docs/**' - 'mkdocs.yml' - 'admin/anchors.py' @@ -23,33 +22,8 @@ permissions: contents: read jobs: - syntax_check: - name: Check User Guide syntax - runs-on: ubuntu-24.04 - - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Setup Python - uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0 - with: - python-version: '3.12' - - - name: Install Sphinx - run: | - python -m pip install --upgrade pip - pip install -r user_guide_src/requirements.txt - - - name: Detect usage of tabs in RST files - run: php utils/check_tabs_in_rst.php - - - name: Build Docs with Sphinx - run: make html SPHINXOPTS="-W --keep-going -w /tmp/sphinx-log" - working-directory: user_guide_src - markdown_check: - name: Check Markdown User Guide + name: Check User Guide runs-on: ubuntu-24.04 steps: diff --git a/.github/workflows/verify-release.yml b/.github/workflows/verify-release.yml index 842c2407a4c5..711cac7bf4a8 100644 --- a/.github/workflows/verify-release.yml +++ b/.github/workflows/verify-release.yml @@ -1,6 +1,6 @@ # When a release is published, verify that the release pipeline delivered # everything: the distributable repos, the new framework version on -# Packagist, and the user guide with its ePub. +# Packagist, and the user guide. # # Use "Run workflow" with the release tag to verify an existing release. name: Verify Release @@ -123,23 +123,21 @@ jobs: timeout-minutes: 30 steps: - - name: Check that the ePub was added + - name: Check that the user guide was added env: GH_TOKEN: ${{ github.token }} run: | - version="${TAG#v}" - for i in $(seq 1 30); do - if gh api "repos/codeigniter4/userguide/contents/CodeIgniter${version}.epub" --jq '.name' > /dev/null 2>&1; then - echo "CodeIgniter${version}.epub is in the userguide repo." + if gh api "repos/codeigniter4/userguide/contents/docs/llms.txt" --jq '.name' > /dev/null 2>&1; then + echo "docs/llms.txt is in the userguide repo." exit 0 fi - echo "Attempt ${i}: CodeIgniter${version}.epub is not yet in the userguide repo." + echo "Attempt ${i}: docs/llms.txt is not yet in the userguide repo." sleep 30 done - echo "Timed out waiting for CodeIgniter${version}.epub." + echo "Timed out waiting for docs/llms.txt." exit 1 - name: Check that the user guide workflows succeeded diff --git a/.nojekyll b/.nojekyll deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index ad6ffacb8f0c..227d477c379d 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -30,7 +30,6 @@ __FILE__, __DIR__ . '/.php-cs-fixer.no-header.php', __DIR__ . '/.php-cs-fixer.tests.php', - __DIR__ . '/.php-cs-fixer.user-guide.php', __DIR__ . '/preload.php', __DIR__ . '/rector.php', __DIR__ . '/spark', diff --git a/.php-cs-fixer.user-guide.php b/.php-cs-fixer.user-guide.php deleted file mode 100644 index 6b925ee8b0b7..000000000000 --- a/.php-cs-fixer.user-guide.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -use PhpCsFixer\ConfigInterface; -use PhpCsFixer\Finder; - -/** @var ConfigInterface $config */ -$config = require __DIR__ . '/.php-cs-fixer.dist.php'; - -$finder = Finder::create() - ->files() - ->in([ - __DIR__ . '/user_guide_src/source', - ]) - ->notPath([ - 'ci3sample/', - 'database/query_builder/075.php', - 'libraries/sessions/016.php', - 'outgoing/response/031.php', - 'outgoing/response/032.php', - ]); - -$overrides = [ - 'echo_tag_syntax' => false, - 'header_comment' => false, - 'php_unit_internal_class' => false, - 'no_unused_imports' => false, - 'class_attributes_separation' => false, - 'fully_qualified_strict_types' => [ - 'import_symbols' => false, - 'leading_backslash_in_global_namespace' => true, - ], -]; - -return $config - ->setFinder($finder) - ->setCacheFile('build/.php-cs-fixer.user-guide.cache') - ->setRules(array_merge($config->getRules(), $overrides)); diff --git a/admin/RELEASE.md b/admin/RELEASE.md index aba653752e43..fac7242b805d 100644 --- a/admin/RELEASE.md +++ b/admin/RELEASE.md @@ -403,7 +403,7 @@ The workflow does the following: - Waits for the "[Deploy Distributable Repos](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/deploy-distributables.yml)" workflow to update **framework**, **appstarter** and **userguide**. - Installs `appstarter` from Packagist, checks that it pulls framework `v$VERSION`, and runs its tests. -- Checks that the user guide deployments succeeded ("Deploy Production" and "pages build and deployment" in the **userguide** repository) and that **CodeIgniter$VERSION.epub** was added. +- Checks that the user guide deployments succeeded ("Deploy Production" and "pages build and deployment" in the **userguide** repository) and that **docs/llms.txt** was added. Check: the workflow passes. @@ -523,22 +523,16 @@ Merge it with **Squash and merge**. The release is complete. ## Appendix -### Sphinx Installation +### MkDocs Installation -You may need to install Sphinx and its dependencies before you build the User Guide. - -This worked on Ubuntu 20.04: - -```bash -sudo apt install python3-sphinx -``` +You may need to install MkDocs and its dependencies before you build the User Guide. It needs Python 3.11 or newer. ```bash -sudo pip3 install sphinxcontrib-phpdomain +python3 -m venv venv ``` ```bash -sudo pip3 install sphinx_rtd_theme +venv/bin/pip install -r docs/requirements.txt ``` ### Manual User Guide Process @@ -547,34 +541,35 @@ sudo pip3 install sphinx_rtd_theme > This process is normally not needed. The "Deploy Distributable Repos" action builds and deploys the User Guide when a release is published. > Follow these steps only if the automatic deployment fails. -1. In the **CodeIgniter4** repository, enter the **user_guide_src** directory and clear out any old build files: +1. In the **CodeIgniter4** repository, clear out any old build files: ```bash - cd user_guide_src - rm -rf build/ + rm -rf site/ ``` -2. Build the HTML version, then the ePub version: +2. Build the site, the llms files and the anchor aliases: + + ```bash + SITE_URL=https://codeigniter.com/user_guide/ venv/bin/mkdocs build --strict + ``` ```bash - make html + venv/bin/python admin/llms.py ``` ```bash - make epub + venv/bin/python admin/anchors.py ``` 3. Switch to the **userguide** repository and create the branch `release-$VERSION`. -4. Replace **docs/** with **CodeIgniter4/user_guide_src/build/html**. -5. Make sure the file **docs/.nojekyll** exists. Without it, GitHub Pages ignores folders that start with an underscore. -6. Copy **CodeIgniter4/user_guide_src/build/epub/CodeIgniter.epub** to **./CodeIgniter$VERSION.epub**. -7. Commit the changes with the message `Update for $VERSION` and push to `origin`. -8. Create a pull request from `release-$VERSION` to `develop`, with the title `Update for $VERSION` and a blank description, and merge it. -9. Create a release in the **userguide** repository: +4. Replace **docs/** with **CodeIgniter4/site**. +5. Commit the changes with the message `Update for $VERSION` and push to `origin`. +6. Create a pull request from `release-$VERSION` to `develop`, with the title `Update for $VERSION` and a blank description, and merge it. +7. Create a release in the **userguide** repository: - Version: `v$VERSION` - Title: `CodeIgniter $VERSION User Guide` - Description: `CodeIgniter $VERSION User Guide` -10. Watch the "github pages" environment to make sure the deployment succeeds. +8. Watch the "github pages" environment to make sure the deployment succeeds. The User Guide website should update itself through the deploy GitHub Action. If that fails, the server must be updated manually. See the repository and hosting details in the deploy script of the User Guide repository. diff --git a/admin/next-changelog-minor.rst b/admin/next-changelog-minor.rst deleted file mode 100644 index c22f0be7d9f3..000000000000 --- a/admin/next-changelog-minor.rst +++ /dev/null @@ -1,84 +0,0 @@ -################# -Version {version} -################# - -Release Date: Unreleased - -**{version} release of CodeIgniter4** - -.. contents:: - :local: - :depth: 3 - -********** -Highlights -********** - -- TBD - -******** -BREAKING -******** - -Behavior Changes -================ - -Interface Changes -================= - -Method Signature Changes -======================== - -************ -Enhancements -************ - -Commands -======== - -Testing -======= - -Database -======== - -Query Builder -------------- - -Forge ------ - -Others ------- - -Model -===== - -Libraries -========= - -Helpers and Functions -===================== - -Others -====== - -*************** -Message Changes -*************** - -******* -Changes -******* - -************ -Deprecations -************ - -********** -Bugs Fixed -********** - -See the repo's -`CHANGELOG.md `_ -for a complete list of bugs fixed. diff --git a/admin/next-changelog-patch.rst b/admin/next-changelog-patch.rst deleted file mode 100644 index ed2ba70570b3..000000000000 --- a/admin/next-changelog-patch.rst +++ /dev/null @@ -1,35 +0,0 @@ -################# -Version {version} -################# - -Release Date: Unreleased - -**{version} release of CodeIgniter4** - -.. contents:: - :local: - :depth: 3 - -******** -BREAKING -******** - -*************** -Message Changes -*************** - -******* -Changes -******* - -************ -Deprecations -************ - -********** -Bugs Fixed -********** - -See the repo's -`CHANGELOG.md `_ -for a complete list of bugs fixed. diff --git a/admin/next-upgrading-guide.rst b/admin/next-upgrading-guide.rst deleted file mode 100644 index e38bebe3c4a7..000000000000 --- a/admin/next-upgrading-guide.rst +++ /dev/null @@ -1,55 +0,0 @@ -############################## -Upgrading from {version} to {version} -############################## - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -********************** -Mandatory File Changes -********************** - -**************** -Breaking Changes -**************** - -********************* -Breaking Enhancements -********************* - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to -these files being outside of the **system** scope they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist - with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) -and it is recommended that you merge the updated versions with your application: - -Config ------- - -- @TODO - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; -many will be simple comments or formatting that have no effect on the runtime: - -- @TODO diff --git a/admin/pre-commit b/admin/pre-commit index 19bec4f4726b..79a274a25b73 100644 --- a/admin/pre-commit +++ b/admin/pre-commit @@ -2,7 +2,6 @@ PROJECT=`php -r "echo dirname(dirname(dirname(realpath('$0'))));"` STAGED_PHP_FILES=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.php$` -STAGED_RST_FILES=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.rst$` echo "Starting CodeIgniter precommit..." @@ -32,9 +31,4 @@ if [ "$FILES" != "" ]; then fi fi -if [ "$STAGED_RST_FILES" != "" ]; then - echo "Checking for tabs in RST files" - php ./utils/check_tabs_in_rst.php -fi - exit $? diff --git a/admin/update-upgrade-guide.php b/admin/update-upgrade-guide.php index d0959bf53b5e..08c6a45f104e 100644 --- a/admin/update-upgrade-guide.php +++ b/admin/update-upgrade-guide.php @@ -86,7 +86,7 @@ function bullets(array $items): string ':!docs/', ':!system/', ':!tests/', - ':!user_guide_src/', + ':!user_guide_src/', // Remove after 4.7.7: tags up to v4.7.6 still contain this folder. ':!utils/', ':!.*', ':!mkdocs.yml', diff --git a/admin/userguide/.gitattributes b/admin/userguide/.gitattributes new file mode 100644 index 000000000000..83aff3d5f4da --- /dev/null +++ b/admin/userguide/.gitattributes @@ -0,0 +1,9 @@ +# The Composer package ships the Markdown pages and the llms files only. +.github/ export-ignore +.gitattributes export-ignore +.gitignore export-ignore +docs/**/*.html export-ignore +docs/assets/ export-ignore +docs/search/ export-ignore +docs/sitemap.xml export-ignore +docs/sitemap.xml.gz export-ignore diff --git a/admin/userguide/README.md b/admin/userguide/README.md index 0ea07075db61..be7327d018a4 100644 --- a/admin/userguide/README.md +++ b/admin/userguide/README.md @@ -7,6 +7,10 @@ More information can be found at the [official site](http://codeigniter.com). It is built automatically as part of the framework release workflow, and pull requests are not accepted here. +The **docs** folder holds the built site. Each page is also available as a Markdown file +next to its HTML, and **docs/llms.txt** and **docs/llms-full.txt** list them for AI tools. +Install the Markdown pages and the llms files with `composer require codeigniter4/userguide`. + Development is done in the [main repository](https://github.com/codeigniter4/codeigniter4). If you find problems with the user guide, please submit a correcting pull request there. diff --git a/admin/userguide/composer.json b/admin/userguide/composer.json new file mode 100644 index 000000000000..add76aa49f36 --- /dev/null +++ b/admin/userguide/composer.json @@ -0,0 +1,12 @@ +{ + "name": "codeigniter4/userguide", + "description": "The CodeIgniter 4 user guide as Markdown", + "license": "MIT", + "type": "library", + "homepage": "https://codeigniter.com/user_guide/", + "support": { + "forum": "https://forum.codeigniter.com/", + "source": "https://github.com/codeigniter4/CodeIgniter4", + "docs": "https://codeigniter.com/user_guide/" + } +} diff --git a/composer.json b/composer.json index f47e5c8ba355..745c817e5e75 100644 --- a/composer.json +++ b/composer.json @@ -102,14 +102,12 @@ ], "cs": [ "Composer\\Config::disableProcessTimeout", - "utils/vendor/bin/php-cs-fixer check --ansi --verbose --diff --config=.php-cs-fixer.user-guide.php", "utils/vendor/bin/php-cs-fixer check --ansi --verbose --diff --config=.php-cs-fixer.no-header.php", "utils/vendor/bin/php-cs-fixer check --ansi --verbose --diff --config=.php-cs-fixer.tests.php", "utils/vendor/bin/php-cs-fixer check --ansi --verbose --diff" ], "cs-fix": [ "Composer\\Config::disableProcessTimeout", - "utils/vendor/bin/php-cs-fixer fix --ansi --verbose --diff --config=.php-cs-fixer.user-guide.php", "utils/vendor/bin/php-cs-fixer fix --ansi --verbose --diff --config=.php-cs-fixer.no-header.php", "utils/vendor/bin/php-cs-fixer fix --ansi --verbose --diff --config=.php-cs-fixer.tests.php", "utils/vendor/bin/php-cs-fixer fix --ansi --verbose --diff" diff --git a/user_guide_src/.htaccess b/user_guide_src/.htaccess deleted file mode 100644 index 3462048add78..000000000000 --- a/user_guide_src/.htaccess +++ /dev/null @@ -1,6 +0,0 @@ - - Require all denied - - - Deny from all - diff --git a/user_guide_src/Makefile b/user_guide_src/Makefile deleted file mode 100644 index d0c3cbf1020d..000000000000 --- a/user_guide_src/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = source -BUILDDIR = build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/user_guide_src/README.rst b/user_guide_src/README.rst deleted file mode 100644 index 049c9f13a472..000000000000 --- a/user_guide_src/README.rst +++ /dev/null @@ -1,127 +0,0 @@ -###################### -CodeIgniter User Guide -###################### - -****************** -Setup Instructions -****************** - -The CodeIgniter user guide uses Sphinx to manage the documentation and -output it to various formats. Pages are written in human-readable -`ReStructured Text `_ format. - -Prerequisites -============= - -Python ------- - -Sphinx requires Python 3.5+, which may already be installed if you are running -OS X or Linux. You can confirm in a Terminal window by executing ``python`` -or ``python3``. - -.. code-block:: bash - - python --version - Python 2.7.17 - - python3 --version - Python 3.6.9 - - # For Windows using the Python Launcher - py -3 --version - Python 3.8.1 - -If you're not on 3.5+, go ahead and install the latest 3.x version from -`Python.org `_. Linux users should use their -operating systems' built-in Package Managers to update. - -pip ---- - -Now that you have Python 3.x up and running, we will be installing -`pip `_ (The Python Package Installer). - -You can check if you have pip installed with ``pip`` or ``pip3``. -As you can see pip follow the same naming convention as Python. -Please take note that it should say ``python 3.x`` at the very end. - -.. code-block:: bash - - pip --version - pip 9.0.1 from /usr/lib/python2.7/dist-packages (python 2.7) - - pip3 --version - pip 9.0.1 from /usr/lib/python3/dist-packages (python 3.6) - - # For Windows using the Python Launcher - py -3 -m pip --version - pip 20.0.2 from C:\Users\\AppData\Local\Programs\Python\Python38\lib\site-packages\pip (python 3.8) - -Linux -^^^^^ - -`Installing pip/setuptools/wheel with Linux Package Managers -`_ - -Others -^^^^^^ - -pip is already installed if you are using Python 3.5+ downloaded from -`Python.org `_. - -Installation -============ - -Now we need to install Sphinx and it's dependencies. Choose ``pip`` or ``pip3`` -depending on operative system. After this step you need to restart your Terminal -window as Python won't find all applications we just installed otherwise. - -.. code-block:: bash - - pip install -r user_guide_src/requirements.txt - - pip3 install -r user_guide_src/requirements.txt - - # For Windows using the Python Launcher - py -3 -m pip install -r user_guide_src/requirements.txt - -It's time to wrap things up and generate the documentation. - -.. code-block:: bash - - cd user_guide_src - make html - -Editing and Creating Documentation -================================== - -All of the source files exist under *source/* and is where you will add new -documentation or modify existing documentation. Just as with code changes, -we recommend working from feature branches and making pull requests to -the *develop* branch of this repo. - -So where's the HTML? -==================== - -Obviously, the HTML documentation is what we care most about, as it is the -primary documentation that our users encounter. Since revisions to the built -files are not of value, they are not under source control. This also allows -you to regenerate as necessary if you want to "preview" your work. Generating -the HTML is very simple. From the root directory of your user guide repo -fork issue the command you used at the end of the installation instructions:: - - make html - -You will see it do a whiz-bang compilation, at which point the fully rendered -user guide and images will be in *build/html/*. After the HTML has been built, -each successive build will only rebuild files that have changed, saving -considerable time. If for any reason you want to "reset" your build files, -simply delete the *build* folder's contents and rebuild. - -*************** -Style Guideline -*************** - -Please refer to /contributing/documentation.rst for general guidelines for -using Sphinx to document CodeIgniter. diff --git a/user_guide_src/add-edit-this-page b/user_guide_src/add-edit-this-page deleted file mode 100755 index cede3f406150..000000000000 --- a/user_guide_src/add-edit-this-page +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env php -' . PHP_EOL; - echo ' e.g: ' . $argv[0] . ' user_guide_src/build/html/' . PHP_EOL; - - exit(1); -} - -$dir = realpath($argv[1]); - -if ($dir === false || ! is_dir($dir)) { - throw new RuntimeException('Cannot find directory: ' . $dir); -} - -$iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( - $dir, - FilesystemIterator::CURRENT_AS_FILEINFO | - FilesystemIterator::KEY_AS_PATHNAME | - FilesystemIterator::SKIP_DOTS - ) -); - -$files = new RegexIterator( - $iterator, - '/\A.+\.html\z/', - RecursiveRegexIterator::MATCH -); - -foreach ($files as $filePath => $fileInfo) { - echo 'processing... ' . PHP_EOL; - - $uriPath = str_replace('.html', '.rst', str_replace($dir, '', $filePath)); - $gitHubLink = 'Edit this page'; - - $content = file_get_contents($filePath); - - $pattern = '!">Edit this page!u'; - if (preg_match($pattern, $content) === 1) { - // Move the cursor up 1 line - echo "\033[1A"; - echo 'skip: ' . $filePath . PHP_EOL; - - continue; - } - - $pattern = '/
/u'; - $content = preg_replace( - $pattern, - '
' . PHP_EOL . $gitHubLink . PHP_EOL, - $content - ); - - file_put_contents($filePath, $content, LOCK_EX); - - // Move the cursor up 1 line - echo "\033[1A"; - echo 'done: ' . $filePath . PHP_EOL; -} diff --git a/user_guide_src/cilexer/pycilexer.egg-info/top_level.txt b/user_guide_src/cilexer/pycilexer.egg-info/top_level.txt deleted file mode 100644 index 2f88e1d75272..000000000000 --- a/user_guide_src/cilexer/pycilexer.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -cilexer diff --git a/user_guide_src/ghpages.rst b/user_guide_src/ghpages.rst deleted file mode 100644 index 682c1eee49ce..000000000000 --- a/user_guide_src/ghpages.rst +++ /dev/null @@ -1,52 +0,0 @@ -######################### -Generating the User Guide -######################### - -The intent is, eventually, for the in-progress user guide to be automatically -generated as part of a PR merge. This writeup explains how it can be done manually -in the meantime. - -The user guide takes advantage of GitHub pages, where the "gh-pages" branch of -a repo, containing HTML only, is accessible through `github.io -`_. - -Setup for Repo Maintainers -========================== - -You already have the repo cloned into ``CodeIgniter4`` in a projects folder. -Create another folder at the same level as this, ``CodeIgniter4-guide``. -Clone the CodeIgniter4 repo again, into ``CodeIgniter4-guide/html``. - -Inside the ``html`` folder, ``git checkout gh-pages``. -All you should see is the generated HTML for the user guide. - -Re-generating the User Guide -============================ - -In the ``user_guide_src`` folder, you generate a conventional user guide, -for testing, using the command:: - - make html - -An additional target has been configured, which will generate the same -HTML but inside the ``html`` folder of the second repo clone:: - - make ghpages - -After making this target, update the online user guide by switching to -the ``CodeIgniter4-guide/html`` folder, and then:: - - git add . - git commit -S -m "Suitable comment" - git push origin gh-pages - -Process -======= - -There should be only one maintainer doing this, to avoid collisions. -The user guide would get regenerated whenever there is a PR merge -that affects it. - -Note: You might have to delete the ``user_guide_src/doctree`` folder before -making the ``gh-pages`` version of the guide, to make sure that the TOC -is properly rebuilt, especially if you are rebuilding the ``html`` target a number of times. diff --git a/user_guide_src/make.bat b/user_guide_src/make.bat deleted file mode 100644 index 9534b018135e..000000000000 --- a/user_guide_src/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=source -set BUILDDIR=build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/user_guide_src/requirements.txt b/user_guide_src/requirements.txt deleted file mode 100644 index caf5a68f9a1c..000000000000 --- a/user_guide_src/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -sphinx>=8.0.0,<9.0.0 -sphinxcontrib-phpdomain>=0.11.0 -docutils>=0.19 -sphinx-rtd-theme>=3.0.0 -jinja2>=3.1.3,<4.0.0 diff --git a/user_guide_src/source/.nojekyll b/user_guide_src/source/.nojekyll deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/user_guide_src/source/_static/ci-logo-text.svg b/user_guide_src/source/_static/ci-logo-text.svg deleted file mode 100644 index 964782602e10..000000000000 --- a/user_guide_src/source/_static/ci-logo-text.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/user_guide_src/source/_static/css/citheme.css b/user_guide_src/source/_static/css/citheme.css deleted file mode 100644 index fae4909dd62c..000000000000 --- a/user_guide_src/source/_static/css/citheme.css +++ /dev/null @@ -1,354 +0,0 @@ -/* RTD Theme ---------------------------------------------------------------- */ - -@import 'theme.css'; - -/* Raleway Font ------------------------------------------------------------- */ - -@font-face { - font-family: 'Raleway'; - font-style: normal; - font-weight: 200; - src: url('../fonts/Raleway/raleway-v14-latin-200.eot'); /* IE9 Compat Modes */ - src: local('Raleway ExtraLight'), local('Raleway-ExtraLight'), - url('../fonts/Raleway/raleway-v14-latin-200.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('../fonts/Raleway/raleway-v14-latin-200.woff2') format('woff2'), /* Super Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-200.woff') format('woff'), /* Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-200.ttf') format('truetype'), /* Safari, Android, iOS */ - url('../fonts/Raleway/raleway-v14-latin-200.svg#Raleway') format('svg'); /* Legacy iOS */ -} - -@font-face { - font-family: 'Raleway'; - font-style: italic; - font-weight: 200; - src: url('../fonts/Raleway/raleway-v14-latin-200italic.eot'); /* IE9 Compat Modes */ - src: local('Raleway ExtraLight Italic'), local('Raleway-ExtraLightItalic'), - url('../fonts/Raleway/raleway-v14-latin-200italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('../fonts/Raleway/raleway-v14-latin-200italic.woff2') format('woff2'), /* Super Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-200italic.woff') format('woff'), /* Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-200italic.ttf') format('truetype'), /* Safari, Android, iOS */ - url('../fonts/Raleway/raleway-v14-latin-200italic.svg#Raleway') format('svg'); /* Legacy iOS */ -} - -@font-face { - font-family: 'Raleway'; - font-style: normal; - font-weight: 400; - src: url('../fonts/Raleway/raleway-v14-latin-regular.eot'); /* IE9 Compat Modes */ - src: local('Raleway'), local('Raleway-Regular'), - url('../fonts/Raleway/raleway-v14-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('../fonts/Raleway/raleway-v14-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-regular.woff') format('woff'), /* Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ - url('../fonts/Raleway/raleway-v14-latin-regular.svg#Raleway') format('svg'); /* Legacy iOS */ -} - -@font-face { - font-family: 'Raleway'; - font-style: italic; - font-weight: 400; - src: url('../fonts/Raleway/raleway-v14-latin-italic.eot'); /* IE9 Compat Modes */ - src: local('Raleway Italic'), local('Raleway-Italic'), - url('../fonts/Raleway/raleway-v14-latin-italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('../fonts/Raleway/raleway-v14-latin-italic.woff2') format('woff2'), /* Super Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-italic.woff') format('woff'), /* Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-italic.ttf') format('truetype'), /* Safari, Android, iOS */ - url('../fonts/Raleway/raleway-v14-latin-italic.svg#Raleway') format('svg'); /* Legacy iOS */ -} - -@font-face { - font-family: 'Raleway'; - font-style: normal; - font-weight: 700; - src: url('../fonts/Raleway/raleway-v14-latin-700.eot'); /* IE9 Compat Modes */ - src: local('Raleway Bold'), local('Raleway-Bold'), - url('../fonts/Raleway/raleway-v14-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('../fonts/Raleway/raleway-v14-latin-700.woff2') format('woff2'), /* Super Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-700.woff') format('woff'), /* Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */ - url('../fonts/Raleway/raleway-v14-latin-700.svg#Raleway') format('svg'); /* Legacy iOS */ -} - -@font-face { - font-family: 'Raleway'; - font-style: italic; - font-weight: 700; - src: url('../fonts/Raleway/raleway-v14-latin-700italic.eot'); /* IE9 Compat Modes */ - src: local('Raleway Bold Italic'), local('Raleway-BoldItalic'), - url('../fonts/Raleway/raleway-v14-latin-700italic.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ - url('../fonts/Raleway/raleway-v14-latin-700italic.woff2') format('woff2'), /* Super Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-700italic.woff') format('woff'), /* Modern Browsers */ - url('../fonts/Raleway/raleway-v14-latin-700italic.ttf') format('truetype'), /* Safari, Android, iOS */ - url('../fonts/Raleway/raleway-v14-latin-700italic.svg#Raleway') format('svg'); /* Legacy iOS */ -} - -/* General ------------------------------------------------------------------ */ - -body, p, legend { - font-family: "Raleway","Helvetica", "Arial", sans-serif; -} - -.wy-nav-content { - background-image: url('../img/ci-background.png'); - background-position: bottom right; - background-repeat: no-repeat; - background-size: 200px; -} - -/* Titles ------------------------------------------------------------------- */ - -h1, h2, h3, h4, h5, h6 { - font-family: "Raleway", "Helvetica", "Arial", sans-serif; -} - -h1 { - margin-bottom: 2rem; -} - -h2, h3 { - margin-bottom: 2rem; - margin-top: 3rem; -} - -/* Images ------------------------------------------------------------------- */ - -.rst-content img { - -webkit-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.75); - -moz-box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.75); - box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.75); - display: block; - height: auto!important; - margin: 3rem auto!important; - max-width: 700px; - width: 100%!important; -} - -.rst-content img.align-left { - margin-right: 2rem!important; - max-width: 375px; -} - -.rst-content img.align-right { - margin-left: 2rem!important; - max-width: 400px; -} - -/* Side Menu ---------------------------------------------------------------- */ - -.wy-nav-side { - background: #252525; -} - -.wy-side-nav-search { - background: #dd4814; -} - -.wy-side-nav-search .logo { - width: 100% !important; -} - -.wy-side-nav-search a { - color: #ffffff; -} - -.wy-side-nav-search input[type=text] { - border-color: #dd4815; -} - -.wy-nav-top { - background-color: #dd4814; -} - -.wy-nav-top a { - color: #ffffff!important; -} - -.wy-menu-vertical a:active { - background-color: #dd4814; -} - -.wy-nav-content { - max-width: 900px; -} - -.wy-nav-content-wrap a, .wy-nav-content-wrap a:visited { - color: #dd4814; -} - -.wy-nav-content-wrap a:hover, .wy-nav-content-wrap a:active { - color: #97310e; -} - -.wy-menu-vertical li span.toctree-expand { - margin-right: 0.65em; -} - -.wy-menu-vertical li span.toctree-expand::before { - display: none !important; -} - -/* Elements ----------------------------------------------------------------- */ - -.highlighted { - padding: 0px !important; - font-weight: inherit !important; - background-color: #f1d40f !important; -} - -/* override table width restrictions */ -.wy-table-responsive table td, .wy-table-responsive table th { - white-space: pre; -} - -.rst-content dl.class>dt { - margin-bottom: 1rem !important; -} - -.rst-content .section ol p, .rst-content .section ul p { - margin: 0; -} - -html.writer-html4 .rst-content dl:not(.docutils)>dt, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple)>dt { - background: #fdc894; - color: #434343; - border-top: solid 3px #dd4814; -} - -html.writer-html4 .rst-content dl:not(.docutils) code.descname, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) code.descname { - padding-right: 0.2rem; -} - -.rst-content dl.field-list { - margin-top: 1rem; - margin-bottom: 0.5rem; -} - -.rst-content dl.field-list dt, .rst-content dl.field-list p, -html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt { - font-size: 90%; -} - -html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list)>dt, -html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) dl:not(.field-list)>dt { - padding: 6px; -} - -.admonition { - margin-bottom: 2.5rem!important; - margin-top: 2rem; -} - -.highlight-console .highlight { - background-color: #fffff0; -} - -span.std, -span.pre { - text-wrap: nowrap; -} - -/* Messages ----------------------------------------------------------------- */ - -.rst-content .success { - background: #dff0d8; -} - -.rst-content .success .admonition-title { - background-color: #9ace25; -} - -.rst-content .info { - background: #e8eff1; -} - -.rst-content .info .admonition-title { - background: #5bc0de; -} - -.rst-content .important { - background: #f9f3f3; -} - -.rst-content .important .admonition-title { - background: #dd4814; -} - -.versionadded { - background: #dff0d8; - padding: 0 5px; -} - -.deprecated:not(.versionmodified) { - background: #f2dede; - padding: 0 5px; -} - -/* Footer ------------------------------------------------------------------- */ - -.rst-footer-buttons { - margin-bottom: 2.5rem; - margin-top: 2.5rem; -} - -/* Carbon Ads --------------------------------------------------------------- */ - -#carbonads { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, - Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif; -} - -#carbonads { - display: flex; - max-width: 330px; - background-color: hsla(0, 0%, 98%, 0.1); - border: 1px solid hsla(0, 0%, 98%, 0.15); - margin: 3em 1.5em; -} - -#carbonads a { - color: inherit; - text-decoration: none; -} - -#carbonads a:hover { - color: inherit; -} - -#carbonads span { - position: relative; - display: block; - overflow: hidden; -} - -.carbon-img { - display: block; - margin: 0; - line-height: 1; - text-align: center; -} - -.carbon-img img { - display: block; - margin: auto; -} - -.carbon-text { - font-size: 13px; - padding: 10px; - line-height: 1.5; - text-align: left; -} - -.carbon-poweredby { - display: block; - padding: 8px 10px; - text-align: center; - text-transform: uppercase; - letter-spacing: .5px; - font-weight: lighter; - font-size: 9px; - line-height: 1; -} diff --git a/user_guide_src/source/_static/css/citheme_dark.css b/user_guide_src/source/_static/css/citheme_dark.css deleted file mode 100644 index 649625a6b150..000000000000 --- a/user_guide_src/source/_static/css/citheme_dark.css +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Based heavily on https://darkreader.org/ - */ - -@media (prefers-color-scheme: dark) { - - hr { - border-top: 1px solid rgb(56, 61, 63); - } - - pre { - background-color: #282b2d !important - } - - img:not([src*='.svg']) { - filter: grayscale(50%) contrast(70%);; - } - - html { - background-color: #181a1b !important; - } - - html, body { - background-color: #181a1b; - color: rgb(192, 186, 178); - } - - table { - border-color: #545b5e; - } - - ::placeholder { - color: #b2aba1; - } - - input:-webkit-autofill, - textarea:-webkit-autofill, - select:-webkit-autofill { - background-color: #404400 !important; - color: #e8e6e3 !important; - } - - .wy-side-nav-search { - background-color: #b13a10; - color: rgb(230, 228, 225); - } - - .wy-side-nav-search input[type=text] { - box-shadow: rgb(43 47 49) 0px 1px 3px inset; - border-color: rgb(59 59 59); - background-color: rgb(59 59 59); - color: #96928c; - } - - .btn { - color: rgb(232, 230, 227); - border-color: rgba(140, 130, 115, 0.1); - background-color: rgb(31, 139, 77); - text-decoration-color: initial; - box-shadow: rgb(24 26 27 / 50%) 0px 1px 2px -1px inset, rgb(0 0 0 / 10%) 0px -2px 0px 0px inset; - padding: 8px 8px 6px; - line-height: 15px; - } - - .btn-neutral, .btn-neutral:visited { - background-color: rgb(27, 36, 36) !important; - color: rgb(192, 186, 178) !important; - } - - .btn-neutral:hover { - background-color: rgb(42, 47, 47) !important; - } - - footer { - color: rgb(152, 143, 129) !important; - } - - .wy-nav-content { - background-color: #181a1b !important; - color: rgb(192, 186, 178) !important; - } - - .method .sig-object, .class dt, .data dt, .attribute dt, .function dt, - .descclassname, .descname { - background-color: rgb(40, 43, 45) !important; - color: rgb(192, 186, 178) !important; - } - - html.writer-html4 .rst-content dl:not(.docutils) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.citation):not(.glossary):not(.simple) > dt { - color: #cccccc !important; - } - - html.writer-html4 .rst-content dl:not(.docutils) dl:not(.field-list) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.citation):not(.glossary):not(.simple) dl:not(.field-list) > dt { - color: #96928c !important; - border-left: 3px solid #3f4547 !important; - } - - html.writer-html4 .rst-content dl:not(.docutils) .optional, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.citation):not(.glossary):not(.simple) .optional { - color: #c0bab2 !important; - } - - .method dt, .function .field-list dt { - background-color: inherit !important; - } - - .rst-content .toc-backref { - color: rgb(192, 186, 178) !important; - } - - code.literal { - background-color: #2d2d2d !important; - border: 1px solid #6d6d6d !important; - } - - .wy-nav-top { - background-color: #b13a10 !important; - } - - .wy-nav-side { - background-color: rgb(28, 30, 31) !important; - } - - .wy-menu-vertical a:visited { - color: rgb(192, 186, 178) !important; - } - - .wy-menu-vertical li.current > a button.toctree-expand, .wy-menu-vertical li.on a button.toctree-expand { - color: rgb(200, 195, 188) !important; - } - .wy-menu-vertical a:hover button.toctree-expand { - color: rgb(208, 204, 198) !important; - } - - .wy-nav-content-wrap { - background-color: #181a1b !important; - } - - .wy-nav-content-wrap a, .wy-nav-content-wrap a:visited { - color: rgb(237, 101, 54) !important; - } - - .wy-nav-content-wrap a:hover, .wy-nav-content-wrap a:active { - color: rgb(241, 138, 103) !important; - } - - .wy-menu-vertical a:active { - background-color: #b13a10 !important; - } - - .sidebar { - background-color: #191919 !important; - } - - .sidebar-title { - background-color: #2b2b2b !important; - } - - .xref, .py-meth { - color: #96928c !important; - } - - .admonition, .note { - background-color: #2d2d2d !important; - } - - /* override table width restrictions */ - - .wy-table thead, .rst-content table.docutils thead, .rst-content table.field-list thead { - background-color: inherit; - } - - .rst-content table.docutils thead, .rst-content table.field-list thead, .wy-table thead { - color: #c0bab2 !important; - } - - .wy-table thead th, .rst-content table.docutils thead th, .rst-content table.field-list thead th { - border: solid 1px #c0bab2 !important; - } - - .rst-content table.docutils td, .wy-table-bordered-all td { - border-bottom: 1px solid #c0bab2 !important; - border-left: 1px solid #c0bab2 !important; - } - - .rst-content table.docutils, .wy-table-bordered-all { - border: solid 1px #c0bab2 !important; - } - - .wy-table thead p, .rst-content table.docutils thead p, .rst-content table.field-list thead p { - margin: 0; - } - - .wy-table-odd td, .wy-table-striped tr:nth-child(2n-1) td, .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { - background-color: #343131 !important; - } - - /* Messages ----------------------------------------------------------------- */ - - .rst-content .section .admonition ul { - margin-bottom: 0; - } - - .rst-content code.literal, .rst-content tt.literal { - color: rgb(233, 88, 73) !important; - } - - .rst-content .note .admonition-title, .rst-content .note .wy-alert-title, .rst-content .seealso .admonition-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .admonition-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .wy-alert.wy-alert-info .wy-alert-title { - background: #3a6d8e !important; - color: #cdcdcd !important; - } - - .rst-content .admonition-todo .admonition-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .attention .admonition-title, .rst-content .attention .wy-alert-title, .rst-content .caution .admonition-title, .rst-content .caution .wy-alert-title, .rst-content .warning .admonition-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.admonition .admonition-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .wy-alert.wy-alert-warning .wy-alert-title { - background: #b96a26 !important; - color: #cdcdcd !important; - } - - /* Content ----------------------------------------------------------------- */ - - .rst-content .important .admonition-title { - background: #b04926 !important; - color: #cdcdcd !important; - } - - .rst-content div[class^="highlight"], .rst-content pre.literal-block { - border: 1px solid rgb(63, 69, 71) !important; - } - - html.writer-html4 .rst-content dl:not(.docutils) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.citation):not(.glossary):not(.simple) > dt { - border-top: solid 3px #b13a10 !important; - } - - html.writer-html4 .rst-content dl:not(.docutils) > dt, html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.citation):not(.glossary):not(.simple) > dt { - background: #282b2d !important; - } - - /* Side Menu ---------------------------------------------------------------- */ - - .wy-menu-vertical li.current { - background: rgb(40, 43, 45) !important; - } - - .wy-menu-vertical li.current > a, .wy-menu-vertical li.on a, .wy-menu-vertical li.current > a:hover, .wy-menu-vertical li.on a:hover { - background-color: rgb(24, 26, 27) !important; - color: rgb(192, 186, 178) !important; - } - - .wy-menu-vertical li.toctree-l1.current > a { - border-bottom-color: rgb(63, 69, 71) !important; - border-top-color: rgb(63, 69, 71) !important; - - } - - .wy-menu-vertical li.current a { - border-right-color: rgb(63, 69, 71) !important; - } - - .wy-menu-vertical li.toctree-l2.current > a, .wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a, - .wy-menu-vertical li.toctree-l2.current:hover > a, .wy-menu-vertical li.toctree-l2.current li.toctree-l3:hover > a { - background: #3c3c3c !important; - border-right-color: rgb(63, 69, 71) !important; - } - - .wy-menu-vertical li.toctree-l2:hover > a, .wy-menu-vertical li.toctree-l2.current li.toctree-l3:hover > a { - background: #1c2020 !important; - } - - .wy-menu-vertical li.toctree-l2 a, .wy-menu-vertical li.toctree-l3 a, .wy-menu-vertical li.toctree-l4 a, .wy-menu-vertical li.toctree-l5 a, .wy-menu-vertical li.toctree-l6 a, .wy-menu-vertical li.toctree-l7 a, .wy-menu-vertical li.toctree-l8 a, .wy-menu-vertical li.toctree-l9 a, .wy-menu-vertical li.toctree-l10 a { - color: rgb(192, 186, 178) !important; - } - - .wy-menu-vertical li code { - color: rgb(237, 101, 54) !important; - } - - .wy-menu-vertical .xref { - color: #2980B9 !important; - } - - /* Search results ---------------------------------------------------------------- */ - - #search-results .search li:first-child { - border-top: 1px solid rgb(56, 61, 63); - } - - #search-results .search li { - border-bottom: 1px solid rgb(56, 61, 63); - padding-bottom: 14px !important; - } - - .highlighted { - background-color: #5e5939 !important - } - - a .highlighted { - color: #cecece; - } - - .rst-content .highlighted { - box-shadow: 0 0 0 2px #b3a159; - } - - .versionadded { - background: #275b11; - } - - .deprecated:not(.versionmodified) { - background: #86371b; - } - - /* Elements ----------------------------------------------------------------- */ - - .highlight .m { - color: inherit - } - - .highlight .nt { - color: #a6a6df; - } - - .highlight .nv { - color: #4f9fd5; - } - - .highlight .na { - color: #57acac; - } - - .highlight .nc { - color: #7687b9; - font-weight: bold; - } - - .highlight .nf { - color: #b96f6f; - font-weight: bold; - } - - .highlight .fm { - color: #b96f6f; - font-weight: bold; - } - - .highlight .ni { - color: #b780b7; - } - - .highlight-console .highlight pre { - background: #434343; - } -} diff --git a/user_guide_src/source/_static/favicon.ico b/user_guide_src/source/_static/favicon.ico deleted file mode 100644 index a725c10e7251..000000000000 Binary files a/user_guide_src/source/_static/favicon.ico and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.eot b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.eot deleted file mode 100644 index 6af49a8f2d87..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.eot and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.svg b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.svg deleted file mode 100644 index 958f46b7618f..000000000000 --- a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.svg +++ /dev/null @@ -1,347 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.ttf b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.ttf deleted file mode 100644 index 88e34739f314..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.ttf and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.woff b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.woff deleted file mode 100644 index d1bbeaacadae..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.woff and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.woff2 b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.woff2 deleted file mode 100644 index e13afef7dae6..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200.woff2 and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.eot b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.eot deleted file mode 100644 index b485d5cd296e..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.eot and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.svg b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.svg deleted file mode 100644 index ce455d6e530d..000000000000 --- a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.svg +++ /dev/null @@ -1,363 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.ttf b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.ttf deleted file mode 100644 index d29beb2646cd..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.ttf and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.woff b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.woff deleted file mode 100644 index 7db615057dff..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.woff and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.woff2 b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.woff2 deleted file mode 100644 index 629105aa6909..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-200italic.woff2 and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.eot b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.eot deleted file mode 100644 index f37ca0fb751e..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.eot and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.svg b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.svg deleted file mode 100644 index 0d682387f0e3..000000000000 --- a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.svg +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.ttf b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.ttf deleted file mode 100644 index 8f3846413034..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.ttf and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.woff b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.woff deleted file mode 100644 index d89a0a2b5ddd..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.woff and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.woff2 b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.woff2 deleted file mode 100644 index 022064260400..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700.woff2 and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.eot b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.eot deleted file mode 100644 index 4f61611231f7..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.eot and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.svg b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.svg deleted file mode 100644 index deac2f332c68..000000000000 --- a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.svg +++ /dev/null @@ -1,352 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.ttf b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.ttf deleted file mode 100644 index 052e0b56450b..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.ttf and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.woff b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.woff deleted file mode 100644 index f412eab113a3..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.woff and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.woff2 b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.woff2 deleted file mode 100644 index e0742c8adaa3..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-700italic.woff2 and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.eot b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.eot deleted file mode 100644 index 7d6b20a04b43..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.eot and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.svg b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.svg deleted file mode 100644 index c6dcd46742d4..000000000000 --- a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.svg +++ /dev/null @@ -1,361 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.ttf b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.ttf deleted file mode 100644 index 7f632b12f729..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.ttf and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.woff b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.woff deleted file mode 100644 index 48b91a4d3fe7..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.woff and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.woff2 b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.woff2 deleted file mode 100644 index e142d3f82761..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-italic.woff2 and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.eot b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.eot deleted file mode 100644 index 84de35ba4c5f..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.eot and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.svg b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.svg deleted file mode 100644 index 35870707df86..000000000000 --- a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.svg +++ /dev/null @@ -1,347 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.ttf b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.ttf deleted file mode 100644 index 03b5a21daa03..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.ttf and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.woff b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.woff deleted file mode 100644 index ab3a51bc092f..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.woff and /dev/null differ diff --git a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.woff2 b/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.woff2 deleted file mode 100644 index 86b505ec5c5c..000000000000 Binary files a/user_guide_src/source/_static/fonts/Raleway/raleway-v14-latin-regular.woff2 and /dev/null differ diff --git a/user_guide_src/source/_static/img/ci-background.png b/user_guide_src/source/_static/img/ci-background.png deleted file mode 100644 index 845e6e0da943..000000000000 Binary files a/user_guide_src/source/_static/img/ci-background.png and /dev/null differ diff --git a/user_guide_src/source/_static/js/carbon.js b/user_guide_src/source/_static/js/carbon.js deleted file mode 100644 index 35968db75e95..000000000000 --- a/user_guide_src/source/_static/js/carbon.js +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Add Carbon Ads underneath navigation to support CodeIgniter Foundation - */ -if (window.location.hostname === 'codeigniter.com') { - window.onload = function () { - // Create a HTML DOM Element Object - var carbon = document.createElement('script'); - carbon.async = true; - carbon.type = 'text/javascript'; - carbon.src = 'https://cdn.carbonads.com/carbon.js?serve=CE7I62QW&placement=codeignitercom'; - carbon.id = '_carbonads_js'; - - // Append Carbon Ads to .wy-menu - document.querySelector('.wy-menu').appendChild(carbon); - } -} diff --git a/user_guide_src/source/_static/js/citheme.js b/user_guide_src/source/_static/js/citheme.js deleted file mode 100644 index 1de776d85487..000000000000 --- a/user_guide_src/source/_static/js/citheme.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Add classes to the body of each page of the documentation. - * - * From: [...]/outgoing/api_responses.html - * Into: ci-outgoing ci-api-responses - */ -window.onload = function() { - // Regular expression for finding chapter and subject in the current url - const regexUrl = new RegExp(/\/([a-z0-9_.-]+)\/([a-z0-9_.-]+)\.html/); - - // Get the current url - const currentUrl = window.location.href; - - // Get the document body - const documentBody = document.body; - - // Placeholder for documentation index - var index = null; - - if ((index = regexUrl.exec(currentUrl)) !== null) - { - // Sanitize the documentation chapter and subject - var chapter = sanitizeClass(index[1]); - var subject = sanitizeClass(index[2]); - - // Documentation is generated into an html-folder for developers. - // This isn't a valid chapter. We are on documentation index. - if (chapter === 'html') - { - index = null; - } - // Add chapter and subject className(s) to the document body - else - { - addClass(documentBody, chapter); - addClass(documentBody, subject); - } - } - - // No chapter and subject found. We are on documentation index. - if (index === null) - { - addClass(documentBody, 'documentation'); - addClass(documentBody, 'index'); - } -} - -/** - * Sanitize the string - removing invalid characters - * - * @param {string} className className to be sanitized - * - * @return {string} - */ -sanitizeClass = function(className) { - return className.replace(/_/g, '-').replace(/[^a-z0-9-]/g, ''); -} - -/** - * Add class to HTML DOM Element Object - * - * @param {object} el The HTML DOM Element Object - * @param {string} className className to be added - * @param {string} namePrefix namePrefix to be added to className - * - * @return {void} - */ -addClass = function(el, className, namePrefix) { - namePrefix = namePrefix || 'ci-'; - - if (el.classList && className.length > 0) - { - el.classList.add(namePrefix + className); - } -} diff --git a/user_guide_src/source/_static/js/version_switcher.js b/user_guide_src/source/_static/js/version_switcher.js deleted file mode 100644 index d33c33ea1509..000000000000 --- a/user_guide_src/source/_static/js/version_switcher.js +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Version switcher for the user guide sidebar. - * - * Injects the sphinx_rtd_theme's native ".switch-menus > .version-switch" - * scaffolding above the search box in the left sidebar, containing a - - -This form is converted into a PUT request and is a true PUT request as far as the routing and the IncomingRequest class -are concerned. - -The form that you are using must be a POST request. GET requests cannot be spoofed. - -.. note:: Be sure to check your web server's configuration as some servers do not support all HTTP verbs with the - default configuration, and must have additional packages enabled to work. diff --git a/user_guide_src/source/incoming/request.rst b/user_guide_src/source/incoming/request.rst deleted file mode 100644 index 8448ef578010..000000000000 --- a/user_guide_src/source/incoming/request.rst +++ /dev/null @@ -1,138 +0,0 @@ -############# -Request Class -############# - -The request class is an object-oriented representation of an HTTP request. This is meant to work for both incoming, such -as a request to the application from a browser, and outgoing requests, like those used to send a request from the -application to a third-party application. - -This class provides the common functionality they both need, but both cases have custom classes that extend from the -Request class to add specific functionality. In practice, you will need to use these classes. - -See the documentation for the :doc:`IncomingRequest Class <./incomingrequest>` and -:doc:`CURLRequest Class <../libraries/curlrequest>` for more usage details. - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\HTTP - -.. php:class:: Request - - .. php:method:: getIPAddress() - - :returns: The user's IP address, if it can be detected. If the IP address - is not a valid IP address, it will return ``0.0.0.0``. - :rtype: string - - Returns the IP address for the current user. If the IP address is not valid, the method will return ``0.0.0.0``: - - .. literalinclude:: request/001.php - - .. important:: This method takes into account the ``Config\App::$proxyIPs`` setting and will return the client - IP address reported by the HTTP header for the allowed IP address. - - .. php:method:: isValidIP($ip[, $which = '']) - - .. deprecated:: 4.0.5 - Use :doc:`../libraries/validation` instead. - - .. important:: This method is deprecated. It will be removed in future releases. - - :param string $ip: IP address - :param string $which: IP protocol (``ipv4`` or ``ipv6``) - :returns: true if the address is valid, false if not - :rtype: bool - - Takes an IP address as input and returns true or false (boolean) depending on whether it is valid or not. - - .. note:: The ``$request->getIPAddress()`` method above automatically validates the IP address. - - .. literalinclude:: request/002.php - - Accepts an optional second string parameter of ``ipv4`` or ``ipv6`` to specify an IP format. The default checks - for both formats. - - .. php:method:: getMethod() - - :returns: HTTP request method - :rtype: string - - Returns the ``$_SERVER['REQUEST_METHOD']``. - - .. literalinclude:: request/003.php - - .. php:method:: setMethod($method) - - .. deprecated:: 4.0.5 - Use :php:meth:`CodeIgniter\\HTTP\\Request::withMethod()` instead. - - :param string $method: Sets the request method. Used when spoofing the request. - :returns: This request - :rtype: Request - - .. php:method:: withMethod($method) - - .. versionadded:: 4.0.5 - - :param string $method: Sets the request method. - :returns: New request instance - :rtype: Request - - .. php:method:: getServer([$index = null[, $filter = null[, $flags = null]]]) - - :param mixed $index: Value name - :param int $filter: The type of filter to apply. A list of filters can be found in the `PHP manual `__. - :param int|array $flags: Flags to apply. A list of flags can be found in the `PHP manual `__. - :returns: ``$_SERVER`` item value if found, null if not - :rtype: mixed - - This method is identical to the ``getPost()``, ``getGet()`` and ``getCookie()`` methods from the - :doc:`IncomingRequest Class <./incomingrequest>`, only it fetches server data (``$_SERVER``): - - .. literalinclude:: request/004.php - - To return an array of multiple ``$_SERVER`` values, pass all the required keys as an array. - - .. literalinclude:: request/005.php - - .. php:method:: getEnv([$index = null[, $filter = null[, $flags = null]]]) - - .. deprecated:: 4.4.4 This method has never worked. Use - :php:func:`env()` instead. - - :param mixed $index: Value name - :param int $filter: The type of filter to apply. A list of filters can be found in the `PHP manual `__. - :param int|array $flags: Flags to apply. A list of flags can be found in the `PHP manual `__. - :returns: ``$_ENV`` item value if found, null if not - :rtype: mixed - - This method is identical to the ``getPost()``, ``getGet()`` and ``getCookie()`` methods from the - :doc:`IncomingRequest Class <./incomingrequest>`, only it fetches env data (``$_ENV``): - - .. literalinclude:: request/006.php - - To return an array of multiple ``$_ENV`` values, pass all the required keys as an array. - - .. literalinclude:: request/007.php - - .. php:method:: setGlobal($method, $value) - - :param string $method: Method name - :param mixed $value: Data to be added - :returns: This request - :rtype: Request - - Allows manually setting the value of a PHP global, like ``$_GET``, ``$_POST``, etc. - - .. php:method:: fetchGlobal($method [, $index = null[, $filter = null[, $flags = null]]]) - - :param string $method: Input filter constant - :param mixed $index: Value name - :param int $filter: The type of filter to apply. A list of filters can be found in the `PHP manual `__. - :param int|array $flags: Flags to apply. A list of flags can be found in the `PHP manual `__. - :rtype: mixed - - Fetches one or more items from a global, like cookies, get, post, etc. Can optionally filter the input when you - retrieve it by passing in a filter. diff --git a/user_guide_src/source/incoming/request/001.php b/user_guide_src/source/incoming/request/001.php deleted file mode 100644 index 09c19433908f..000000000000 --- a/user_guide_src/source/incoming/request/001.php +++ /dev/null @@ -1,3 +0,0 @@ -getIPAddress(); diff --git a/user_guide_src/source/incoming/request/002.php b/user_guide_src/source/incoming/request/002.php deleted file mode 100644 index 4b2e39489f72..000000000000 --- a/user_guide_src/source/incoming/request/002.php +++ /dev/null @@ -1,7 +0,0 @@ -isValidIP($ip)) { - echo 'Not Valid'; -} else { - echo 'Valid'; -} diff --git a/user_guide_src/source/incoming/request/003.php b/user_guide_src/source/incoming/request/003.php deleted file mode 100644 index d448962cb55a..000000000000 --- a/user_guide_src/source/incoming/request/003.php +++ /dev/null @@ -1,3 +0,0 @@ -getMethod(); // Outputs: POST diff --git a/user_guide_src/source/incoming/request/004.php b/user_guide_src/source/incoming/request/004.php deleted file mode 100644 index e05381317b95..000000000000 --- a/user_guide_src/source/incoming/request/004.php +++ /dev/null @@ -1,3 +0,0 @@ -getServer('some_data'); diff --git a/user_guide_src/source/incoming/request/005.php b/user_guide_src/source/incoming/request/005.php deleted file mode 100644 index 0dabcaa7d528..000000000000 --- a/user_guide_src/source/incoming/request/005.php +++ /dev/null @@ -1,3 +0,0 @@ -getServer(['SERVER_PROTOCOL', 'REQUEST_URI']); diff --git a/user_guide_src/source/incoming/request/006.php b/user_guide_src/source/incoming/request/006.php deleted file mode 100644 index b503574b79cc..000000000000 --- a/user_guide_src/source/incoming/request/006.php +++ /dev/null @@ -1,3 +0,0 @@ -getEnv('some_data'); diff --git a/user_guide_src/source/incoming/request/007.php b/user_guide_src/source/incoming/request/007.php deleted file mode 100644 index aa1ad285e0bd..000000000000 --- a/user_guide_src/source/incoming/request/007.php +++ /dev/null @@ -1,3 +0,0 @@ -getEnv(['CI_ENVIRONMENT', 'S3_BUCKET']); diff --git a/user_guide_src/source/incoming/restful.rst b/user_guide_src/source/incoming/restful.rst deleted file mode 100644 index 74bf80edf0a3..000000000000 --- a/user_guide_src/source/incoming/restful.rst +++ /dev/null @@ -1,197 +0,0 @@ -######################### -RESTful Resource Handling -######################### - -.. contents:: - :local: - :depth: 2 - -Representational State Transfer (REST) is an architectural style for distributed applications, first described by Roy -Fielding in his 2000 PhD dissertation, -`Architectural Styles and the Design of Network-based Software Architectures `_. -That might be a bit of a dry read, and you might find Martin Fowler's -`Richardson Maturity Model `_ a gentler introduction. - -REST has been interpreted, and misinterpreted, in more ways than most software architectures, and it might be easier to -say that the more of Roy Fielding's principles that you embrace in an architecture, the more "RESTful" your application -would be considered. - -CodeIgniter makes it easy to create RESTful APIs for your resources, with its resource routes and -``ResourceController``. - -*************** -Resource Routes -*************** - -You can quickly create a handful of RESTful routes for a single resource with the ``resource()`` method. This creates -the five most common routes needed for full CRUD of a resource: create a new resource, update an existing one, list all -of that resource, show a single resource, and delete a single resource. The first parameter is the resource name: - -.. literalinclude:: restful/001.php - -.. note:: The ordering above is for clarity, whereas the actual order in which RouteCollection creates the routes - ensures proper route resolution. - -.. important:: The routes are matched in the order they are specified, so if you have a ``photos`` resource above a GET - route for ``photos/poll``, the ``show`` action's route from the resource line will be matched before the GET line. - To fix this, move the GET line above the resource line so that it is matched first. - -The second parameter accepts an array of options that can be used to modify the routes that are generated. While these -routes are geared toward API usage, where more methods are allowed, you can pass in the ``websafe`` option to have it -generate update and delete methods that work with HTML forms: - -.. literalinclude:: restful/002.php - -Change the Controller Used -========================== - -You can specify the controller that should be used by passing in the ``controller`` option with the name of the -controller that should be used: - -.. literalinclude:: restful/003.php - -.. literalinclude:: restful/017.php - -.. literalinclude:: restful/018.php - -See also :ref:`controllers-namespace`. - -Change the Placeholder Used -=========================== - -By default, the ``(:segment)`` placeholder is used when a resource ID is needed. You can change this by passing in the -``placeholder`` option with the new string to use: - -.. literalinclude:: restful/004.php - -Limit the Routes Made -===================== - -You can restrict the routes generated with the ``only`` option. This should be **an array** or **comma-separated list** -of method names that should be created. Only routes that match one of these methods will be created. The rest will be -ignored: - -.. literalinclude:: restful/005.php - -Otherwise you can remove unused routes with the ``except`` option. This should also be **an array** or -**comma-separated list** of method names. This option runs after ``only``: - -.. literalinclude:: restful/006.php - -Valid methods are: ``index``, ``show``, ``create``, ``update``, ``new``, ``edit`` and ``delete``. - -****************** -ResourceController -****************** - -The ``ResourceController`` provides a convenient starting point for your RESTful API, with methods that correspond to -the resource routes above. - -Extend it, overriding the ``modelName`` and ``format`` properties, and then implement those methods that you want -handled: - -.. literalinclude:: restful/007.php - -The routing for this would be: - -.. literalinclude:: restful/008.php - -**************** -Presenter Routes -**************** - -You can quickly create a presentation controller which aligns with a resource controller, using the ``presenter()`` -method. This creates routes for the controller methods that would return views for your resource, or process forms -submitted from those views. - -It is not needed, since the presentation can be handled with a conventional controller - it is a convenience. Its usage -is similar to the resource routing: - -.. literalinclude:: restful/009.php - -.. note:: The ordering above is for clarity, whereas the actual order in which RouteCollection creates the routes - ensures proper route resolution. - -You would not have routes for ``photos`` for both a resource and a presenter controller. You need to distinguish them, -for instance: - -.. literalinclude:: restful/010.php - -The second parameter accepts an array of options that can be used to modify the routes that are generated. - -Change the Controller Used -========================== - -You can specify the controller that should be used by passing in the ``controller`` option with the name of the -controller that should be used: - -.. literalinclude:: restful/011.php - -.. literalinclude:: restful/019.php - -.. literalinclude:: restful/020.php - -See also :ref:`controllers-namespace`. - -Change the Placeholder Used -=========================== - -By default, the ``(:segment)`` placeholder is used when a resource ID is needed. You can change this by passing in the -``placeholder`` option with the new string to use: - -.. literalinclude:: restful/012.php - -Limit the Routes Made -===================== - -You can restrict the routes generated with the ``only`` option. This should be **an array** or **comma-separated list** -of method names that should be created. Only routes that match one of these methods will be created. The rest will be -ignored: - -.. literalinclude:: restful/013.php - -Otherwise you can remove unused routes with the ``except`` option. This should also be **an array** or -**comma-separated list** of method names. This option runs after ``only``: - -.. literalinclude:: restful/014.php - -Valid methods are: ``index``, ``show``, ``new``, ``create``, ``edit``, ``update``, ``remove`` and ``delete``. - -***************** -ResourcePresenter -***************** - -The ``ResourcePresenter`` provides a convenient starting point for presenting views of your resource, and processing -data from forms in those views, with methods that align with the resource routes above. - -Extend it, overriding the ``modelName`` property, and then implement those methods that you want handled: - -.. literalinclude:: restful/015.php - -The routing for this would be: - -.. literalinclude:: restful/016.php - -******************************* -Presenter/Controller Comparison -******************************* - -This table presents a comparison of the default routes created by ``resource()`` and ``presenter()`` with their -corresponding Controller functions. - -================ ========= ======================== ======================== ====================== ====================== -Operation Method Controller Route Presenter Route Controller Function Presenter Function -================ ========= ======================== ======================== ====================== ====================== -**New** GET photos/new photos/new ``new()`` ``new()`` -**Create** POST photos photos ``create()`` ``create()`` -Create (alias) POST photos/create ``create()`` -**List** GET photos photos ``index()`` ``index()`` -**Show** GET photos/(:segment) photos/(:segment) ``show($id = null)`` ``show($id = null)`` -Show (alias) GET photos/show/(:segment) ``show($id = null)`` -**Edit** GET photos/(:segment)/edit photos/edit/(:segment) ``edit($id = null)`` ``edit($id = null)`` -**Update** PUT/PATCH photos/(:segment) ``update($id = null)`` -Update (websafe) POST photos/(:segment) photos/update/(:segment) ``update($id = null)`` ``update($id = null)`` -**Remove** GET photos/remove/(:segment) ``remove($id = null)`` -**Delete** DELETE photos/(:segment) ``delete($id = null)`` -Delete (websafe) POST photos/(:segment)/delete photos/delete/(:segment) ``delete($id = null)`` ``delete($id = null)`` -================ ========= ======================== ======================== ====================== ====================== diff --git a/user_guide_src/source/incoming/restful/001.php b/user_guide_src/source/incoming/restful/001.php deleted file mode 100644 index 3244b799ff91..000000000000 --- a/user_guide_src/source/incoming/restful/001.php +++ /dev/null @@ -1,13 +0,0 @@ -resource('photos'); - -// Equivalent to the following: -$routes->get('photos/new', 'Photos::new'); -$routes->post('photos', 'Photos::create'); -$routes->get('photos', 'Photos::index'); -$routes->get('photos/(:segment)', 'Photos::show/$1'); -$routes->get('photos/(:segment)/edit', 'Photos::edit/$1'); -$routes->put('photos/(:segment)', 'Photos::update/$1'); -$routes->patch('photos/(:segment)', 'Photos::update/$1'); -$routes->delete('photos/(:segment)', 'Photos::delete/$1'); diff --git a/user_guide_src/source/incoming/restful/002.php b/user_guide_src/source/incoming/restful/002.php deleted file mode 100644 index 67ce23393964..000000000000 --- a/user_guide_src/source/incoming/restful/002.php +++ /dev/null @@ -1,7 +0,0 @@ -resource('photos', ['websafe' => 1]); - -// The following equivalent routes are created: -$routes->post('photos/(:segment)/delete', 'Photos::delete/$1'); -$routes->post('photos/(:segment)', 'Photos::update/$1'); diff --git a/user_guide_src/source/incoming/restful/003.php b/user_guide_src/source/incoming/restful/003.php deleted file mode 100644 index 6f255282622d..000000000000 --- a/user_guide_src/source/incoming/restful/003.php +++ /dev/null @@ -1,5 +0,0 @@ -resource('photos', ['controller' => 'Gallery']); -// Would create routes like: -$routes->get('photos', '\App\Controllers\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/004.php b/user_guide_src/source/incoming/restful/004.php deleted file mode 100644 index 540fbb84aeed..000000000000 --- a/user_guide_src/source/incoming/restful/004.php +++ /dev/null @@ -1,6 +0,0 @@ -resource('photos', ['placeholder' => '(:num)']); - -// Generates routes like: -$routes->get('photos/(:num)', 'Photos::show/$1'); diff --git a/user_guide_src/source/incoming/restful/005.php b/user_guide_src/source/incoming/restful/005.php deleted file mode 100644 index 4ac8480f8ca2..000000000000 --- a/user_guide_src/source/incoming/restful/005.php +++ /dev/null @@ -1,3 +0,0 @@ -resource('photos', ['only' => ['index', 'show']]); diff --git a/user_guide_src/source/incoming/restful/006.php b/user_guide_src/source/incoming/restful/006.php deleted file mode 100644 index a1a98809adc1..000000000000 --- a/user_guide_src/source/incoming/restful/006.php +++ /dev/null @@ -1,3 +0,0 @@ -resource('photos', ['except' => 'new,edit']); diff --git a/user_guide_src/source/incoming/restful/007.php b/user_guide_src/source/incoming/restful/007.php deleted file mode 100644 index 930c61f28e8c..000000000000 --- a/user_guide_src/source/incoming/restful/007.php +++ /dev/null @@ -1,18 +0,0 @@ -respond($this->model->findAll()); - } - - // ... -} diff --git a/user_guide_src/source/incoming/restful/008.php b/user_guide_src/source/incoming/restful/008.php deleted file mode 100644 index d1a6c08dd03c..000000000000 --- a/user_guide_src/source/incoming/restful/008.php +++ /dev/null @@ -1,3 +0,0 @@ -resource('photos'); diff --git a/user_guide_src/source/incoming/restful/009.php b/user_guide_src/source/incoming/restful/009.php deleted file mode 100644 index 25e069258781..000000000000 --- a/user_guide_src/source/incoming/restful/009.php +++ /dev/null @@ -1,15 +0,0 @@ -presenter('photos'); - -// Equivalent to the following: -$routes->get('photos/new', 'Photos::new'); -$routes->post('photos/create', 'Photos::create'); -$routes->post('photos', 'Photos::create'); // alias -$routes->get('photos', 'Photos::index'); -$routes->get('photos/show/(:segment)', 'Photos::show/$1'); -$routes->get('photos/(:segment)', 'Photos::show/$1'); // alias -$routes->get('photos/edit/(:segment)', 'Photos::edit/$1'); -$routes->post('photos/update/(:segment)', 'Photos::update/$1'); -$routes->get('photos/remove/(:segment)', 'Photos::remove/$1'); -$routes->post('photos/delete/(:segment)', 'Photos::delete/$1'); diff --git a/user_guide_src/source/incoming/restful/010.php b/user_guide_src/source/incoming/restful/010.php deleted file mode 100644 index b36c7ed8973e..000000000000 --- a/user_guide_src/source/incoming/restful/010.php +++ /dev/null @@ -1,4 +0,0 @@ -resource('api/photo'); -$routes->presenter('admin/photos'); diff --git a/user_guide_src/source/incoming/restful/011.php b/user_guide_src/source/incoming/restful/011.php deleted file mode 100644 index e08078d47e31..000000000000 --- a/user_guide_src/source/incoming/restful/011.php +++ /dev/null @@ -1,5 +0,0 @@ -presenter('photos', ['controller' => 'Gallery']); -// Would create routes like: -$routes->get('photos', '\App\Controllers\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/012.php b/user_guide_src/source/incoming/restful/012.php deleted file mode 100644 index 0bd42b5120f0..000000000000 --- a/user_guide_src/source/incoming/restful/012.php +++ /dev/null @@ -1,6 +0,0 @@ -presenter('photos', ['placeholder' => '(:num)']); - -// Generates routes like: -$routes->get('photos/(:num)', 'Photos::show/$1'); diff --git a/user_guide_src/source/incoming/restful/013.php b/user_guide_src/source/incoming/restful/013.php deleted file mode 100644 index 1a3cc23a9004..000000000000 --- a/user_guide_src/source/incoming/restful/013.php +++ /dev/null @@ -1,3 +0,0 @@ -presenter('photos', ['only' => ['index', 'show']]); diff --git a/user_guide_src/source/incoming/restful/014.php b/user_guide_src/source/incoming/restful/014.php deleted file mode 100644 index 0d88d4ba5cdc..000000000000 --- a/user_guide_src/source/incoming/restful/014.php +++ /dev/null @@ -1,3 +0,0 @@ -presenter('photos', ['except' => 'new,edit']); diff --git a/user_guide_src/source/incoming/restful/015.php b/user_guide_src/source/incoming/restful/015.php deleted file mode 100644 index 0600f7c686ef..000000000000 --- a/user_guide_src/source/incoming/restful/015.php +++ /dev/null @@ -1,17 +0,0 @@ -model->findAll()); - } - - // ... -} diff --git a/user_guide_src/source/incoming/restful/016.php b/user_guide_src/source/incoming/restful/016.php deleted file mode 100644 index d0511180ee22..000000000000 --- a/user_guide_src/source/incoming/restful/016.php +++ /dev/null @@ -1,3 +0,0 @@ -presenter('photos'); diff --git a/user_guide_src/source/incoming/restful/017.php b/user_guide_src/source/incoming/restful/017.php deleted file mode 100644 index 853748f84527..000000000000 --- a/user_guide_src/source/incoming/restful/017.php +++ /dev/null @@ -1,5 +0,0 @@ -resource('photos', ['controller' => '\App\Gallery']); -// Would create routes like: -$routes->get('photos', '\App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/018.php b/user_guide_src/source/incoming/restful/018.php deleted file mode 100644 index 6951d07b07b3..000000000000 --- a/user_guide_src/source/incoming/restful/018.php +++ /dev/null @@ -1,7 +0,0 @@ -resource('photos', ['namespace' => '', 'controller' => Gallery::class]); -// Would create routes like: -$routes->get('photos', '\App\Controllers\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/019.php b/user_guide_src/source/incoming/restful/019.php deleted file mode 100644 index 09885e7f0039..000000000000 --- a/user_guide_src/source/incoming/restful/019.php +++ /dev/null @@ -1,5 +0,0 @@ -presenter('photos', ['controller' => '\App\Gallery']); -// Would create routes like: -$routes->get('photos', '\App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/020.php b/user_guide_src/source/incoming/restful/020.php deleted file mode 100644 index ddd67cc22d93..000000000000 --- a/user_guide_src/source/incoming/restful/020.php +++ /dev/null @@ -1,7 +0,0 @@ -presenter('photos', ['namespace' => '', 'controller' => Gallery::class]); -// Would create routes like: -$routes->get('photos', '\App\Controllers\Gallery::index'); diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst deleted file mode 100644 index ef79e9ee12dd..000000000000 --- a/user_guide_src/source/incoming/routing.rst +++ /dev/null @@ -1,1041 +0,0 @@ -########### -URI Routing -########### - -.. contents:: - :local: - :depth: 3 - -What is URI Routing? -******************** - -URI Routing associates a URI with a controller's method. - -CodeIgniter has two kinds of routing. One is **Defined Route Routing**, and the other is **Auto Routing**. With Defined -Route Routing, you can define routes manually. It allows flexible URLs. Auto Routing automatically routes HTTP requests -based on conventions and executes the corresponding controller methods. There is no need to define routes manually. - -First, let's look at Defined Route Routing. If you want to use Auto Routing, see :ref:`auto-routing-improved`. - -.. _defined-route-routing: - -Setting Routing Rules -********************* - -Routing rules are defined in the **app/Config/Routes.php** file. In it you'll see that it creates an instance of the -RouteCollection class (``$routes``) that permits you to specify your own routing criteria. Routes can be specified using -placeholders or Regular Expressions. - -When you specify a route, you choose a method corresponding to HTTP verbs (request method). If you expect a GET request, -you use the ``get()`` method: - -.. literalinclude:: routing/001.php - -A route takes the **Route Path** (the URI path relative to the BaseURL, here ``/``) on the left, and maps it to the -**Route Handler** (the controller and method, here ``Home::index``) on the right, along with any parameters that should -be passed to the controller. - -The controller and method should be listed in the same way that you would use a static method, by separating the class -and its method with a double-colon, like ``Users::list``. - -If that method requires parameters to be passed to it, then they would be listed after the method name, separated by -forward slashes: - -.. literalinclude:: routing/002.php - -Examples -======== - -Here are a few basic routing examples. - -A URL containing the word **journals** in the first segment will be mapped to the ``\App\Controllers\Blogs`` class, and -the :ref:`default method `, which is usually ``index()``: - -.. literalinclude:: routing/006.php - -A URL containing the segments **blog/joe** will be mapped to the ``\App\Controllers\Blogs`` class and the ``users()`` -method. The ID will be set to ``34``: - -.. literalinclude:: routing/007.php - -A URL with **product** as the first segment and anything in the second will be mapped to the -``\App\Controllers\Catalog`` class and the ``productLookup()`` method: - -.. literalinclude:: routing/008.php - -A URL with **product** as the first segment and a number in the second will be mapped to the -``\App\Controllers\Catalog`` class and the ``productLookupByID()`` method, passing in the match as a variable to the -method: - -.. literalinclude:: routing/009.php - -.. _routing-http-verb-routes: - -HTTP verb Routes -================ - -You can use any standard HTTP verb (GET, POST, PUT, DELETE, OPTIONS, etc.): - -.. literalinclude:: routing/003.php - -You can supply multiple verbs that a route should match by passing them in as an array to the ``match()`` method: - -.. literalinclude:: routing/004.php - -Specifying Route Handlers -========================= - -.. _controllers-namespace: - -Controller's Namespace ----------------------- - -When you specify a controller and method name as a string, if a controller is written without a leading ``\``, the -:ref:`routing-default-namespace` will be prepended: - -.. literalinclude:: routing/063.php - -If you put ``\`` at the beginning, it is treated as a fully qualified class name: - -.. literalinclude:: routing/064.php - -You can also specify the namespace with the ``namespace`` option: - -.. literalinclude:: routing/038.php - -See :ref:`assigning-namespace` for details. - -Array Callable Syntax ---------------------- - -.. versionadded:: 4.2.0 - -Since v4.2.0, you can use array callable syntax to specify the controller: - -.. literalinclude:: routing/013.php - :lines: 2- - -Or using the ``use`` keyword: - -.. literalinclude:: routing/014.php - :lines: 2- - -If you forget to add ``use App\Controllers\Home;``, the controller classname is interpreted as ``\Home``, not -``App\Controllers\Home``. - -.. note:: When you use Array Callable Syntax, the classname is always interpreted as a fully qualified classname. So - :ref:`routing-default-namespace` and :ref:`namespace option ` have no effect. - -Array Callable Syntax and Placeholders -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If there are placeholders, it will automatically set the parameters in the specified order: - -.. literalinclude:: routing/015.php - :lines: 2- - -But the auto-configured parameters may not be correct if you use regular expressions in routes. In such a case, you can -specify the parameters manually: - -.. literalinclude:: routing/016.php - :lines: 2- - -Using Closures --------------- - -You can use an anonymous function, or Closure, as the destination that a route maps to. This function will be executed -when the user visits that URI. This is handy for quickly executing small tasks, or even just showing a simple view: - -.. literalinclude:: routing/020.php - -Specifying Route Paths -====================== - -Placeholders ------------- - -A typical route might look something like this: - -.. literalinclude:: routing/005.php - -In a route, the first parameter contains the URI to be matched, while the second parameter contains the destination it -should be routed to. In the above example, if the literal word "product" is found in the first segment of the URL path, -and a number is found in the second segment, the ``Catalog`` class and the ``productLookup`` method are used instead. - -Placeholders are simply strings that represent a Regular Expression pattern. During the routing process, these -placeholders are replaced with the value of the Regular Expression. They are primarily used for readability. - -The following placeholders are available for you to use in your routes: - -============ =========================================================================================================== -Placeholders Description -============ =========================================================================================================== -(:any) will match all characters from that point to the end of the URI. This may include multiple URI segments. -(:segment) will match any character except for a forward slash (``/``) restricting the result to a single segment. -(:num) will match any positive integer. -(:alpha) will match any string of alphabetic characters. -(:alphanum) will match any string of alphabetic characters or integers, or any combination of the two. -(:hash) is the same as ``(:segment)``, but can be used to easily see which routes use hashed ids. -============ =========================================================================================================== - -.. note:: ``{locale}`` cannot be used as a placeholder or other part of the route, as it is reserved for use in - :doc:`localization `. - -.. _routing-placeholder-any: - -The Behavior of (:any) -^^^^^^^^^^^^^^^^^^^^^^ - -Note that a single ``(:any)`` will match multiple segments in the URL if present. - -For example, the route: - -.. literalinclude:: routing/010.php - -will match **product/123**, **product/123/456**, **product/123/456/789** and so on. - -By default, in the above example, if the ``$1`` placeholder contains a slash (``/``), it will still be split into -multiple parameters when passed to ``Catalog::productLookup()``. - -.. note:: Since v4.5.0, you can change the behavior with the config option. See - :ref:`multiple-uri-segments-as-one-parameter` for details. - -The implementation in the Controller should take into account the maximum parameters: - -.. literalinclude:: routing/011.php - -Or you can use -`variable-length argument lists `_: - -.. literalinclude:: routing/068.php - -.. important:: Do not put any placeholder after ``(:any)``, because the number of parameters passed to the controller - method may change. - -If matching multiple segments is not the intended behavior, ``(:segment)`` should be used when defining the routes. With -the example URLs from above: - -.. literalinclude:: routing/012.php - -will only match **product/123** and generate 404 errors for the other examples. - -Custom Placeholders -------------------- - -You can create your own placeholders that can be used in your routes file to fully customize the experience and -readability. - -You add new placeholders with the ``addPlaceholder()`` method. The first parameter is the string to be used as the -placeholder. The second parameter is the Regular Expression pattern it should be replaced with. This must be called -before you add the route: - -.. literalinclude:: routing/017.php - -Regular Expressions -------------------- - -If you prefer, you can use regular expressions to define your routing rules. Any valid regular expression is allowed, as -are back-references. - -.. important:: If you use back-references, you must use the dollar syntax rather than the double backslash syntax. A - typical RegEx route might look something like this: - - .. literalinclude:: routing/018.php - -In the above example, a URI similar to **products/shirts/123** would instead call the ``show()`` method of the -``Products`` controller class, with the original first and second segments passed as arguments to it. - -With regular expressions, you can also catch a segment containing a forward slash (``/``), which would usually represent -the delimiter between multiple segments. - -For example, if a user accesses a password-protected area of your web application and you wish to be able to redirect -them back to the same page after they log in, you may find this example useful: - -.. literalinclude:: routing/019.php - -By default, in the above example, if the ``$1`` placeholder contains a slash (``/``), it will still be split into -multiple parameters when passed to ``Auth::login()``. - -.. note:: Since v4.5.0, you can change the behavior with the config option. See - :ref:`multiple-uri-segments-as-one-parameter` for details. - -For those of you who don't know regular expressions and want to learn more about them, -`regular-expressions.info `_ might be a good starting point. - -.. note:: You can also mix and match placeholders with regular expressions. - -.. _view-routes: - -View Routes -=========== - -.. versionadded:: 4.3.0 - -If you just want to render a view that has no logic associated with it, you can use the ``view()`` method. This is -always treated as a GET request. This method accepts the name of the view to load as the second parameter. - -.. literalinclude:: routing/065.php - -If you use placeholders within your route, you can access them within the view in a special variable, ``$segments``. -They are available as an array, indexed in the order they appear in the route. - -.. literalinclude:: routing/066.php - -.. _redirecting-routes: - -Redirecting Routes -================== - -Any site that lives long enough is bound to have pages that move. You can specify routes that should redirect to other -routes with the ``addRedirect()`` method. The first parameter is the URI pattern for the old route. The second parameter -is either the new URI to redirect to, or the name of a named route. The third parameter is the HTTP status code that -should be sent along with the redirect. The default value is ``302``, which is a temporary redirect and is recommended -in most cases: - -.. literalinclude:: routing/022.php - -.. note:: Since v4.2.0, ``addRedirect()`` can use placeholders. - -If a redirect route is matched during a page load, the user will be immediately redirected to the new page before a -controller can be loaded. - -Environment Restrictions -======================== - -You can create a set of routes that will only be viewable in a certain environment. This allows you to create tools that -only the developer can use on their local machines that are not reachable on testing or production servers. This can be -done with the ``environment()`` method. The first parameter is the name of the environment. Any routes defined within -this closure are only accessible from the given environment: - -.. literalinclude:: routing/028.php - -Routes with any HTTP verbs -========================== - -.. important:: This method exists only for backward compatibility. Do not use it in new projects. Even if you are - already using it, we recommend that you use another, more appropriate method. - -.. warning:: While the ``add()`` method seems to be convenient, it is recommended to always use the HTTP-verb-based - routes, described above, as it is more secure. If you use the :doc:`CSRF protection `, it does - not protect **GET** requests. If the URI specified in the ``add()`` method is accessible by the GET method, the CSRF - protection will not work. - -It is possible to define a route with any HTTP verb. You can use the ``add()`` method: - -.. literalinclude:: routing/031.php - -.. note:: Using the HTTP-verb-based routes will also provide a slight performance increase, since only routes that match - the current request method are stored, resulting in fewer routes to scan through when trying to find a match. - -Mapping Multiple Routes -======================= - -.. important:: This method exists only for backward compatibility. Do not use it in new projects. Even if you are - already using it, we recommend that you use another, more appropriate method. - -.. warning:: Like ``add()``, the ``map()`` method is not recommended because it calls ``add()`` internally. - -While the ``add()`` method is simple to use, it is often handier to work with multiple routes at once, using the -``map()`` method. Instead of calling the ``add()`` method for each route that you need to add, you can define an array -of routes and then pass it as the first parameter to the ``map()`` method: - -.. literalinclude:: routing/021.php - -.. _command-line-only-routes: - -Command-Line Only Routes -======================== - -.. note:: It is recommended to use Spark Commands for CLI scripts instead of calling controllers via CLI. See the - :doc:`../cli/cli_commands` page for detailed information. - -Any route created by any of the HTTP-verb-based route methods will also be inaccessible from the CLI, but routes created -by the ``add()`` method will still be available from the command line. - -You can create routes that work only from the command line, and are inaccessible from the web browser, with the -``cli()`` method: - -.. literalinclude:: routing/032.php - -.. warning:: If you enable :ref:`auto-routing-legacy` and place the command file in **app/Controllers**, anyone could - access the command with the help of Auto Routing (Legacy) via HTTP. - -Global Options -************** - -All of the methods for creating a route (``get()``, ``post()``, :doc:`resource() `, etc.) can take an array of -options that can modify the generated routes, or further restrict them. The ``$options`` array is always the last -parameter: - -.. literalinclude:: routing/033.php - -.. _applying-filters: - -Applying Filters -================ - -You can alter the behavior of specific routes by supplying filters to run before or after the controller. This is -especially handy during authentication or API logging. - -The value for the filter can be a string or an array of strings: - -* matching the aliases defined in **app/Config/Filters.php**. -* filter classnames - -See :ref:`Controller Filters ` for more information on defining aliases. - -.. Warning:: If you set filters to routes in **app/Config/Routes.php** - (not in **app/Config/Filters.php**), it is recommended to disable Auto Routing (Legacy). When - :ref:`auto-routing-legacy` is enabled, it may be possible that a controller can be accessed via a different URL than - the configured route, in which case the filter you specified for the route will not be applied. See - :ref:`use-defined-routes-only` to disable auto-routing. - -Alias Filter ------------- - -You specify an alias :ref:`defined in app/Config/Filters.php ` for the filter value: - -.. literalinclude:: routing/034.php - -You may also supply arguments to be passed to the alias filter's ``before()`` and ``after()`` methods: - -.. literalinclude:: routing/035.php - -Classname Filter ----------------- - -.. versionadded:: 4.1.5 - -You can specify a filter classname for the filter value: - -.. literalinclude:: routing/036.php - -.. _multiple-filters: - -Multiple Filters ----------------- - -.. versionadded:: 4.1.5 - -.. important:: Since v4.5.0, *Multiple Filters* are always enabled. Prior to v4.5.0, *Multiple Filters* were disabled by - default. If you want to use them prior to v4.5.0, see - :ref:`Upgrading from 4.1.4 to 4.1.5 ` for the details. - -You can specify an array for the filter value: - -.. literalinclude:: routing/037.php - -Filter Arguments -^^^^^^^^^^^^^^^^ - -Additional arguments may be passed to a filter: - -.. literalinclude:: routing/067.php - -In this example, the array ``['dual', 'noreturn']`` will be passed in ``$arguments`` to the filter's ``before()`` and -``after()`` implementation methods. - -.. _assigning-namespace: - -Assigning Namespace -=================== - -While a :ref:`routing-default-namespace` will be prepended to the generated controllers, you can also specify a -different namespace to be used in any options array, with the ``namespace`` option. The value should be the namespace -you want modified: - -.. literalinclude:: routing/038.php - -The new namespace is only applied during that call for any methods that create a single route, like get, post, etc. For -any methods that create multiple routes, the new namespace is attached to all routes generated by that function or, in -the case of ``group()``, all routes generated while in the closure. - -Limit to Hostname -================= - -You can restrict groups of routes to function only in certain domains or sub-domains of your application by passing the -"hostname" option along with the desired domain to allow it on as part of the options array: - -.. literalinclude:: routing/039.php - -This example would only allow the specified hosts to work if the domain exactly matched **accounts.example.com**. It -would not work under the main site at **example.com**. - -.. note:: - - The ``hostname`` option is compared against the full ``HTTP_HOST`` value of the request, including the port when one - is present. When your application is served on a non-standard port (for example ``localhost:8080``, behind Docker, - or when using ``php spark serve``), you must include the port in the ``hostname`` option for the routes to match. - For example, ``['hostname' => 'localhost:8080']`` matches only requests to ``localhost:8080``. - -Restrict by Multiple Hostnames ------------------------------- - -.. versionadded:: 4.6.0 - -You can also restrict by multiple hostnames, e.g.: - -.. literalinclude:: routing/073.php - -Limit to Subdomains -=================== - -When the ``subdomain`` option is present, the system will restrict the routes to only be available on that sub-domain. -The route will only be matched if the subdomain is the one the application is being viewed through: - -.. literalinclude:: routing/040.php - -You can restrict it to any subdomain by setting the value to an asterisk (``*``). If you are viewing from a URL that -does not have any subdomain present, this will not be matched: - -.. literalinclude:: routing/041.php - -.. important:: The system is not perfect and should be tested for your specific domain before being used in production. - Most domains should work fine, but some edge cases, especially with a period in the domain itself (not used to - separate suffixes or www) can potentially lead to false positives. - -Offsetting the Matched Parameters -================================= - -You can offset the matched parameters in your route by any numeric value with the ``offset`` option, with the value -being the number of segments to offset. - -This can be beneficial when developing APIs with the first URI segment being the version number. It can also be used -when the first parameter is a language string: - -.. literalinclude:: routing/042.php - -.. _reverse-routing: - -Reverse Routing -*************** - -Reverse routing allows you to define the controller and method, as well as any parameters, that a link should go to, and -have the router look up the current route to it. This allows route definitions to change without you having to update -your application code. This is typically used within views to create links. - -For example, if you have a route to a photo gallery that you want to link to, you can use the :php:func:`url_to()` -helper function to get the route that should be used. The first parameter is the fully qualified Controller and method, -separated by a double colon (``::``), much like you would use when writing the initial route itself. Any parameters that -should be passed to the route are passed in next: - -.. literalinclude:: routing/029.php - -.. _using-named-routes: - -Named Routes -************ - -You can name routes to make your application less fragile. This applies a name to a route that can be called later, and -even if the route definition changes, all of the links in your application built with :php:func:`url_to()` will still -work without you having to make any changes. A route is named by passing in the ``as`` option with the name of the -route: - -.. literalinclude:: routing/030.php - -This has the added benefit of making the views more readable, too. - -.. note:: By default, all defined routes have names matching their paths, with placeholders replaced by their - corresponding regular expressions. For example, if you define a route like - ``$routes->get('edit/(:num)', 'PostController::edit/$1');``, you can generate the corresponding URL using - ``route_to('edit/([0-9]+)', 12)``. - -.. warning:: According to :ref:`routing-priority`, if an unnamed route is defined first (e.g., - ``$routes->get('edit', 'PostController::edit');``) and another named route is defined later with the same name as - the path of the first route (e.g., ``$routes->get('edit/(:num)', 'PostController::edit/$1', ['as' => 'edit']);``), - the second route will not be registered because its name will conflict with the automatically assigned name of the - first route. - -Grouping Routes -*************** - -You can group your routes under a common name with the ``group()`` method. The group name becomes a segment that appears -prior to the routes defined inside of the group. This allows you to reduce the typing needed to build out an extensive -set of routes that all share the opening string, like when building an admin area: - -.. literalinclude:: routing/023.php - -This would prefix the **users** and **blog** URIs with **admin**, handling URLs like **admin/users** and **admin/blog**. - -Setting Namespace -================= - -If you need to assign options to a group, like :ref:`assigning-namespace`, do it before the callback: - -.. literalinclude:: routing/024.php - -This would handle a resource route to the ``App\API\v1\Users`` controller with the **api/users** URI. - -Setting Filters -=============== - -You can also use a specific :doc:`filter ` for a group of routes. This will always run the filter before or -after the controller. This is especially handy during authentication or API logging: - -.. literalinclude:: routing/025.php - -The value for the filter must match one of the aliases defined within **app/Config/Filters.php**. - -.. note:: Prior to v4.5.4, due to a bug, filters passed to the ``group()`` were not merged into the filters passed to - the inner routes. - -Setting Other Options -===================== - -At some point, you may want to group routes for the purpose of applying filters or other route config options like -namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass an empty string in -place of the prefix and the routes in the group will be routed as though the group never existed but with the given -route config options: - -.. literalinclude:: routing/027.php - -.. _routing-nesting-groups: - -Nesting Groups -============== - -It is possible to nest groups within groups for finer organization if you need it: - -.. literalinclude:: routing/026.php - -This would handle the URL at **admin/users/list**. - -The ``filter`` option passed to the outer ``group()`` is merged with the inner ``group()`` filter option. The above code -runs ``myfilter1:config`` for the route ``admin``, and ``myfilter1:config`` and ``myfilter2:region`` for the route -``admin/users/list``. - -.. note:: Prior to v4.6.0, the same filter could not be run multiple times with different arguments. - -Any other overlapping options passed to the inner ``group()`` will overwrite their values. - -.. note:: Prior to v4.5.0, due to a bug, options passed to the outer ``group()`` were not merged with the inner - ``group()`` options. - -.. _routing-priority: - -Route Priority -************** - -Routes are registered in the routing table in the order in which they are defined. This means that when a URI is -accessed, the first matching route will be executed. - -.. warning:: If a route path is defined more than once with different handlers, only the first defined route is - registered. - -You can check registered routes in the routing table by running the :ref:`spark routes ` command. - -Changing Route Priority -======================= - -When working with modules, it can be a problem if the routes in the application contain wildcards. Then the module -routes will not be processed correctly. You can solve this problem by lowering the priority of route processing using -the ``priority`` option. The parameter accepts positive integers and zero. The higher the number specified in the -``priority``, the lower the route priority in the processing queue: - -.. literalinclude:: routing/043.php - -To disable this functionality, you must call the method with the parameter ``false``: - -.. literalinclude:: routing/044.php - -.. note:: By default, all routes have a priority of 0. Negative integers will be cast to the absolute value. - -.. _routes-configuration-options: - -Routes Configuration Options -**************************** - -The RouteCollection class provides several options that affect all routes, and can be modified to meet your -application's needs. These options are available in **app/Config/Routing.php**. - -.. note:: The config file **app/Config/Routing.php** was added in v4.4.0. In previous versions, the setter methods were - used in **app/Config/Routes.php** to change settings. - -.. _routing-default-namespace: - -Default Namespace -================= - -When matching a controller to a route, the router will add the default namespace value to the front of the controller -specified by the route. By default, this value is ``App\Controllers``. - -If you set the value to an empty string (``''``), it leaves each route to specify the fully namespaced controller: - -.. literalinclude:: routing/045.php - -If your controllers are not explicitly namespaced, there is no need to change this. If you namespace your controllers, -then you can change this value to save typing: - -.. literalinclude:: routing/046.php - -.. _routing-default-method: - -Default Method -============== - -This setting is used when the route handler only has the controller name and no method name listed. The default value is -``index``. :: - - // In app/Config/Routing.php - public string $defaultMethod = 'index'; - -.. note:: The ``$defaultMethod`` is also common with Auto Routing. See - :ref:`Auto Routing (Improved) ` or - :ref:`Auto Routing (Legacy) `. - -If you define the following route:: - - $routes->get('/', 'Home'); - -the ``index()`` method of the ``App\Controllers\Home`` controller is executed when the route matches. - -.. note:: Method names beginning with ``_`` cannot be used as the default method. However, starting with v4.5.0, the - ``__invoke`` method is allowed. - -Translate URI Dashes -==================== - -This option enables you to automatically replace dashes (``-``) with underscores in the controller and method URI -segments when used in Auto Routing, thus saving you additional route entries if you need to do that. This is required -because the dash isn't a valid class or method name character and would cause a fatal error if you try to use it: - -.. literalinclude:: routing/049.php - -.. note:: When using Auto Routing (Improved), prior to v4.4.0, if ``$translateURIDashes`` is true, two URIs correspond - to a single controller method, one URI for dashes (e.g., **foo-bar**) and one URI for underscores (e.g., - **foo_bar**). This was incorrect behavior. Since v4.4.0, the URI for underscores (**foo_bar**) is not accessible. - -.. _use-defined-routes-only: - -Use Defined Routes Only -======================= - -Since v4.2.0, auto-routing is disabled by default. - -When no defined route is found that matches the URI, the system will attempt to match that URI against the controllers -and methods when Auto Routing is enabled. - -You can disable this automatic matching, and restrict routes to only those defined by you, by setting the ``$autoRoute`` -property to false: - -.. literalinclude:: routing/050.php - -.. warning:: If you use the :doc:`CSRF protection `, it does not protect **GET** requests. If the - URI is accessible by the GET method, the CSRF protection will not work. - -.. _404-override: - -404 Override -============ - -When a page is not found that matches the current URI, the system will show a generic 404 view. Using the -``$override404`` property within the routing config file, you can define a controller class/method for 404 routes. - -.. literalinclude:: routing/051.php - -You can also change what happens by specifying an action to happen with the ``set404Override()`` method in the Routes -config file. The value can be either a valid class/method pair, or a Closure: - -.. literalinclude:: routing/069.php - -.. note:: Starting with v4.5.0, the 404 Override feature sets the Response status code to ``404`` by default. In - previous versions, the code was ``200``. If you want to change the status code in the controller, see - :php:meth:`CodeIgniter\\HTTP\\Response::setStatusCode()` for information on how to set the status code. - -Route Processing by Priority -============================ - -Enables or disables processing of the routes queue by priority. Lowering the priority is defined in the route option. -Disabled by default. This functionality affects all routes. For an example use of lowering the priority, see -:ref:`routing-priority`: - -.. literalinclude:: routing/052.php - -.. _multiple-uri-segments-as-one-parameter: - -Multiple URI Segments as One Parameter -====================================== - -.. versionadded:: 4.5.0 - -When this option is enabled, a placeholder that matches multiple segments, such as ``(:any)``, will be passed directly -as it is to one parameter, even if it contains multiple segments. - -.. literalinclude:: routing/070.php - -For example, the route: - -.. literalinclude:: routing/010.php - -will match **product/123**, **product/123/456**, **product/123/456/789** and so on. And if the URI is -**product/123/456**, ``123/456`` will be passed to the first parameter of the ``Catalog::productLookup()`` method. - -Auto Routing (Improved) -*********************** - -.. versionadded:: 4.2.0 - -Auto Routing (Improved) is a new, more secure automatic routing system. - -See :doc:`auto_routing_improved` for details. - -.. _auto-routing-legacy: - -Auto Routing (Legacy) -********************* - -.. important:: This feature exists only for backward compatibility. Do not use it in new projects. Even if you are - already using it, we recommend that you use the :ref:`auto-routing-improved` instead. - -Auto Routing (Legacy) is a routing system from CodeIgniter 3. It can automatically route HTTP requests based on -conventions and execute the corresponding controller methods. - -It is recommended to define all routes in the **app/Config/Routes.php** file, or to use :ref:`auto-routing-improved`. - -.. warning:: To prevent misconfiguration and miscoding, we recommend that you do not use the Auto Routing (Legacy) - feature. It is easy to create vulnerable apps where controller filters or CSRF protection are bypassed. - -.. important:: Auto Routing (Legacy) routes an HTTP request with **any** HTTP method to a controller method. - -Enable Auto Routing (Legacy) -============================ - -Since v4.2.0, auto-routing is disabled by default. - -To use it, you need to set the ``$autoRoute`` option to ``true`` in **app/Config/Routing.php**:: - - public bool $autoRoute = true; - -And set the property ``$autoRoutesImproved`` to ``false`` in **app/Config/Feature.php**:: - - public bool $autoRoutesImproved = false; - -URI Segments (Legacy) -===================== - -The segments in the URL, following the Model-View-Controller approach, usually represent:: - - example.com/class/method/ID - -1. The first segment represents the controller **class** that should be invoked. -2. The second segment represents the class **method** that should be called. -3. The third, and any additional segments, represent the ID and any variables that will be passed to the controller. - -Consider this URI:: - - example.com/index.php/helloworld/index/1 - -In the above example, CodeIgniter would attempt to find a controller named **Helloworld.php** and execute the -``index()`` method, passing ``'1'`` as the first argument. - -See :ref:`Auto Routing (Legacy) in Controllers ` for more info. - -.. _routing-auto-routing-legacy-configuration-options: - -Configuration Options (Legacy) -============================== - -These options are available in the **app/Config/Routing.php** file. - -Default Controller (Legacy) ---------------------------- - -For Site Root URI (Legacy) -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When a user visits the root of your site (i.e., **example.com**), the controller to use is determined by the value set -to the ``$defaultController`` property, unless a route exists for it explicitly. - -The default value for this is ``Home``, which matches the controller at **app/Controllers/Home.php**:: - - public string $defaultController = 'Home'; - -For Directory URI (Legacy) -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The default controller is also used when no matching route has been found, and the URI would point to a directory in the -controllers directory. For example, if the user visits **example.com/admin**, and a controller was found at -**app/Controllers/Admin/Home.php**, it would be used. - -See :ref:`Auto Routing (Legacy) in Controllers ` for more info. - -.. _routing-auto-routing-legacy-default-method: - -Default Method (Legacy) ------------------------ - -This works similarly to the default controller setting, but is used to determine the default method that is used when a -controller is found that matches the URI, but no segment exists for the method. The default value is ``index``. - -In this example, if the user were to visit **example.com/products**, and a ``Products`` controller existed, the -``Products::listAll()`` method would be executed:: - - public string $defaultMethod = 'listAll'; - -Confirming Routes -***************** - -CodeIgniter has the following :doc:`command ` to display all routes. - -.. _routing-spark-routes: - -spark routes -============ - -Displays all routes and filters: - -.. code-block:: console - - php spark routes - -The output is like the following: - -.. code-block:: none - - +---------+---------+---------------+-------------------------------+----------------+---------------+ - | Method | Route | Name | Handler | Before Filters | After Filters | - +---------+---------+---------------+-------------------------------+----------------+---------------+ - | GET | / | » | \App\Controllers\Home::index | | toolbar | - | GET | feed | » | (Closure) | | toolbar | - +---------+---------+---------------+-------------------------------+----------------+---------------+ - -The *Method* column shows the HTTP method that the route is listening for. - -The *Route* column shows the route path to match. The route of a defined route is expressed as a regular expression. - -Since v4.3.0, the *Name* column shows the route name. ``»`` indicates the name is the same as the route path. - -.. important:: The system is not perfect. For routes containing regular expression patterns like ``([^/]+)`` or - ``{locale}``, the *Filters* displayed might not be correct (if you set a complicated URI pattern for the filters in - **app/Config/Filters.php**), or they are displayed as ````. - - The :ref:`spark filter:check ` command can be used to check for 100% accurate filters. - -Auto Routing (Improved) ------------------------ - -When you use Auto Routing (Improved), the output is like the following: - -.. code-block:: none - - +-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+ - | Method | Route | Name | Handler | Before Filters | After Filters | - +-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+ - | GET(auto) | product/list/../..[/..] | | \App\Controllers\Product::getList | | toolbar | - +-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+ - -The *Method* will be like ``GET(auto)``. - -``/..`` in the *Route* column indicates one segment. ``[/..]`` indicates it is optional. - -.. note:: When auto-routing is enabled and you have the route ``home``, it can also be accessed by ``Home``, or maybe by - ``hOme``, ``hoMe``, ``HOME``, etc., but the command will show only ``home``. - -If you see a route starting with ``x`` like the following, it indicates an invalid route that won't be routed, but the -controller has a public method for routing. - -.. code-block:: none - - +-----------+----------------+------+-------------------------------------+----------------+---------------+ - | Method | Route | Name | Handler | Before Filters | After Filters | - +-----------+----------------+------+-------------------------------------+----------------+---------------+ - | GET(auto) | x home/foo | | \App\Controllers\Home::getFoo | | | - +-----------+----------------+------+-------------------------------------+----------------+---------------+ - -The above example shows that you have the ``\App\Controllers\Home::getFoo()`` method, but it is not routed because it is -the default controller (``Home`` by default) and the default controller name must be omitted in the URI. You should -delete the ``getFoo()`` method. - -.. note:: Prior to v4.3.4, the invalid route was displayed as a normal route due to a bug. - -Auto Routing (Legacy) ---------------------- - -When you use Auto Routing (Legacy), the output is like the following: - -.. code-block:: none - - +--------+--------------------+---------------+-----------------------------------+----------------+---------------+ - | Method | Route | Name | Handler | Before Filters | After Filters | - +--------+--------------------+---------------+-----------------------------------+----------------+---------------+ - | auto | product/list[/...] | | \App\Controllers\Product::getList | | toolbar | - +--------+--------------------+---------------+-----------------------------------+----------------+---------------+ - -The *Method* will be ``auto``. - -``[/...]`` in the *Route* column indicates any number of segments. - -.. note:: When auto-routing is enabled and you have the route ``home``, it can also be accessed by ``Home``, or maybe by - ``hOme``, ``hoMe``, ``HOME``, etc., but the command will show only ``home``. - -.. _routing-spark-routes-sort-by-handler: - -Sort by Handler ---------------- - -.. versionadded:: 4.3.0 - -You can sort the routes by *handler*: - -.. code-block:: console - - php spark routes --sort-by-handler - -.. _routing-spark-routes-specify-host: - -Specify Host ------------- - -.. versionadded:: 4.4.0 - -You can specify the host in the request URL with the ``--host`` option: - -.. code-block:: console - - php spark routes --host accounts.example.com - -Getting Routing Information -*************************** - -In CodeIgniter 4, understanding and managing routing information is crucial for handling HTTP requests effectively. This -involves retrieving details about the active controller and method, as well as the filters applied to a specific route. -Below, we explore how to access this routing information to assist in tasks such as logging, debugging, or implementing -conditional logic. - -Retrieving the Current Controller/Method Names -============================================== - -In some cases, you might need to determine which controller and method have been triggered by the current HTTP request. -This can be useful for logging, debugging, or conditional logic based on the active controller method. - -CodeIgniter 4 provides a simple way to access the current route's controller and method names using the ``Router`` -class. Here is an example: - -.. literalinclude:: routing/071.php - -This functionality is particularly useful when you need to dynamically interact with your controller or log which method -is handling a particular request. - -Getting Active Filters for the Current Route -============================================ - -:doc:`Filters ` are a powerful feature that enables you to perform operations such as authentication, logging, -and security checks before or after processing HTTP requests. To access the active filters for a specific route, you can -use the :php:meth:`CodeIgniter\\Router\\Router::getFilters()` method from the ``Router`` class. - -This method returns a list of filters that are currently active for the route being processed: - -.. literalinclude:: routing/072.php - -.. note:: The ``getFilters()`` method returns only the filters defined for the specific route. It does not include - global filters or those specified in the **app/Config/Filters.php** file. - -Getting Matched Route Options for the Current Route -=================================================== - -When we're defining routes, they may have optional parameters: ``filter``, ``namespace``, ``hostname``, ``subdomain``, -``offset``, ``priority``, ``as``. All of them are described above. Additionally, if we use ``addRedirect()`` we can also -expect the ``redirect`` key. To access the values of these parameters, we can call ``Router::getMatchedRouteOptions()``. -Here is an example of the returned array: - -.. literalinclude:: routing/074.php diff --git a/user_guide_src/source/incoming/routing/001.php b/user_guide_src/source/incoming/routing/001.php deleted file mode 100644 index d799d1cf0fb5..000000000000 --- a/user_guide_src/source/incoming/routing/001.php +++ /dev/null @@ -1,3 +0,0 @@ -get('/', 'Home::index'); diff --git a/user_guide_src/source/incoming/routing/002.php b/user_guide_src/source/incoming/routing/002.php deleted file mode 100644 index 030ac6d25045..000000000000 --- a/user_guide_src/source/incoming/routing/002.php +++ /dev/null @@ -1,7 +0,0 @@ -list() -$routes->get('users', 'Users::list'); - -// Calls $Users->list(1, 23) -$routes->get('users/1/23', 'Users::list/1/23'); diff --git a/user_guide_src/source/incoming/routing/003.php b/user_guide_src/source/incoming/routing/003.php deleted file mode 100644 index 7351142dea77..000000000000 --- a/user_guide_src/source/incoming/routing/003.php +++ /dev/null @@ -1,5 +0,0 @@ -post('products', 'Product::feature'); -$routes->put('products/1', 'Product::feature'); -$routes->delete('products/1', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/004.php b/user_guide_src/source/incoming/routing/004.php deleted file mode 100644 index d7b211c8d81b..000000000000 --- a/user_guide_src/source/incoming/routing/004.php +++ /dev/null @@ -1,3 +0,0 @@ -match(['GET', 'PUT'], 'products', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/005.php b/user_guide_src/source/incoming/routing/005.php deleted file mode 100644 index ba4d8d98a28a..000000000000 --- a/user_guide_src/source/incoming/routing/005.php +++ /dev/null @@ -1,3 +0,0 @@ -get('product/(:num)', 'Catalog::productLookup'); diff --git a/user_guide_src/source/incoming/routing/006.php b/user_guide_src/source/incoming/routing/006.php deleted file mode 100644 index 7a9075b57b2f..000000000000 --- a/user_guide_src/source/incoming/routing/006.php +++ /dev/null @@ -1,3 +0,0 @@ -get('journals', 'Blogs'); diff --git a/user_guide_src/source/incoming/routing/007.php b/user_guide_src/source/incoming/routing/007.php deleted file mode 100644 index 4ee87c0af53a..000000000000 --- a/user_guide_src/source/incoming/routing/007.php +++ /dev/null @@ -1,3 +0,0 @@ -get('blog/joe', 'Blogs::users/34'); diff --git a/user_guide_src/source/incoming/routing/008.php b/user_guide_src/source/incoming/routing/008.php deleted file mode 100644 index 0e9c3afdafa7..000000000000 --- a/user_guide_src/source/incoming/routing/008.php +++ /dev/null @@ -1,3 +0,0 @@ -get('product/(:segment)', 'Catalog::productLookup'); diff --git a/user_guide_src/source/incoming/routing/009.php b/user_guide_src/source/incoming/routing/009.php deleted file mode 100644 index 638ed4492220..000000000000 --- a/user_guide_src/source/incoming/routing/009.php +++ /dev/null @@ -1,3 +0,0 @@ -get('product/(:num)', 'Catalog::productLookupByID/$1'); diff --git a/user_guide_src/source/incoming/routing/010.php b/user_guide_src/source/incoming/routing/010.php deleted file mode 100644 index c88bc65573a3..000000000000 --- a/user_guide_src/source/incoming/routing/010.php +++ /dev/null @@ -1,3 +0,0 @@ -get('product/(:any)', 'Catalog::productLookup/$1'); diff --git a/user_guide_src/source/incoming/routing/011.php b/user_guide_src/source/incoming/routing/011.php deleted file mode 100644 index 1aa779af3494..000000000000 --- a/user_guide_src/source/incoming/routing/011.php +++ /dev/null @@ -1,13 +0,0 @@ -get('product/(:segment)', 'Catalog::productLookup/$1'); diff --git a/user_guide_src/source/incoming/routing/013.php b/user_guide_src/source/incoming/routing/013.php deleted file mode 100644 index b562d01ba3b2..000000000000 --- a/user_guide_src/source/incoming/routing/013.php +++ /dev/null @@ -1,3 +0,0 @@ -get('/', [\App\Controllers\Home::class, 'index']); diff --git a/user_guide_src/source/incoming/routing/014.php b/user_guide_src/source/incoming/routing/014.php deleted file mode 100644 index 6105564b13f3..000000000000 --- a/user_guide_src/source/incoming/routing/014.php +++ /dev/null @@ -1,5 +0,0 @@ -get('/', [Home::class, 'index']); diff --git a/user_guide_src/source/incoming/routing/015.php b/user_guide_src/source/incoming/routing/015.php deleted file mode 100644 index cd98314d8fe8..000000000000 --- a/user_guide_src/source/incoming/routing/015.php +++ /dev/null @@ -1,8 +0,0 @@ -get('product/(:num)/(:num)', [Product::class, 'index']); - -// The above code is the same as the following: -$routes->get('product/(:num)/(:num)', 'Product::index/$1/$2'); diff --git a/user_guide_src/source/incoming/routing/016.php b/user_guide_src/source/incoming/routing/016.php deleted file mode 100644 index aed6cc5176df..000000000000 --- a/user_guide_src/source/incoming/routing/016.php +++ /dev/null @@ -1,8 +0,0 @@ -get('product/(:num)/(:num)', [[Product::class, 'index'], '$2/$1']); - -// The above code is the same as the following: -$routes->get('product/(:num)/(:num)', 'Product::index/$2/$1'); diff --git a/user_guide_src/source/incoming/routing/017.php b/user_guide_src/source/incoming/routing/017.php deleted file mode 100644 index cb1cdda7c78c..000000000000 --- a/user_guide_src/source/incoming/routing/017.php +++ /dev/null @@ -1,4 +0,0 @@ -addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); -$routes->get('users/(:uuid)', 'Users::show/$1'); diff --git a/user_guide_src/source/incoming/routing/018.php b/user_guide_src/source/incoming/routing/018.php deleted file mode 100644 index a1619a4bf080..000000000000 --- a/user_guide_src/source/incoming/routing/018.php +++ /dev/null @@ -1,3 +0,0 @@ -get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2'); diff --git a/user_guide_src/source/incoming/routing/019.php b/user_guide_src/source/incoming/routing/019.php deleted file mode 100644 index c9ddfae73610..000000000000 --- a/user_guide_src/source/incoming/routing/019.php +++ /dev/null @@ -1,3 +0,0 @@ -get('login/(.+)', 'Auth::login/$1'); diff --git a/user_guide_src/source/incoming/routing/020.php b/user_guide_src/source/incoming/routing/020.php deleted file mode 100644 index 450d3dd499d5..000000000000 --- a/user_guide_src/source/incoming/routing/020.php +++ /dev/null @@ -1,9 +0,0 @@ -get('feed', static function () { - $rss = new RSSFeeder(); - - return $rss->feed('general'); -}); diff --git a/user_guide_src/source/incoming/routing/021.php b/user_guide_src/source/incoming/routing/021.php deleted file mode 100644 index 8ebc27e3f9f5..000000000000 --- a/user_guide_src/source/incoming/routing/021.php +++ /dev/null @@ -1,8 +0,0 @@ - 'Catalog::productLookupById', - 'product/(:alphanum)' => 'Catalog::productLookupByName', -]; - -$routes->map($multipleRoutes); diff --git a/user_guide_src/source/incoming/routing/022.php b/user_guide_src/source/incoming/routing/022.php deleted file mode 100644 index c4da46bdd431..000000000000 --- a/user_guide_src/source/incoming/routing/022.php +++ /dev/null @@ -1,16 +0,0 @@ -get('users/profile', 'Users::profile', ['as' => 'profile']); - -// Redirect to a named route -$routes->addRedirect('users/about', 'profile'); -// Redirect to a URI -$routes->addRedirect('users/about', 'users/profile'); - -// Redirect with placeholder -$routes->get('post/(:num)/comment/(:num)', 'PostsComments::index', ['as' => 'post.comment']); - -// Redirect to a URI -$routes->addRedirect('article/(:num)/(:num)', 'post/$1/comment/$2'); -// Redirect to a named route -$routes->addRedirect('article/(:num)/(:num)', 'post.comment'); diff --git a/user_guide_src/source/incoming/routing/023.php b/user_guide_src/source/incoming/routing/023.php deleted file mode 100644 index 6f08c319c551..000000000000 --- a/user_guide_src/source/incoming/routing/023.php +++ /dev/null @@ -1,6 +0,0 @@ -group('admin', static function ($routes) { - $routes->get('users', 'Admin\Users::index'); - $routes->get('blog', 'Admin\Blog::index'); -}); diff --git a/user_guide_src/source/incoming/routing/024.php b/user_guide_src/source/incoming/routing/024.php deleted file mode 100644 index 7c66c3b693dd..000000000000 --- a/user_guide_src/source/incoming/routing/024.php +++ /dev/null @@ -1,5 +0,0 @@ -group('api', ['namespace' => 'App\API\v1'], static function ($routes) { - $routes->resource('users'); -}); diff --git a/user_guide_src/source/incoming/routing/025.php b/user_guide_src/source/incoming/routing/025.php deleted file mode 100644 index 75cec09100cb..000000000000 --- a/user_guide_src/source/incoming/routing/025.php +++ /dev/null @@ -1,5 +0,0 @@ -group('api', ['filter' => 'api-auth'], static function ($routes) { - $routes->resource('users'); -}); diff --git a/user_guide_src/source/incoming/routing/026.php b/user_guide_src/source/incoming/routing/026.php deleted file mode 100644 index c45b22d2b58f..000000000000 --- a/user_guide_src/source/incoming/routing/026.php +++ /dev/null @@ -1,9 +0,0 @@ -group('admin', ['filter' => 'myfilter1:config'], static function ($routes) { - $routes->get('/', 'Admin\Admin::index'); - - $routes->group('users', ['filter' => 'myfilter2:region'], static function ($routes) { - $routes->get('list', 'Admin\Users::list'); - }); -}); diff --git a/user_guide_src/source/incoming/routing/027.php b/user_guide_src/source/incoming/routing/027.php deleted file mode 100644 index d7624ddc6d5c..000000000000 --- a/user_guide_src/source/incoming/routing/027.php +++ /dev/null @@ -1,7 +0,0 @@ -group('', ['namespace' => 'Myth\Auth\Controllers'], static function ($routes) { - $routes->get('login', 'AuthController::login', ['as' => 'login']); - $routes->post('login', 'AuthController::attemptLogin'); - $routes->get('logout', 'AuthController::logout'); -}); diff --git a/user_guide_src/source/incoming/routing/028.php b/user_guide_src/source/incoming/routing/028.php deleted file mode 100644 index 53921b33f5eb..000000000000 --- a/user_guide_src/source/incoming/routing/028.php +++ /dev/null @@ -1,5 +0,0 @@ -environment('development', static function ($routes) { - $routes->get('builder', 'Tools\Builder::index'); -}); diff --git a/user_guide_src/source/incoming/routing/029.php b/user_guide_src/source/incoming/routing/029.php deleted file mode 100644 index 793a93588475..000000000000 --- a/user_guide_src/source/incoming/routing/029.php +++ /dev/null @@ -1,10 +0,0 @@ -get('users/(:num)/gallery/(:num)', 'Galleries::showUserGallery/$1/$2'); - -?> - - -View Gallery - diff --git a/user_guide_src/source/incoming/routing/030.php b/user_guide_src/source/incoming/routing/030.php deleted file mode 100644 index 1e0eb5baa451..000000000000 --- a/user_guide_src/source/incoming/routing/030.php +++ /dev/null @@ -1,10 +0,0 @@ -get('users/(:num)/gallery/(:num)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery']); - -?> - - -View Gallery - diff --git a/user_guide_src/source/incoming/routing/031.php b/user_guide_src/source/incoming/routing/031.php deleted file mode 100644 index e2a3784f335f..000000000000 --- a/user_guide_src/source/incoming/routing/031.php +++ /dev/null @@ -1,3 +0,0 @@ -add('products', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/032.php b/user_guide_src/source/incoming/routing/032.php deleted file mode 100644 index a82d57ebc5c7..000000000000 --- a/user_guide_src/source/incoming/routing/032.php +++ /dev/null @@ -1,3 +0,0 @@ -cli('migrate', 'App\Database::migrate'); diff --git a/user_guide_src/source/incoming/routing/033.php b/user_guide_src/source/incoming/routing/033.php deleted file mode 100644 index 1f2892fc3f0f..000000000000 --- a/user_guide_src/source/incoming/routing/033.php +++ /dev/null @@ -1,14 +0,0 @@ -add('from', 'to', $options); -$routes->get('from', 'to', $options); -$routes->post('from', 'to', $options); -$routes->put('from', 'to', $options); -$routes->head('from', 'to', $options); -$routes->options('from', 'to', $options); -$routes->delete('from', 'to', $options); -$routes->patch('from', 'to', $options); -$routes->match(['GET', 'PUT'], 'from', 'to', $options); -$routes->resource('photos', $options); -$routes->map($array, $options); -$routes->group('name', $options, static function () {}); diff --git a/user_guide_src/source/incoming/routing/034.php b/user_guide_src/source/incoming/routing/034.php deleted file mode 100644 index 2515937bb02a..000000000000 --- a/user_guide_src/source/incoming/routing/034.php +++ /dev/null @@ -1,3 +0,0 @@ -get('admin', ' AdminController::index', ['filter' => 'admin-auth']); diff --git a/user_guide_src/source/incoming/routing/035.php b/user_guide_src/source/incoming/routing/035.php deleted file mode 100644 index b50db49bd962..000000000000 --- a/user_guide_src/source/incoming/routing/035.php +++ /dev/null @@ -1,3 +0,0 @@ -post('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); diff --git a/user_guide_src/source/incoming/routing/036.php b/user_guide_src/source/incoming/routing/036.php deleted file mode 100644 index dd6cd63ba61d..000000000000 --- a/user_guide_src/source/incoming/routing/036.php +++ /dev/null @@ -1,3 +0,0 @@ -get('admin', ' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]); diff --git a/user_guide_src/source/incoming/routing/037.php b/user_guide_src/source/incoming/routing/037.php deleted file mode 100644 index 94ae43246897..000000000000 --- a/user_guide_src/source/incoming/routing/037.php +++ /dev/null @@ -1,3 +0,0 @@ -get('admin', ' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); diff --git a/user_guide_src/source/incoming/routing/038.php b/user_guide_src/source/incoming/routing/038.php deleted file mode 100644 index b992deb96ecf..000000000000 --- a/user_guide_src/source/incoming/routing/038.php +++ /dev/null @@ -1,4 +0,0 @@ -get('admin/users', 'Users::index', ['namespace' => 'Admin']); diff --git a/user_guide_src/source/incoming/routing/039.php b/user_guide_src/source/incoming/routing/039.php deleted file mode 100644 index 5b415a50138b..000000000000 --- a/user_guide_src/source/incoming/routing/039.php +++ /dev/null @@ -1,3 +0,0 @@ -get('from', 'to', ['hostname' => 'accounts.example.com']); diff --git a/user_guide_src/source/incoming/routing/040.php b/user_guide_src/source/incoming/routing/040.php deleted file mode 100644 index 32a74934eb3a..000000000000 --- a/user_guide_src/source/incoming/routing/040.php +++ /dev/null @@ -1,4 +0,0 @@ -get('from', 'to', ['subdomain' => 'media']); diff --git a/user_guide_src/source/incoming/routing/041.php b/user_guide_src/source/incoming/routing/041.php deleted file mode 100644 index 0d0fd0e67fb4..000000000000 --- a/user_guide_src/source/incoming/routing/041.php +++ /dev/null @@ -1,4 +0,0 @@ -get('from', 'to', ['subdomain' => '*']); diff --git a/user_guide_src/source/incoming/routing/042.php b/user_guide_src/source/incoming/routing/042.php deleted file mode 100644 index ec7fa680f65e..000000000000 --- a/user_guide_src/source/incoming/routing/042.php +++ /dev/null @@ -1,6 +0,0 @@ -get('users/(:num)', 'users/show/$1', ['offset' => 1]); - -// Creates: -$routes['users/(:num)'] = 'users/show/$2'; diff --git a/user_guide_src/source/incoming/routing/043.php b/user_guide_src/source/incoming/routing/043.php deleted file mode 100644 index 7abc130305b9..000000000000 --- a/user_guide_src/source/incoming/routing/043.php +++ /dev/null @@ -1,12 +0,0 @@ -setPrioritize(); - -// Config\Routes -$routes->get('(.*)', 'Posts::index', ['priority' => 1]); - -// Modules\Acme\Config\Routes -$routes->get('admin', 'Admin::index'); - -// The "admin" route will now be processed before the wildcard route. diff --git a/user_guide_src/source/incoming/routing/044.php b/user_guide_src/source/incoming/routing/044.php deleted file mode 100644 index 9465f4147e2c..000000000000 --- a/user_guide_src/source/incoming/routing/044.php +++ /dev/null @@ -1,3 +0,0 @@ -setPrioritize(false); diff --git a/user_guide_src/source/incoming/routing/045.php b/user_guide_src/source/incoming/routing/045.php deleted file mode 100644 index d3d5e66dbd7c..000000000000 --- a/user_guide_src/source/incoming/routing/045.php +++ /dev/null @@ -1,19 +0,0 @@ -get('users', 'Users::index'); - -// Controller is \Admin\Users -$routes->get('users', 'Admin\Users::index'); diff --git a/user_guide_src/source/incoming/routing/046.php b/user_guide_src/source/incoming/routing/046.php deleted file mode 100644 index 78768c76044a..000000000000 --- a/user_guide_src/source/incoming/routing/046.php +++ /dev/null @@ -1,10 +0,0 @@ -setDefaultNamespace('App'); - -// Controller is \App\Users -$routes->get('users', 'Users::index'); - -// Controller is \App\Admin\Users -$routes->get('users', 'Admin\Users::index'); diff --git a/user_guide_src/source/incoming/routing/049.php b/user_guide_src/source/incoming/routing/049.php deleted file mode 100644 index 303fff95304a..000000000000 --- a/user_guide_src/source/incoming/routing/049.php +++ /dev/null @@ -1,15 +0,0 @@ -setTranslateURIDashes(true); diff --git a/user_guide_src/source/incoming/routing/050.php b/user_guide_src/source/incoming/routing/050.php deleted file mode 100644 index f11fabf834f9..000000000000 --- a/user_guide_src/source/incoming/routing/050.php +++ /dev/null @@ -1,15 +0,0 @@ -setAutoRoute(false); diff --git a/user_guide_src/source/incoming/routing/051.php b/user_guide_src/source/incoming/routing/051.php deleted file mode 100644 index 33852c87e021..000000000000 --- a/user_guide_src/source/incoming/routing/051.php +++ /dev/null @@ -1,12 +0,0 @@ -setPrioritize(); - -// to disable -$routes->setPrioritize(false); diff --git a/user_guide_src/source/incoming/routing/063.php b/user_guide_src/source/incoming/routing/063.php deleted file mode 100644 index 4996345ed7ae..000000000000 --- a/user_guide_src/source/incoming/routing/063.php +++ /dev/null @@ -1,4 +0,0 @@ -post('api/users', 'Api\Users::update'); diff --git a/user_guide_src/source/incoming/routing/064.php b/user_guide_src/source/incoming/routing/064.php deleted file mode 100644 index 8d6df0548e30..000000000000 --- a/user_guide_src/source/incoming/routing/064.php +++ /dev/null @@ -1,4 +0,0 @@ -get('blog', '\Acme\Blog\Controllers\Home::list'); diff --git a/user_guide_src/source/incoming/routing/065.php b/user_guide_src/source/incoming/routing/065.php deleted file mode 100644 index ad3c10094075..000000000000 --- a/user_guide_src/source/incoming/routing/065.php +++ /dev/null @@ -1,4 +0,0 @@ -view('about', 'pages/about'); diff --git a/user_guide_src/source/incoming/routing/066.php b/user_guide_src/source/incoming/routing/066.php deleted file mode 100644 index 10f867f186fc..000000000000 --- a/user_guide_src/source/incoming/routing/066.php +++ /dev/null @@ -1,7 +0,0 @@ -view('map/(:segment)/(:segment)', 'map'); - -// Within the view, you can access the segments with -// $segments[0] and $segments[1] respectively. diff --git a/user_guide_src/source/incoming/routing/067.php b/user_guide_src/source/incoming/routing/067.php deleted file mode 100644 index 7a486fb1d7c3..000000000000 --- a/user_guide_src/source/incoming/routing/067.php +++ /dev/null @@ -1,3 +0,0 @@ -add('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); diff --git a/user_guide_src/source/incoming/routing/068.php b/user_guide_src/source/incoming/routing/068.php deleted file mode 100644 index 50b0891ce928..000000000000 --- a/user_guide_src/source/incoming/routing/068.php +++ /dev/null @@ -1,13 +0,0 @@ -set404Override('App\Errors::show404'); - -// Will display a custom view. -$routes->set404Override(static function () { - // If you want to get the URI segments. - $segments = request()->getUri()->getSegments(); - - return view('my_errors/not_found.html'); -}); diff --git a/user_guide_src/source/incoming/routing/070.php b/user_guide_src/source/incoming/routing/070.php deleted file mode 100644 index f62961f1bcf6..000000000000 --- a/user_guide_src/source/incoming/routing/070.php +++ /dev/null @@ -1,11 +0,0 @@ -controllerName(); - -// Retrieve the method name being executed in the controller for the current request. -$method = $router->methodName(); - -echo 'Current Controller: ' . $controller . '
'; -echo 'Current Method: ' . $method; diff --git a/user_guide_src/source/incoming/routing/072.php b/user_guide_src/source/incoming/routing/072.php deleted file mode 100644 index dbf695c57d86..000000000000 --- a/user_guide_src/source/incoming/routing/072.php +++ /dev/null @@ -1,8 +0,0 @@ -getFilters(); - -echo 'Active Filters for the Route: ' . implode(', ', $filters); diff --git a/user_guide_src/source/incoming/routing/073.php b/user_guide_src/source/incoming/routing/073.php deleted file mode 100644 index b8c42b0ad7d5..000000000000 --- a/user_guide_src/source/incoming/routing/073.php +++ /dev/null @@ -1,3 +0,0 @@ -get('from', 'to', ['hostname' => ['s1.example.com', 's2.example.com']]); diff --git a/user_guide_src/source/incoming/routing/074.php b/user_guide_src/source/incoming/routing/074.php deleted file mode 100644 index 74eaeaf7e353..000000000000 --- a/user_guide_src/source/incoming/routing/074.php +++ /dev/null @@ -1,23 +0,0 @@ -getMatchedRouteOptions(); - -echo 'Route name: ' . $options['as']; - -print_r($options); - -// Route name: api:auth -// -// Array -// ( -// [filter] => api-auth -// [namespace] => App\API\v1 -// [hostname] => example.com -// [subdomain] => api -// [offset] => 1 -// [priority] => 1 -// [as] => api:auth -// ) diff --git a/user_guide_src/source/index.rst b/user_guide_src/source/index.rst deleted file mode 100644 index cf781b282018..000000000000 --- a/user_guide_src/source/index.rst +++ /dev/null @@ -1,124 +0,0 @@ -####################### -CodeIgniter4 User Guide -####################### - -.. toctree:: - :includehidden: - :titlesonly: - - intro/index - -*************** -Getting Started -*************** - -.. toctree:: - :maxdepth: 2 - :titlesonly: - - installation/index - -****** -Guides -****** - -.. toctree:: - :includehidden: - :titlesonly: - - guides/index - -************************* -Overview & General Topics -************************* - -.. toctree:: - :titlesonly: - - concepts/index - -.. toctree:: - :titlesonly: - - general/index - -**************** -Request Handling -**************** - -.. toctree:: - :titlesonly: - - incoming/index - -.. toctree:: - :titlesonly: - - outgoing/index - -****************** -Handling Databases -****************** - -.. toctree:: - :titlesonly: - - database/index - -.. toctree:: - :titlesonly: - - models/index - -.. toctree:: - :titlesonly: - - dbmgmt/index - -******************* -Libraries & Helpers -******************* - -.. toctree:: - :titlesonly: - - libraries/index - -.. toctree:: - :titlesonly: - - helpers/index - -*************** -Advanced Topics -*************** - -.. toctree:: - :titlesonly: - - testing/index - -.. toctree:: - :titlesonly: - - cli/index - -.. toctree:: - :titlesonly: - - extending/index - -.. toctree:: - :hidden: - - license - changelogs/index - -***************** -Official Packages -***************** - -.. toctree:: - :titlesonly: - - libraries/official_packages diff --git a/user_guide_src/source/installation/backward_compatibility_notes.rst b/user_guide_src/source/installation/backward_compatibility_notes.rst deleted file mode 100644 index 5d404ddf31c8..000000000000 --- a/user_guide_src/source/installation/backward_compatibility_notes.rst +++ /dev/null @@ -1,25 +0,0 @@ -############################ -Backward Compatibility Notes -############################ - -We try to develop our products to be as backward compatible (BC) as possible. - -Only major releases (such as 4.0, 5.0 etc.) are allowed to break backward compatibility. Minor releases (such as 4.2, -4.3 etc.) may introduce new features, but must do so without breaking the existing API. - -However, the code is not mature and bug fixes may break compatibility in minor releases, or even in patch releases (such -as 4.2.5). In that case, all the breaking changes are described in the :doc:`../changelogs/index`. - -***************************** -What are not Breaking Changes -***************************** - -- Deprecated items are not covered by the backward compatibility (BC) promise. They may be removed in the second - subsequent **minor** version or later. For example, if an item has been deprecated since 4.3.x, it may be removed in - 4.5.0. -- System messages defined in **system/Language/en/** are strictly for internal framework use and are not covered by the - backward compatibility (BC) promise. If developers are relying on language string output, they should be checking it - against the function call (``lang('...')``), not the content. -- `Named arguments `_ are not covered - by the backward compatibility (BC) promise. We may choose to rename method/function parameter names when necessary in - order to improve the codebase. diff --git a/user_guide_src/source/installation/deployment.rst b/user_guide_src/source/installation/deployment.rst deleted file mode 100644 index 1336e2a3a335..000000000000 --- a/user_guide_src/source/installation/deployment.rst +++ /dev/null @@ -1,207 +0,0 @@ -########## -Deployment -########## - -.. contents:: - :local: - :depth: 3 - -************ -Optimization -************ - -Before deploying your CodeIgniter application to production, there are several things you can do to make your -application run more efficiently. - -This section describes the optimization features that CodeIgniter provides. - -.. _spark_optimize: - -spark optimize -============== - -.. versionadded:: 4.5.0 - -The ``spark optimize`` command performs the following optimizations: - -- `Removing Dev Packages`_ -- Enabling `Config Caching`_ -- Enabling `FileLocator Caching`_ - -.. warning:: Do not use ``spark optimize`` when running the app in the :doc:`worker_mode`. - -Composer Optimization -===================== - -Removing Dev Packages ---------------------- - -When you deploy, don't forget to run the following command: - -.. code-block:: console - - composer install --no-dev - -The above command will remove the development-only Composer packages that are not needed in the production environment. -This will greatly reduce the vendor folder size. - -Specifying Packages to Discover -------------------------------- - -If Composer Package Auto-Discovery is enabled, all Composer packages are scanned when needed. But there is no need to -scan packages that are not CodeIgniter packages, so specifying the packages to be scanned prevents unnecessary scanning. - -See :ref:`modules-specify-composer-packages`. - -Config Caching -============== - -.. important:: Once cached, configuration values are never changed until the cache is deleted, even if the configuration - file or **.env** is changed. - -Caching the Config objects can improve performance. However, the cache must be manually deleted when changing Config -values. - -See :ref:`factories-config-caching`. - -FileLocator Caching -=================== - -Caching the file paths that FileLocator found can improve performance. However, the cache must be manually deleted when -adding/deleting/changing file paths. - -See :ref:`file-locator-caching`. - -PHP Preloading -============== - -With PHP preloading, you can instruct the server to load essential files like functions and classes into memory during -startup. This means these elements are readily available for all requests, skipping the usual loading process and -boosting your application's performance. However, this comes at the cost of increased memory usage and requires -restarting the PHP engine for changes to take effect. - -.. note:: If you want to use `Preloading `_, we provide a - `preload script `_. - -Requirement ------------ - -Using preloading requires one dedicated PHP handler. Normally, web servers are configured to use one PHP handler, so one -app requires a dedicated web server. If you want to use preloading for multiple apps on one web server, configure your -server to use virtual hosts with multiple PHP handlers like multiple PHP-FPMs, with each virtual host using one PHP -handler. Preloading keeps the relevant definitions in memory by reading the files specified in ``opcache.preload``. - -.. note:: See :ref:`running-multiple-app` to make one core CodeIgniter4 handle your multiple apps. - -Configuration -------------- - -Open ``php.ini``, or ``xx-opcache.ini`` if you have split INI configuration in PHP. We recommend setting -``opcache.preload=/path/to/preload.php`` and ``opcache.preload_user=myuser``. - -.. note:: ``myuser`` is the user running your web server. If you want to find the location of the split INI - configuration, just run ``php --ini`` or open a ``phpinfo()`` page and search for *Additional .ini files parsed*. - -Make sure you use the appstarter installation. If using manual installation, you must change the directory in the -``include`` path. - -.. literalinclude:: preloading/001.php - -.. _deployment-to-shared-hosting-services: - -************************************* -Deployment to Shared Hosting Services -************************************* - -.. important:: - **index.php** is no longer in the root of the project! It has been moved inside the **public** folder, for better - security and separation of components. - - This means that you should configure your web server to "point" to your project's **public** folder, and not to the - project root. - -Specifying the Document Root -============================ - -The best way is to set the document root to the **public** folder in the server configuration:: - - └── example.com/ (project folder) - └── public/ (document root) - -Check with your hosting service provider to see if you can change the document root. Unfortunately, if you cannot change -the document root, go to the next way. - -Using Two Directories -===================== - -The second way is to use two directories, and adjust the path. One is for the application and the other is the default -document root. - -Upload the contents of the **public** folder to **public_html** (the default document root) and the other files to the -directory for the application:: - - ├── example.com/ (for the application) - │ ├── app/ - │ ├── vendor/ (or system/) - │ └── writable/ - └── public_html/ (the default document root) - ├── .htaccess - ├── favicon.ico - ├── index.php - └── robots.txt - -See `Install CodeIgniter 4 on Shared Hosting (cPanel) `_ for -details. - -Adding .htaccess -================ - -The last resort is to add **.htaccess** to the project root. - -It is not recommended that you place the project folder in the document root. However, if you have no other choice, you -can use this. - -Place your project folder as follows, where **public_html** is the document root, and create the **.htaccess** file:: - - └── public_html/ (the default document root) - └── example.com/ (project folder) - ├── .htaccess - └── public/ - -And edit **.htaccess** as follows: - -.. code-block:: apache - - - RewriteEngine On - RewriteRule ^(.*)$ public/$1 [L] - - - - Require all denied - Satisfy All - - -And remove the redirect settings in **public/.htaccess**: - -.. code-block:: diff - - --- a/public/.htaccess - +++ b/public/.htaccess - @@ -16,16 +16,6 @@ Options -Indexes - # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase - # RewriteBase / - - - # Redirect Trailing Slashes... - - RewriteCond %{REQUEST_FILENAME} !-d - - RewriteCond %{REQUEST_URI} (.+)/$ - - RewriteRule ^ %1 [L,R=301] - - - - # Rewrite "www.example.com -> example.com" - - RewriteCond %{HTTPS} !=on - - RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] - - RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] - - - # Checks to see if the user is attempting to access a valid file, - # such as an image or css document, if this isn't true it sends the - # request to the front controller, index.php diff --git a/user_guide_src/source/installation/index.rst b/user_guide_src/source/installation/index.rst deleted file mode 100644 index 8769d4bf9ca5..000000000000 --- a/user_guide_src/source/installation/index.rst +++ /dev/null @@ -1,30 +0,0 @@ -############ -Installation -############ - -CodeIgniter has two supported installation methods: manual download, or using `Composer `_. -Which is right for you? - -- We recommend the Composer installation because it keeps CodeIgniter up to date easily. -- If you would like the simple "download & go" install that CodeIgniter 3 is known for, choose the manual installation. - -However you choose to install and run CodeIgniter4, the latest `user guide `_ is -accessible online. If you want to see previous versions, you can download them from the -`codeigniter4/userguide `_ repository. - -.. note:: Before using CodeIgniter 4, make sure that your server meets the :doc:`requirements `, in - particular the PHP version and the PHP extensions that are needed. You may find that you have to uncomment the - ``php.ini`` "extension" lines to enable "curl" and "intl", for instance. - -.. toctree:: - :titlesonly: - - installing_composer - installing_manual - running - worker_mode - troubleshooting - deployment - ../changelogs/index - upgrading - repositories diff --git a/user_guide_src/source/installation/installing_composer.rst b/user_guide_src/source/installation/installing_composer.rst deleted file mode 100644 index e120d2463dcf..000000000000 --- a/user_guide_src/source/installation/installing_composer.rst +++ /dev/null @@ -1,306 +0,0 @@ -Composer Installation -##################### - -.. contents:: - :local: - :depth: 2 - -Composer can be used in two ways to install CodeIgniter4 on your system. - -.. important:: CodeIgniter4 requires Composer 2.0.14 or later. - -.. note:: If you are not familiar with Composer, we recommend you read - `Basic usage `_ first. - -The first technique describes creating a skeleton project (app starter) using CodeIgniter4, which you would then use as -the base for a new webapp. The second technique described below lets you add CodeIgniter4 to an existing webapp. - -.. note:: If you are using a Git repository to store your code, or for collaboration with others, then the **vendor** - folder would normally be "git ignored". In such a case, you will need to do a ``composer install`` (or - ``composer update`` if you want to update all Composer dependencies) when you clone the repository to a new system. - -App Starter -=========== - -The `CodeIgniter 4 app starter `_ repository holds a skeleton application, -with a composer dependency on the latest released version of the framework. - -This installation technique would suit a developer who wishes to start a new CodeIgniter4-based project. - -Installation ------------- - -In the folder above your project root: - -.. code-block:: console - - composer create-project codeigniter4/appstarter project-root - -The command above will create a **project-root** folder. - -If you omit the "project-root" argument, the command will create an "appstarter" folder, which can be renamed as -appropriate. - -.. note:: Before v4.4.0, the CodeIgniter autoloader did not allow special characters that are illegal in filenames on - certain operating systems. The symbols that can be used are ``/``, ``_``, ``.``, ``:``, ``\`` and space. So if you - installed CodeIgniter under a folder that contains special characters like ``(``, ``)``, etc., CodeIgniter didn't - work. Since v4.4.0, this restriction has been removed. - -.. important:: When you deploy to your production server, don't forget to run the following command: - - .. code-block:: console - - composer install --no-dev - - The above command will remove the development-only Composer packages that are not needed in the production - environment. This will greatly reduce the vendor folder size. - -Installing Previous Versions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For example, you may want to install v4.4.8 after v4.5.0 has been released. - -In that case, specify the version in the command: - -.. code-block:: console - - composer create-project codeigniter4/appstarter:4.4.8 project-root - -Then, open **composer.json** in your project root folder, and specify the framework version: - -.. code-block:: text - - "require": { - ... - "codeigniter4/framework": "4.4.8" - }, - -Then, run the ``composer update`` command. - -.. note:: When you use a fixed version number like ``"codeigniter4/framework": "4.4.8"`` in your **composer.json**, the - ``composer update`` command will not update the framework to the latest version. See `Writing Version Constraints`_ - for how to specify the version. - -.. _Writing Version Constraints: https://getcomposer.org/doc/articles/versions.md#writing-version-constraints - -Initial Configuration ---------------------- - -After installation, a few initial configurations are required. See :ref:`initial-configuration` for the details. - -.. _app-starter-upgrading: - -Upgrading ---------- - -Whenever there is a new release, run this from the command line in your project root: - -.. code-block:: console - - composer update - -Read the :doc:`upgrade instructions ` and :doc:`change log <../changelogs/index>`, and check Breaking Changes -and Enhancements. - -Upgrading to a Specified Version -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For example, you may want to upgrade from v4.4.7 to v4.4.8 after v4.5.0 has been released. - -In that case, open **composer.json** in your project root folder, and specify the framework version: - -.. code-block:: text - - "require": { - ... - "codeigniter4/framework": "4.4.8" - }, - -Then, run the ``composer update`` command. - -.. note:: When you use a fixed version number like ``"codeigniter4/framework": "4.4.8"`` in your **composer.json**, the - ``composer update`` command will not update the framework to the latest version. See `Writing Version Constraints`_ - for how to specify the version. - -Pros ----- - -Simple installation; easy to update. - -Cons ----- - -You still need to check for file changes in the **project space** (root, app, public, writable) and merge them after -updating. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Structure ---------- - -Folders in your project after setup: - -- app, public, tests, writable -- vendor/codeigniter4/framework/system - -.. _switch-to-dev-version: - -Latest Dev ----------- - -The App Starter repo comes with a **builds** script to switch Composer sources between the current stable release and -the latest development branch of the framework. This script is for developers who are willing to live with the latest -unreleased changes, which may be unstable. This way you can help find bugs and improve new features. - -The `development user guide `_ is accessible online. Note that this -differs from the released user guide, and will pertain to the develop branch explicitly. - -Before running the script, check ``$files``, which is the list of files to be changed. This is useful if you have -additional places in the code that mention the directory with the framework. - -.. note:: You should not rely on the version of the framework in your project because the development code may contain - an incorrect number. - -Update for Latest Dev -^^^^^^^^^^^^^^^^^^^^^ - -In your project root: - -.. code-block:: console - - php builds development - -The command above will update **composer.json** to point to the ``develop`` branch of the working repository, and update -the corresponding paths in config and XML files. - -After using the ``builds`` command, be sure to run ``composer update`` to sync your vendor folder with the latest target -build. Then, check the :doc:`upgrading` and update project files if necessary. - -Next Minor Version -^^^^^^^^^^^^^^^^^^ - -If you want to use the next minor version branch: - -.. code-block:: console - - php builds next - -And run ``composer update`` to sync your vendor folder with the latest target build. Then, check the Upgrading Guide -(**user_guide_src/source/installation/upgrade_{version}.rst**) and update project files if necessary. - -Revert to Stable Release -^^^^^^^^^^^^^^^^^^^^^^^^ - -To revert the changes, run: - -.. code-block:: console - - php builds release - -Adding CodeIgniter4 to an Existing Project -========================================== - -The same `CodeIgniter 4 framework `_ repository described in "Manual -Installation" can also be added to an existing project using Composer. - -Installation ------------- - -Develop your app inside the ``app`` folder, and the ``public`` folder will be your document root. - -In your project root: - -.. code-block:: console - - composer require codeigniter4/framework - -.. important:: When you deploy to your production server, don't forget to run the following command: - - .. code-block:: console - - composer install --no-dev - - The above command will remove the development-only Composer packages that are not needed in the production - environment. This will greatly reduce the vendor folder size. - -Setting Up ----------- - -1. Copy the **app**, **public**, **tests** and **writable** folders from **vendor/codeigniter4/framework** to your - project root. -2. Copy the **env**, **phpunit.dist.xml** and **spark** files from **vendor/codeigniter4/framework** to your project - root. -3. You will have to adjust the ``$systemDirectory`` property in **app/Config/Paths.php** to refer to the vendor one, - e.g., ``__DIR__ . '/../../vendor/codeigniter4/framework/system'``. - -Initial Configuration ---------------------- - -A few initial configurations are required. See :ref:`initial-configuration` for the details. - -.. _adding-codeigniter4-upgrading: - -Upgrading ---------- - -Whenever there is a new release, run this from the command line in your project root: - -.. code-block:: console - - composer update - -Read the :doc:`upgrade instructions ` and :doc:`change log <../changelogs/index>`, and check Breaking Changes -and Enhancements. - -Upgrading to a Specified Version -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For example, you may want to upgrade from v4.4.7 to v4.4.8 after v4.5.0 has been released. - -In that case, open **composer.json** in your project root folder, and specify the framework version: - -.. code-block:: text - - "require": { - ... - "codeigniter4/framework": "4.4.8" - }, - -Then, run the ``composer update`` command. - -Pros ----- - -Relatively simple installation; easy to update. - -Cons ----- - -You still need to check for file changes in the **project space** (root, app, public, writable) after updating. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Structure ---------- - -Folders in your project after setup: - -- app, public, tests, writable -- vendor/codeigniter4/framework/system - -Translations Installation -========================= - -If you want to take advantage of the system message translations, they can be added to your project in a similar -fashion. - -From the command line inside your project root: - -.. code-block:: console - - composer require codeigniter4/translations - -Copy the contents of the **vendor/codeigniter4/translations/Language** folder to your **app/Language** folder. These -will be updated along with the framework whenever you do a ``composer update``. diff --git a/user_guide_src/source/installation/installing_manual.rst b/user_guide_src/source/installation/installing_manual.rst deleted file mode 100644 index d94f7bb9f781..000000000000 --- a/user_guide_src/source/installation/installing_manual.rst +++ /dev/null @@ -1,70 +0,0 @@ -Manual Installation -################### - -.. contents:: - :local: - :depth: 2 - -The `CodeIgniter 4 framework `_ repository holds the released versions of the -framework. It is intended for developers who do not wish to use Composer. - -Develop your app inside the **app** folder, and the **public** folder will be your public-facing document root. Do not -change anything inside the **system** folder! - -.. note:: This is the installation technique closest to that described for - `CodeIgniter 3 `_. - -Installation -============ - -Download the `latest version `_, and extract it to become -your project root. - -.. note:: Before v4.4.0, the CodeIgniter autoloader did not allow special characters that are illegal in filenames on - certain operating systems. The symbols that can be used are ``/``, ``_``, ``.``, ``:``, ``\`` and space. So if you - installed CodeIgniter under a folder that contains special characters like ``(``, ``)``, etc., CodeIgniter didn't - work. Since v4.4.0, this restriction has been removed. - -Initial Configuration -===================== - -After installation, a few initial configurations are required. See :ref:`initial-configuration` for details. - -.. _installing-manual-upgrading: - -Upgrading -========= - -Download a new copy of the framework, and then replace the **system** folder. - -Read the :doc:`upgrade instructions ` and :doc:`change log <../changelogs/index>`, and check Breaking Changes -and Enhancements. - -Pros -==== - -Download and run. - -Cons -==== - -You need to check for file changes in the **project space** (root, app, public, tests, writable) and merge them by -yourself. - -Structure -========= - -Folders in your project after setup: - -- app, public, tests, writable, system - -Translations Installation -========================= - -If you want to take advantage of the system message translations, they can be added to your project in a similar -fashion. - -Download the `latest version of them `_. Extract the -downloaded zip, and copy the contents of its **Language** folder to your **app/Language** folder. - -This would need to be repeated to incorporate any updates to the translations. diff --git a/user_guide_src/source/installation/preloading/001.php b/user_guide_src/source/installation/preloading/001.php deleted file mode 100644 index 059c6d846613..000000000000 --- a/user_guide_src/source/installation/preloading/001.php +++ /dev/null @@ -1,20 +0,0 @@ - __DIR__ . '/system', // <== change this line to where CI is installed - // ... - ], - ]; - - // ... -} - -// ... diff --git a/user_guide_src/source/installation/repositories.rst b/user_guide_src/source/installation/repositories.rst deleted file mode 100644 index 101ad0058336..000000000000 --- a/user_guide_src/source/installation/repositories.rst +++ /dev/null @@ -1,103 +0,0 @@ -CodeIgniter Repositories -######################## - -.. contents:: - :local: - :depth: 2 - -codeigniter4 organization -========================= - -The CodeIgniter 4 open source project has its own `GitHub organization `_. - -There are several development repositories of interest to potential contributors: - -+------------------+--------------+-----------------------------------------------------------------+ -| Repository | Audience | Description | -+==================+==============+=================================================================+ -| CodeIgniter4_ | contributors | Project codebase, including tests & user guide sources | -+------------------+--------------+-----------------------------------------------------------------+ -| translations_ | developers | System message translations | -+------------------+--------------+-----------------------------------------------------------------+ -| coding-standard_ | contributors | Coding style conventions & rules | -+------------------+--------------+-----------------------------------------------------------------+ -| devkit_ | developers | Development toolkit for CodeIgniter libraries and projects | -+------------------+--------------+-----------------------------------------------------------------+ -| settings_ | developers | Settings Library for CodeIgniter 4 | -+------------------+--------------+-----------------------------------------------------------------+ -| shield_ | developers | Authentication and Authorization Library for CodeIgniter 4 | -+------------------+--------------+-----------------------------------------------------------------+ -| tasks_ | developers | Task Scheduler for CodeIgniter 4 | -+------------------+--------------+-----------------------------------------------------------------+ -| cache_ | developers | PSR-6 and PSR-16 Cache Adapters for CodeIgniter 4 | -+------------------+--------------+-----------------------------------------------------------------+ -| queue_ | developers | Job Queue for CodeIgniter 4 | -+------------------+--------------+-----------------------------------------------------------------+ - -.. _CodeIgniter4: https://github.com/codeigniter4/CodeIgniter4 -.. _translations: https://github.com/codeigniter4/translations -.. _coding-standard: https://github.com/CodeIgniter/coding-standard -.. _devkit: https://github.com/codeigniter4/devkit -.. _settings: https://github.com/codeigniter4/settings -.. _shield: https://codeigniter4.github.io/shield -.. _tasks: https://github.com/codeigniter4/tasks -.. _cache: https://github.com/codeigniter4/cache -.. _queue: https://github.com/codeigniter4/queue - -There are also several deployment repositories, referenced in the installation directions. The deployment repositories -are built automatically when a new version is released, and they are not directly contributed to. - -+------------------+--------------+-----------------------------------------------------------------+ -| Repository | Audience | Description | -+==================+==============+=================================================================+ -| framework_ | developers | Released versions of the framework | -+------------------+--------------+-----------------------------------------------------------------+ -| appstarter_ | developers | Starter project (app/public/writable). | -| | | Dependent on "framework" | -+------------------+--------------+-----------------------------------------------------------------+ -| userguide_ | anyone | Pre-built user guide | -+------------------+--------------+-----------------------------------------------------------------+ - -.. _framework: https://github.com/codeigniter4/framework -.. _appstarter: https://github.com/codeigniter4/appstarter -.. _userguide: https://github.com/codeigniter4/userguide - -In all the above, the latest version of a repository can be downloaded from the **Releases** section of its GitHub -repository page. The current development version of each can be cloned or downloaded using the **Code** dropdown on the -repository homepage. - -Composer Packages -================= - -We also maintain composer-installable packages on `packagist.org `_. -These correspond to the repositories mentioned above: - -- `codeigniter4/framework `_ -- `codeigniter4/appstarter `_ -- `codeigniter4/translations `_ -- `codeigniter/coding-standard `_ -- `codeigniter4/devkit `_ -- `codeigniter4/settings `_ -- `codeigniter4/shield `_ -- `codeigniter4/cache `_ - -See the :doc:`Installation ` page for more information. - -CodeIgniter 4 Projects -====================== - -We maintain a `codeigniter4projects `_ organization on GitHub as well, with -projects that are not part of the framework, but which showcase it or make it easier to work with! - -+------------------+--------------+-----------------------------------------------------------------+ -| Repository | Audience | Description | -+==================+==============+=================================================================+ -| website_ | developers | The codeigniter.com website, written in CodeIgniter 4 | -+------------------+--------------+-----------------------------------------------------------------+ -| playground_ | developers | Basic code examples in project form. Still growing. | -+------------------+--------------+-----------------------------------------------------------------+ - -.. _website: https://github.com/codeigniter4projects/website -.. _playground: https://github.com/codeigniter4projects/playground - -These are not composer-installable repositories. diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst deleted file mode 100644 index 993ce3d19a86..000000000000 --- a/user_guide_src/source/installation/running.rst +++ /dev/null @@ -1,541 +0,0 @@ -################ -Running Your App -################ - -.. contents:: - :local: - :depth: 3 - -A CodeIgniter 4 app can be run in a number of different ways: hosted on a web server, using virtualization, or using -CodeIgniter's command line tool for testing. This section addresses how to use each technique, and explains some of the -pros and cons of them. - -.. important:: You should always be careful about the case of filenames. Many developers develop on case-insensitive - file systems on Windows or macOS. However, most server environments use case-sensitive file systems. If the file - name case is incorrect, code that works locally will not work on the server. - -If you're new to CodeIgniter, please read the :doc:`Getting Started ` section of the User Guide to begin -learning how to build dynamic PHP applications. Enjoy! - -.. _initial-configuration: - -********************* -Initial Configuration -********************* - -Configure for Your Site URIs -============================ - -Open the **app/Config/App.php** file with a text editor. - -#. ``$baseURL`` - Set your base URL in ``$baseURL``. If you need more flexibility, the baseURL may - be set within the :ref:`.env ` file as ``app.baseURL = 'http://example.com/'``. - **Always use a trailing slash on your base URL!** - - .. note:: If you don't set the ``$baseURL`` correctly, in development mode, the debug toolbar may not load properly - and web pages may take considerably longer to display. - -#. ``$indexPage`` - If you don't want to include **index.php** in your site URIs, set ``$indexPage`` to ``''``. - The setting will be used when the framework generates your site URIs. - - .. note:: You may need to configure your web server to access your site with a URL that does not contain - **index.php**. See :ref:`CodeIgniter URLs `. - -Configure Database Connection Settings -====================================== - -If you intend to use a database, open the **app/Config/Database.php** file with a text editor and set your database -settings. Alternatively, these could be set in your **.env** file. See -:ref:`Database Configuration ` for details. - -Set to Development Mode -======================= - -If the site is not on the production server, set ``CI_ENVIRONMENT`` to ``development`` in the **.env** file to take -advantage of the debugging tools provided. See :ref:`setting-development-mode` for details. - -.. important:: In production environments, you should disable error display and any other development-only - functionality. In CodeIgniter, this can be done by setting the environment to "production". By default, the - application will run using the "production" environment. See also :ref:`environment-constant`. - -Set Writable Folder Permission -============================== - -If you will be running your site using a web server (e.g., Apache or nginx), you will need to modify the permissions for -the **writable** folder inside your project, so that it is writable by the user or account used by your web server. - -.. _spark-phpini-check: - -Checking PHP ini Settings -========================= - -.. versionadded:: 4.5.0 - -`PHP ini settings`_ change the behavior of PHP. CodeIgniter provides a command to check important PHP settings. - -.. _PHP ini settings: https://www.php.net/manual/en/ini.list.php - -.. code-block:: console - - php spark phpini:check - -The *Recommended* column shows the recommended values for production environments. They may differ in development -environments. - -.. note:: - If you cannot use the spark command, you can use ``CheckPhpIni::run(false)`` in your controller. - - E.g., - - .. code-block:: php - - `_ - -2. Generate worker mode files: - - .. code-block:: console - - php spark worker:install - -3. Start the server: - - .. code-block:: console - - frankenphp run - -For detailed configuration, performance tuning, and important considerations about state management, see -:doc:`worker_mode`. - -******************* -Hosting with Apache -******************* - -A CodeIgniter4 webapp is normally hosted on a web server. Apache HTTP Server is the "standard" platform, and is assumed -in much of our documentation. - -Apache is bundled with many platforms, but can also be downloaded in a bundle with a database engine and PHP from -`Bitnami `_. - -Configure Main Config File -========================== - -Enabling mod_rewrite --------------------- - -The "mod_rewrite" module enables URLs without "**index.php**" in them, and is assumed in our user guide. - -Make sure that the rewrite module is enabled (uncommented) in the main configuration file, e.g., -**apache2/conf/httpd.conf**: - -.. code-block:: apache - - LoadModule rewrite_module modules/mod_rewrite.so - -Setting Document Root ---------------------- - -Also make sure that the default document root's ```` element enables this too, in the ``AllowOverride`` -setting: - -.. code-block:: apache - - - Options Indexes FollowSymLinks - AllowOverride All - Require all granted - - -Hosting with VirtualHost -======================== - -We recommend using "virtual hosting" to run your apps. You can set up different aliases for each of the apps you work -on. - -Enabling vhost_alias_module ---------------------------- - -Make sure that the virtual hosting module is enabled (uncommented) in the main configuration file, e.g., -**apache2/conf/httpd.conf**: - -.. code-block:: apache - - LoadModule vhost_alias_module modules/mod_vhost_alias.so - -Adding Host Alias ------------------ - -Add a host alias in your "hosts" file, typically **/etc/hosts** on unix-type platforms, or -**c:\\Windows\\System32\\drivers\\etc\\hosts** on Windows. - -Add a line to the file. This could be ``myproject.local`` or ``myproject.test``, for instance:: - - 127.0.0.1 myproject.local - -Setting VirtualHost -------------------- - -Add a ```` element for your webapp inside the virtual hosting configuration, e.g., -**apache2/conf/extra/httpd-vhost.conf**: - -.. code-block:: apache - - - DocumentRoot "/opt/lamp/apache2/myproject/public" - ServerName myproject.local - ErrorLog "logs/myproject-error_log" - CustomLog "logs/myproject-access_log" common - - - AllowOverride All - Require all granted - - - -The above configuration assumes the project folder is located as follows: - -.. code-block:: text - - apache2/ - ├── myproject/ (Project Folder) - │ └── public/ (DocumentRoot for myproject.local) - └── htdocs/ - -Restart Apache. - -Testing -------- - -With the above configuration, your webapp would be accessed with the URL **http://myproject.local/** in your browser. - -Apache needs to be restarted whenever you change its configuration. - -Hosting with Subfolder -====================== - -If you want a baseURL like **http://localhost/myproject/** with a subfolder, there are three ways. - -Making Symlink --------------- - -Place your project folder as follows, where **htdocs** is the Apache document root:: - - ├── myproject/ (project folder) - │ └── public/ - └── htdocs/ - -Navigate to the **htdocs** folder and create a symbolic link as follows: - -.. code-block:: console - - cd htdocs/ - ln -s ../myproject/public/ myproject - -Using Alias ------------ - -Place your project folder as follows, where **htdocs** is the Apache document root:: - - ├── myproject/ (project folder) - │ └── public/ - └── htdocs/ - -Add the following in the main configuration file, e.g., **apache2/conf/httpd.conf**: - -.. code-block:: apache - - Alias /myproject /opt/lamp/apache2/myproject/public - - AllowOverride All - Require all granted - - -Restart Apache. - -Adding .htaccess ----------------- - -The last resort is to add **.htaccess** to the project root. - -It is not recommended that you place the project folder in the document root. However, if you have no other choice, like -on a shared server, you can use this. - -Place your project folder as follows, where **htdocs** is the Apache document root, and create the **.htaccess** file:: - - └── htdocs/ - └── myproject/ (project folder) - ├── .htaccess - └── public/ - -And edit **.htaccess** as follows: - -.. code-block:: apache - - - RewriteEngine On - RewriteRule ^(.*)$ public/$1 [L] - - - - Require all denied - Satisfy All - - -And remove the redirect settings in **public/.htaccess**: - -.. code-block:: diff - - --- a/public/.htaccess - +++ b/public/.htaccess - @@ -16,16 +16,6 @@ Options -Indexes - # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase - # RewriteBase / - - - # Redirect Trailing Slashes... - - RewriteCond %{REQUEST_FILENAME} !-d - - RewriteCond %{REQUEST_URI} (.+)/$ - - RewriteRule ^ %1 [L,R=301] - - - - # Rewrite "www.example.com -> example.com" - - RewriteCond %{HTTPS} !=on - - RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] - - RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] - - - # Checks to see if the user is attempting to access a valid file, - # such as an image or css document, if this isn't true it sends the - # request to the front controller, index.php - -Hosting with mod_userdir (Shared Hosts) -======================================= - -A common practice in shared hosting environments is to use the Apache module "mod_userdir" to enable per-user Virtual -Hosts automatically. Additional configuration is required to allow CodeIgniter4 to be run from these per-user -directories. - -The following assumes that the server is already configured for mod_userdir. A guide to enabling this module is -available `in the Apache documentation `_. - -Because CodeIgniter4 expects the server to find the framework front controller at **public/index.php** by default, you -must specify this location as an alternative to search for the request (even if CodeIgniter4 is installed within the -per-user web directory). - -The default user web directory **~/public_html** is specified by the ``UserDir`` directive, typically in -**apache2/mods-available/userdir.conf** or **apache2/conf/extra/httpd-userdir.conf**: - -.. code-block:: apache - - UserDir public_html - -So you will need to configure Apache to look for CodeIgniter's public directory first before trying to serve the -default: - -.. code-block:: apache - - UserDir "public_html/public" "public_html" - -Be sure to specify options and permissions for the CodeIgniter public directory as well. A **userdir.conf** might look -like: - -.. code-block:: apache - - - UserDir "public_html/public" "public_html" - UserDir disabled root - - - AllowOverride All - Options MultiViews Indexes FollowSymLinks - - # Apache <= 2.2: - # Order allow,deny - # Allow from all - - # Apache >= 2.4: - Require all granted - - - # Apache <= 2.2: - # Order deny,allow - # Deny from all - - # Apache >= 2.4: - Require all denied - - - - - AllowOverride All - Options MultiViews Indexes FollowSymLinks - - # Apache <= 2.2: - # Order allow,deny - # Allow from all - - # Apache >= 2.4: - Require all granted - - - # Apache <= 2.2: - # Order deny,allow - # Deny from all - - # Apache >= 2.4: - Require all denied - - - - -Removing the index.php -====================== - -See :ref:`CodeIgniter URLs `. - -Setting Environment -=================== - -See :ref:`Handling Multiple Environments `. - -****************** -Hosting with nginx -****************** - -nginx is the second most widely used HTTP server for web hosting. Here you can find an example configuration using PHP -8.2 FPM (unix sockets) under Ubuntu Server. - -default.conf -============ - -This configuration enables URLs without "**index.php**" in them and uses CodeIgniter's "404 - File Not Found" for URLs -ending with ".php". - -.. code-block:: nginx - - server { - listen 80; - listen [::]:80; - - server_name example.com; - - root /var/www/example.com/public; - index index.php index.html index.htm; - - location / { - try_files $uri $uri/ /index.php$is_args$args; - } - - location ~ \.php$ { - include snippets/fastcgi-php.conf; - - # With php-fpm: - fastcgi_pass unix:/run/php/php8.2-fpm.sock; - # With php-cgi: - # fastcgi_pass 127.0.0.1:9000; - } - - error_page 404 /index.php; - - # deny access to hidden files such as .htaccess - location ~ /\. { - deny all; - } - } - -Setting Environment -=================== - -See :ref:`Handling Multiple Environments `. - -************************************* -Deployment to Shared Hosting Services -************************************* - -See :ref:`Deployment `. - -********************* -Bootstrapping the App -********************* - -In some scenarios, you will want to load the framework without actually running the whole application. This is -particularly useful for unit testing your project, but may also be handy for using third-party tools to analyze and -modify your code. The framework comes with two separate bootstrap scripts specifically for these scenarios: - -- **system/Test/bootstrap.php**: This script is used primarily for unit testing. -- **system/util_bootstrap.php**: This script is used for other scripts that need access to the framework. It is - recommended for use in scripts that are not part of testing, as this will NOT fail gracefully if an exception is - thrown. - -Most of the paths to your project are defined during the bootstrap process. You may use pre-defined constants to -override these, but when using the defaults be sure that your paths align with the expected directory structure for your -installation method. diff --git a/user_guide_src/source/installation/troubleshooting.rst b/user_guide_src/source/installation/troubleshooting.rst deleted file mode 100644 index efa5ac01036f..000000000000 --- a/user_guide_src/source/installation/troubleshooting.rst +++ /dev/null @@ -1,98 +0,0 @@ -############### -Troubleshooting -############### - -Here are some common installation problems, and suggested workarounds. - -.. contents:: - :local: - :depth: 2 - -How do I know if my install is working? ---------------------------------------- - -From the command line, at your project root: - -.. code-block:: console - - php spark serve - -``http://localhost:8080`` in your browser should then show the default welcome page: - -|CodeIgniter4 Welcome| - -I have to include index.php in my URL -------------------------------------- - -If a URL like ``/mypage/find/apple`` doesn't work, but the similar URL ``/index.php/mypage/find/apple`` does, that -sounds like your **.htaccess** rules (for Apache) are not set up properly, or the ``mod_rewrite`` extension in Apache's -**httpd.conf** is commented out. See :ref:`urls-remove-index-php`. - -Only the default page loads ---------------------------- - -If you find that no matter what you put in your URL, only your default page is loading, it might be that your server -does not support the REQUEST_URI variable needed to serve search-engine friendly URLs. As a first step, open your -**app/Config/App.php** file and look for the URI Protocol information. It will recommend that you try a couple of -alternate settings. If it still doesn't work after you've tried this, you'll need to force CodeIgniter to add a question -mark (``?``) to your URLs. To do this, open your **app/Config/App.php** file and change this: - -.. literalinclude:: troubleshooting/001.php - -To this: - -.. literalinclude:: troubleshooting/002.php - -No input file specified ------------------------ - -If you see "No input file specified", try changing the rewrite rule like the following (to add ``?`` after -``index.php``): - -.. code-block:: apache - - RewriteRule ^([\s\S]*)$ index.php?/$1 [L,NC,QSA] - -My app works fine locally but not on the production server ----------------------------------------------------------- - -Make sure that the case of the folder and file names matches the code. - -Many developers develop on case-insensitive file systems on Windows or macOS. However, most server environments use -case-sensitive file systems. - -For example, when you have **app/Controllers/Product.php**, you must use ``Product`` as the short classname, not -``product``. - -If the file name case is incorrect, the file is not found on the server. - -The tutorial gives 404 errors everywhere :( -------------------------------------------- - -You can't follow the tutorial using PHP's built-in web server. It doesn't process the **.htaccess** file needed to route -requests properly. - -The solution: use Apache to serve your site, or else the built-in CodeIgniter equivalent, ``php spark serve`` from your -project root. - -.. |CodeIgniter4 Welcome| image:: ../images/welcome.png - -What's with an unhelpful "Whoops!" page? ----------------------------------------- - -You find that your app is displaying a page with "Whoops!" and then the text line "We seem to have hit a snag. Please -try again later...". - -That is a sign that you are in production mode and have hit an unrecoverable error, which we don't want to show to the -viewer of the webapp, for better security. - -You can see the error in the log file. See `CodeIgniter Error Logs`_ below. - -If you reach this page while developing, you should change your environment to "development" (in **.env**). See -:ref:`setting-development-mode` for more details. After that, reload the page. You will see the error and the back -trace. - -CodeIgniter Error Logs ----------------------- - -See :ref:`codeigniter-error-logs`. diff --git a/user_guide_src/source/installation/troubleshooting/001.php b/user_guide_src/source/installation/troubleshooting/001.php deleted file mode 100644 index 953d7b86bb82..000000000000 --- a/user_guide_src/source/installation/troubleshooting/001.php +++ /dev/null @@ -1,14 +0,0 @@ -` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -CodeIgniter 4.0.4 fixes a bug in the implementation of :doc:`Controller Filters `, breaking code -implementing the ``FilterInterface``. - -Breaking Changes -**************** - -Update FilterInterface Declarations -=================================== - -The method signatures for ``after()`` and ``before()`` must be updated to include ``$arguments``. The function -definitions should be changed from:: - - public function before(RequestInterface $request) - public function after(RequestInterface $request, ResponseInterface $response) - -to:: - - public function before(RequestInterface $request, $arguments = null) - public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) diff --git a/user_guide_src/source/installation/upgrade_405.rst b/user_guide_src/source/installation/upgrade_405.rst deleted file mode 100644 index 85a553afe75f..000000000000 --- a/user_guide_src/source/installation/upgrade_405.rst +++ /dev/null @@ -1,167 +0,0 @@ -############################# -Upgrading from 4.0.4 to 4.0.5 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Enhancements -********************* - -Cookie SameSite Support -======================= - -CodeIgniter 4.0.5 introduces a setting for the cookie SameSite attribute. Prior versions did not set this attribute at -all. The default setting for cookies is now ``Lax``. This will affect how cookies are handled in cross-domain contexts -and you may need to adjust this setting in your projects. Separate settings in **app/Config/App.php** exist for Response -cookies and for CSRF cookies. - -For additional information, see -`MDN Web Docs `_. The SameSite -specifications are described in `RFC 6265 `_ and the -`RFC 6265bis revision `_. - -Message::getHeader(s) -===================== - -The HTTP layer is moving towards `PSR-7 compliance `_. Towards this end, -``Message::getHeader()`` and ``Message::getHeaders()`` are deprecated and should be replaced with ``Message::header()`` -and ``Message::headers()`` respectively. Note that this pertains to all classes that extend ``Message`` as well: -``Request``, ``Response`` and their subclasses. - -Additional related deprecations from the HTTP layer: - -* ``Message::isJSON()``: Check the "Content-Type" header directly -* ``Request[Interface]::isValidIP()``: Use the Validation class with ``valid_ip`` -* ``Request[Interface]::getMethod()``: The ``$upper`` parameter will be removed. Use ``strtoupper()`` -* ``Request[Trait]::$ipAddress``: This property will become private -* ``Request::$proxyIPs``: This property will be removed; access ``config('App')->proxyIPs`` directly -* ``Request::__construct()``: The constructor will no longer take ``Config\App`` and has been made nullable to aid - transition -* ``Response[Interface]::getReason()``: Use ``getReasonPhrase()`` instead -* ``Response[Interface]::getStatusCode()``: The explicit ``int`` return type will be removed (no action required) - -ResponseInterface -================= - -This interface intends to include the necessary methods for any framework-compatible response class. A number of methods -expected by the framework were missing and have now been added. If you use any classes that implement -``ResponseInterface`` directly, they will need to be compatible with the updated requirements. These methods are as -follows: - -* ``setLastModified($date)`` -* ``setLink(PagerInterface $pager)`` -* ``setJSON($body, bool $unencoded = false)`` -* ``getJSON()`` -* ``setXML($body)`` -* ``getXML()`` -* ``send()`` -* ``sendHeaders()`` -* ``sendBody()`` -* ``setCookie($name, $value = '', $expire = '', $domain = '', $path = '/', $prefix = '', $secure = false, $httponly = false, $samesite = null)`` -* ``hasCookie(string $name, string $value = null, string $prefix = ''): bool`` -* ``getCookie(string $name = null, string $prefix = '')`` -* ``deleteCookie(string $name = '', string $domain = '', string $path = '/', string $prefix = '')`` -* ``getCookies()`` -* ``redirect(string $uri, string $method = 'auto', int $code = null)`` -* ``download(string $filename = '', $data = '', bool $setMime = false)`` - -To facilitate use of this interface, these methods have been moved from the framework's ``Response`` into a -``ResponseTrait`` which you may use, and ``DownloadResponse`` now extends ``Response`` directly to ensure maximum -compatibility. - -Config\\Services -================ - -Service discovery has been updated to allow third-party services (when enabled via Modules) to take precedence over core -services. Update **app/Config/Services.php** so the class extends ``CodeIgniter\Config\BaseService`` to allow proper -discovery of third-party services. - -Project Files -************* - -Numerous files in the project space (root, app, public, writable) received updates. Due to these files being outside of -the system scope, they will not be changed without your intervention. There are some third-party CodeIgniter modules -available to assist with merging changes to the project space: -`Explore on Packagist `_. - -.. note:: Except in very rare cases for bug fixes, no changes made to files for the project space will break your - application. All changes noted here are optional until the next major version, and any mandatory changes will be - covered in the sections above. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -* ``app/Views/*`` -* ``public/index.php`` -* ``public/.htaccess`` -* ``spark`` -* ``phpunit.xml.dist`` -* ``composer.json`` - -All Changes -=========== - -This is a list of all files in the project space that received changes; many will be simple comments or formatting that -have no effect on the runtime: - -* ``LICENSE`` -* ``README.md`` -* ``app/Config/App.php`` -* ``app/Config/Autoload.php`` -* ``app/Config/Boot/development.php`` -* ``app/Config/Boot/production.php`` -* ``app/Config/Boot/testing.php`` -* ``app/Config/Cache.php`` -* ``app/Config/Constants.php`` -* ``app/Config/ContentSecurityPolicy.php`` -* ``app/Config/Database.php`` -* ``app/Config/DocTypes.php`` -* ``app/Config/Email.php`` -* ``app/Config/Encryption.php`` -* ``app/Config/Events.php`` -* ``app/Config/Exceptions.php`` -* ``app/Config/Filters.php`` -* ``app/Config/ForeignCharacters.php`` -* ``app/Config/Format.php`` -* ``app/Config/Generators.php`` -* ``app/Config/Honeypot.php`` -* ``app/Config/Images.php`` -* ``app/Config/Kint.php`` -* ``app/Config/Logger.php`` -* ``app/Config/Migrations.php`` -* ``app/Config/Mimes.php`` -* ``app/Config/Modules.php`` -* ``app/Config/Pager.php`` -* ``app/Config/Paths.php`` -* ``app/Config/Routes.php`` -* ``app/Config/Security.php`` -* ``app/Config/Services.php`` -* ``app/Config/Toolbar.php`` -* ``app/Config/UserAgents.php`` -* ``app/Config/Validation.php`` -* ``app/Config/View.php`` -* ``app/Controllers/BaseController.php`` -* ``app/Controllers/Home.php`` -* ``app/Views/errors/cli/error_404.php`` -* ``app/Views/errors/cli/error_exception.php`` -* ``app/Views/errors/html/debug.css`` -* ``app/Views/errors/html/debug.js`` -* ``app/Views/errors/html/error_exception.php`` -* ``composer.json`` -* ``env`` -* ``license.txt`` -* ``phpunit.xml.dist`` -* ``public/.htaccess`` -* ``public/index.php`` -* ``spark`` diff --git a/user_guide_src/source/installation/upgrade_410.rst b/user_guide_src/source/installation/upgrade_410.rst deleted file mode 100644 index 747b7e73e7fe..000000000000 --- a/user_guide_src/source/installation/upgrade_410.rst +++ /dev/null @@ -1,22 +0,0 @@ -###################################### -Upgrading from 4.0.5 to 4.1.0 or 4.1.1 -###################################### - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -Legacy Autoloading -================== - -The ``Autoloader::loadLegacy()`` method was originally for the transition to CodeIgniter v4. Since v4.1.0, this support -was removed. All classes must be namespaced. diff --git a/user_guide_src/source/installation/upgrade_412.rst b/user_guide_src/source/installation/upgrade_412.rst deleted file mode 100644 index 10d9242208ba..000000000000 --- a/user_guide_src/source/installation/upgrade_412.rst +++ /dev/null @@ -1,145 +0,0 @@ -############################# -Upgrading from 4.1.1 to 4.1.2 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -current_url() and indexPage -=========================== - -Due to `a bug `_ in ``current_url()``, the resulting URIs -could be incorrect for a project's configuration, most importantly: ``indexPage`` would *not* be included. Projects -using ``App::$indexPage`` should expect altered values from ``current_url()`` and all its dependencies (including -Response Testing, Pager, Form Helper, and View Parser). Update your projects accordingly. - -Cache Keys -========== - -Cache handlers had wildly different compatibility for keys. The updated cache drivers now pass all keys through -validation, roughly matching PSR-6's recommendations: - - A string of at least one character that uniquely identifies a cached item. Implementing libraries MUST support keys - consisting of the characters A-Z, a-z, 0-9, _, and . in any order in UTF-8 encoding and a length of up to 64 - characters. Implementing libraries MAY support additional characters and encodings or longer lengths, but must - support at least that minimum. Libraries are responsible for their own escaping of key strings as appropriate, but - MUST be able to return the original unmodified key string. The following characters are reserved for future - extensions and MUST NOT be supported by implementing libraries: ``{}()/\@:`` - -Update your projects to remove any invalid cache keys. - -BaseConnection::query() Return Values -===================================== - -The ``BaseConnection::query()`` method in prior versions was incorrectly returning BaseResult objects even if the query -failed. This method will now return ``false`` for failed queries (or throw an Exception if ``DBDebug`` is ``true``) and -will return booleans for write-type queries. Review any use of the ``query()`` method and assess whether the value might -be boolean instead of a Result object. For a better idea of what queries are write-type queries, check -``BaseConnection::isWriteType()`` and any DBMS-specific override ``isWriteType()`` in the relevant Connection class. - -Breaking Enhancements -********************* - -ConnectionInterface::isWriteType() Declaration Added -==================================================== - -If you have written any classes that implement ConnectionInterface, these must now implement the ``isWriteType()`` -method, declared as ``public function isWriteType($sql): bool``. If your class extends BaseConnection, then that class -will provide a basic ``isWriteType()`` method which you might want to override. - -Test Traits -=========== - -The ``CodeIgniter\Test`` namespace has had significant improvements to help developers with their own test cases. Most -notably, test extensions have moved to Traits to make them easier to pick-and-choose across various test case needs. The -``CIDatabaseTestCase`` and ``FeatureTestCase`` classes have been deprecated and their methods moved to -``DatabaseTestTrait`` and ``FeatureTestTrait`` respectively. Update your test cases to extend the main test case and use -any traits you need. For example: - -.. literalinclude:: upgrade_412/001.php - -... becomes: - -.. literalinclude:: upgrade_412/002.php - -Finally, ``ControllerTester`` has been superseded by ``ControllerTestTrait`` to standardize the approach and take -advantage of the updated response testing (below). - -Test Responses -============== - -The tools for testing responses have been consolidated and improved. A new ``TestResponse`` replaces -``ControllerResponse`` and ``FeatureResponse`` with a complete set of methods and properties expected from both those -classes. In most cases, these changes will be handled "behind the scenes" by ``ControllerTestTrait`` and -``FeatureTestCase``, but there are two changes to be aware of: - -* ``TestResponse``'s ``$request`` and ``$response`` properties are protected and should only be accessed through their - getter methods, ``request()`` and ``response()`` -* ``TestResponse`` does not have ``getBody()`` and ``setBody()`` methods, but rather uses the Response methods directly, - e.g.: ``$body = $result->response()->getBody();`` - -Project Files -************* - -Numerous files in the project space (root, app, public, writable) received updates. Due to these files being outside of -the system scope, they will not be changed without your intervention. There are some third-party CodeIgniter modules -available to assist with merging changes to the project space: -`Explore on Packagist `_. - -.. note:: Except in very rare cases for bug fixes, no changes made to files for the project space will break your - application. All changes noted here are optional until the next major version, and any mandatory changes will be - covered in the sections above. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -* ``app/Config/App.php`` -* ``app/Config/Autoload.php`` -* ``app/Config/Cookie.php`` -* ``app/Config/Events.php`` -* ``app/Config/Exceptions.php`` -* ``app/Config/Security.php`` -* ``app/Views/errors/html/*`` -* ``env`` -* ``spark`` - -All Changes -=========== - -This is a list of all files in the project space that received changes; many will be simple comments or formatting that -have no effect on the runtime: - -* ``app/Config/App.php`` -* ``app/Config/Autoload.php`` -* ``app/Config/ContentSecurityPolicy.php`` -* ``app/Config/Cookie.php`` -* ``app/Config/Events.php`` -* ``app/Config/Exceptions.php`` -* ``app/Config/Logger.php`` -* ``app/Config/Mimes.php`` -* ``app/Config/Modules.php`` -* ``app/Config/Security.php`` -* ``app/Controllers/BaseController.php`` -* ``app/Views/errors/html/debug.css`` -* ``app/Views/errors/html/error_404.php`` -* ``app/Views/errors/html/error_exception.php`` -* ``app/Views/welcome_message.php`` -* ``composer.json`` -* ``contributing/guidelines.rst`` -* ``env`` -* ``public/.htaccess`` -* ``public/index.php`` -* ``spark`` diff --git a/user_guide_src/source/installation/upgrade_412/001.php b/user_guide_src/source/installation/upgrade_412/001.php deleted file mode 100644 index 94fb395e8077..000000000000 --- a/user_guide_src/source/installation/upgrade_412/001.php +++ /dev/null @@ -1,11 +0,0 @@ -` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Enhancements -********************* - -Cache TTL -========= - -There is a new value in **app/Config/Cache.php**: ``$ttl``. This is not used by framework handlers where 60 seconds is -hard-coded, but may be useful to projects and modules. In a future release this value will replace the hard-coded -version, so either leave this as ``60`` or stop relying on the hard-coded version. - -Project Files -************* - -Only a few files in the project space (root, app, public, writable) received updates. Due to these files being outside -of the system scope, they will not be changed without your intervention. The following files received changes and it is -recommended that you merge the updated versions with your application: - -* ``app/Config/Cache.php`` -* ``spark`` diff --git a/user_guide_src/source/installation/upgrade_414.rst b/user_guide_src/source/installation/upgrade_414.rst deleted file mode 100644 index 1107ecce6347..000000000000 --- a/user_guide_src/source/installation/upgrade_414.rst +++ /dev/null @@ -1,56 +0,0 @@ -############################# -Upgrading from 4.1.3 to 4.1.4 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -This release focuses on code style. All changes (except those noted below) are cosmetic to bring the code in line with -the new `CodeIgniter Coding Standard `_ (based on PSR-12). - -Breaking Changes -**************** - -Method Scope -============ - -The following methods were changed from ``public`` to ``protected`` to match their parent class methods and better align -with their uses. If you relied on any of these methods being public (highly unlikely), adjust your code accordingly: - -* ``CodeIgniter\Database\MySQLi\Connection::execute()`` -* ``CodeIgniter\Database\MySQLi\Connection::_fieldData()`` -* ``CodeIgniter\Database\MySQLi\Connection::_indexData()`` -* ``CodeIgniter\Database\MySQLi\Connection::_foreignKeyData()`` -* ``CodeIgniter\Database\Postgre\Builder::_like_statement()`` -* ``CodeIgniter\Database\Postgre\Connection::execute()`` -* ``CodeIgniter\Database\Postgre\Connection::_fieldData()`` -* ``CodeIgniter\Database\Postgre\Connection::_indexData()`` -* ``CodeIgniter\Database\Postgre\Connection::_foreignKeyData()`` -* ``CodeIgniter\Database\SQLSRV\Connection::execute()`` -* ``CodeIgniter\Database\SQLSRV\Connection::_fieldData()`` -* ``CodeIgniter\Database\SQLSRV\Connection::_indexData()`` -* ``CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData()`` -* ``CodeIgniter\Database\SQLite3\Connection::execute()`` -* ``CodeIgniter\Database\SQLite3\Connection::_fieldData()`` -* ``CodeIgniter\Database\SQLite3\Connection::_indexData()`` -* ``CodeIgniter\Database\SQLite3\Connection::_foreignKeyData()`` -* ``CodeIgniter\Images\Handlers\GDHandler::_flatten()`` -* ``CodeIgniter\Images\Handlers\GDHandler::_flip()`` -* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten()`` -* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flip()`` -* ``CodeIgniter\Test\Mock\MockIncomingRequest::detectURI()`` -* ``CodeIgniter\Test\Mock\MockSecurity::sendCookie()`` - -Project Files -************* - -All files in the project space were reformatted with the new coding style. This will not affect existing code but you -may want to apply the updated coding style to your own projects to keep them in line with the framework's version of -these files. diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst deleted file mode 100644 index 82fe051ee575..000000000000 --- a/user_guide_src/source/installation/upgrade_415.rst +++ /dev/null @@ -1,163 +0,0 @@ -############################# -Upgrading from 4.1.4 to 4.1.5 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -================ - -Changes for set() method in BaseBuilder and Model class -------------------------------------------------------- - -The casting for the ``$value`` parameter has been removed to fix a bug where passing parameters as an array and as a -string to the ``set()`` method was handled differently. If you extended the ``BaseBuilder`` class or ``Model`` class -yourself and modified the ``set()`` method, then you need to change its definition from -``public function set($key, ?string $value = '', ?bool $escape = null)`` to -``public function set($key, $value = '', ?bool $escape = null)``. - -Session DatabaseHandler's Database Table Change ------------------------------------------------ - -The types of the following columns in the session table have been changed for optimization. - -- MySQL - - - ``timestamp`` - -- PostgreSQL - - - ``ip_address`` - - ``timestamp`` - - ``data`` - -Update the definition of the session table. See the :doc:`/libraries/sessions` for the new definition. - -The change was introduced in v4.1.2. But due to `a bug `_, the -DatabaseHandler Driver did not work properly. - -CSRF Protection ---------------- - -Because of a bug fix, CSRF protection now works on not only **POST** but also **PUT/PATCH/DELETE** requests when the -CSRF filter is applied. - -When you use **PUT/PATCH/DELETE** requests, you need to send the CSRF token. Or remove the CSRF filter for such requests -if you don't need CSRF protection for them. - -If you want the same behavior as the previous version, set the CSRF filter like the following in -**app/Config/Filters.php**: - -.. literalinclude:: upgrade_415/001.php - -Protecting the **GET** method is needed only when you use ``form_open()`` auto-generation of the CSRF field. - -.. warning:: In general, if you use ``$methods`` filters, you should - :ref:`disable Auto Routing (Legacy) ` because :ref:`auto-routing-legacy` permits any HTTP - method to access a controller. Accessing the controller with a method you don't expect could bypass the filter. - -CURLRequest Header Change -------------------------- - -In the previous version, if you didn't provide your own headers, ``CURLRequest`` would send the request-headers from the -browser. The bug was fixed. If your requests depend on the headers, your requests might fail after upgrading. In this -case, add the necessary headers manually. See :ref:`CURLRequest Class ` for how to -add them. - -Query Builder Changes ---------------------- - -For optimization and a bug fix, the following behaviors, mostly used in testing, have been changed. - -- When you use ``insertBatch()`` and ``updateBatch()``, the return value of ``$query->getOriginalQuery()`` has changed. - It no longer returns the query with the bound parameters, but the actual query that was run. -- If ``testMode`` is ``true``, ``insertBatch()`` will return an SQL string array instead of the number of affected rows. - This change was made so that the returned data type is the same as the ``updateBatch()`` method. - -Breaking Enhancements -===================== - -.. _upgrade-415-multiple-filters-for-a-route: - -Multiple Filters for a Route ----------------------------- - -A new feature has been added to set multiple filters for a route. - -.. important:: This feature is disabled by default because it breaks backward compatibility. - -If you want to use this, you need to set the property ``$multipleFilters`` to ``true`` in ``app/Config/Feature.php``. If -you enable it: - -- ``CodeIgniter\CodeIgniter::handleRequest()`` uses - - - ``CodeIgniter\Filters\Filters::enableFilters()``, instead of ``enableFilter()`` - -- ``CodeIgniter\CodeIgniter::tryToRouteIt()`` uses - - - ``CodeIgniter\Router\Router::getFilters()``, instead of ``getFilter()`` - -- ``CodeIgniter\Router\Router::handle()`` uses - - - the property ``$filtersInfo``, instead of ``$filterInfo`` - - ``CodeIgniter\Router\RouteCollection::getFiltersForRoute()``, instead of ``getFilterForRoute()`` - -If you extended the above classes, then you need to change them. - -The following methods and a property have been deprecated: - -- ``CodeIgniter\Filters\Filters::enableFilter()`` -- ``CodeIgniter\Router\Router::getFilter()`` -- ``CodeIgniter\Router\RouteCollection::getFilterForRoute()`` -- ``CodeIgniter\Router\RouteCollection``'s property ``$filterInfo`` - -See :ref:`applying-filters` for the functionality. - -Project Files -============= - -Numerous files in the project space (root, app, public, writable) received updates. Due to these files being outside of -the system scope, they will not be changed without your intervention. There are some third-party CodeIgniter modules -available to assist with merging changes to the project space: -`Explore on Packagist `_. - -.. note:: Except in very rare cases for bug fixes, no changes made to files for the project space will break your - application. All changes noted here are optional until the next major version, and any mandatory changes will be - covered in the sections above. - -Content Changes ---------------- - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -* ``app/Config/CURLRequest.php`` -* ``app/Config/Cache.php`` -* ``app/Config/Feature.php`` -* ``app/Config/Generators.php`` -* ``app/Config/Publisher.php`` -* ``app/Config/Security.php`` -* ``app/Views/welcome_message.php`` - -All Changes ------------ - -This is a list of all files in the project space that received changes; many will be simple comments or formatting that -have no effect on the runtime: - -* ``app/Config/CURLRequest.php`` -* ``app/Config/Cache.php`` -* ``app/Config/Feature.php`` -* ``app/Config/Generators.php`` -* ``app/Config/Kint.php`` -* ``app/Config/Publisher.php`` -* ``app/Config/Security.php`` -* ``app/Views/welcome_message.php`` diff --git a/user_guide_src/source/installation/upgrade_415/001.php b/user_guide_src/source/installation/upgrade_415/001.php deleted file mode 100644 index 272f9e2f1fab..000000000000 --- a/user_guide_src/source/installation/upgrade_415/001.php +++ /dev/null @@ -1,16 +0,0 @@ - ['csrf'], - 'POST' => ['csrf'], - ]; - // ... -} diff --git a/user_guide_src/source/installation/upgrade_416.rst b/user_guide_src/source/installation/upgrade_416.rst deleted file mode 100644 index 7acdeb9177a0..000000000000 --- a/user_guide_src/source/installation/upgrade_416.rst +++ /dev/null @@ -1,74 +0,0 @@ -############################# -Upgrading from 4.1.5 to 4.1.6 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -Validation Result Changes -========================= - -Due to a bug fix, Validation might now change the validation results when you validate an array item (see -:ref:`Changelog `). So check the validation results for all the code that validates -the array. Validating multiple fields like ``contacts.*.name`` is not affected. - -If you have the following form:: - - - - -And you have the validation rule like this:: - - 'invoice_rule' => ['rules' => 'numeric', 'errors' => ['numeric' => 'Not numeric']] - -Change the rule key to ``invoice_rule.*`` and the validation will work. - -Breaking Enhancements -********************* - -None. - -Project Files -************* - -Numerous files in the **project space** (root, app, public, writable) received updates. Due to these files being outside -of the **system** scope, they will not be changed without your intervention. There are some third-party CodeIgniter -modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -.. note:: Except in very rare cases for bug fixes, no changes made to files for the project space will break your - application. All changes noted here are optional until the next major version, and any mandatory changes will be - covered in the sections above. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -* ``app/Config/Filters.php`` -* ``app/Config/Mimes.php`` -* ``app/Config/Security.php`` -* ``app/Config/Toolbar.php`` - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* ``app/Config/Filters.php`` -* ``app/Config/Mimes.php`` -* ``app/Config/Security.php`` -* ``app/Config/Toolbar.php`` -* ``app/Views/errors/html/error_exception.php`` diff --git a/user_guide_src/source/installation/upgrade_417.rst b/user_guide_src/source/installation/upgrade_417.rst deleted file mode 100644 index 39736332df07..000000000000 --- a/user_guide_src/source/installation/upgrade_417.rst +++ /dev/null @@ -1,21 +0,0 @@ -############################# -Upgrading from 4.1.6 to 4.1.7 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -- The output of ``get_cookie()`` when ``$xssClean`` is true has changed. Now it uses - ``FILTER_SANITIZE_FULL_SPECIAL_CHARS``, not ``FILTER_SANITIZE_STRING``. Make sure the change is acceptable. Note that - using XSS filtering is a bad practice. It does not prevent XSS attacks perfectly. Using ``esc()`` with the correct - ``$context`` in the views is recommended. diff --git a/user_guide_src/source/installation/upgrade_418.rst b/user_guide_src/source/installation/upgrade_418.rst deleted file mode 100644 index c187ee5cd527..000000000000 --- a/user_guide_src/source/installation/upgrade_418.rst +++ /dev/null @@ -1,20 +0,0 @@ -############################# -Upgrading from 4.1.7 to 4.1.8 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -- Due to a security issue in the ``API\ResponseTrait``, all trait methods are now scoped to ``protected``. See the - `Security advisory GHSA-7528-7jg5-6g62 `_ - for more information. diff --git a/user_guide_src/source/installation/upgrade_420.rst b/user_guide_src/source/installation/upgrade_420.rst deleted file mode 100644 index 22ffb8161546..000000000000 --- a/user_guide_src/source/installation/upgrade_420.rst +++ /dev/null @@ -1,137 +0,0 @@ -############################# -Upgrading from 4.1.9 to 4.2.0 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Mandatory File Changes -********************** - -index.php and spark -=================== - -The following files received significant changes and **you must merge the updated versions** with your application: - -* ``public/index.php`` -* ``spark`` - -.. important:: If you don't update the above two files, CodeIgniter will not work at all after running - ``composer update``. - - The upgrade procedure, for example, is as follows: - - .. code-block:: console - - composer update - cp vendor/codeigniter4/framework/public/index.php public/index.php - cp vendor/codeigniter4/framework/spark . - -Config/Constants.php -==================== - -The constants ``EVENT_PRIORITY_LOW``, ``EVENT_PRIORITY_NORMAL`` and ``EVENT_PRIORITY_HIGH`` are deprecated, and the -definitions are moved to ``app/Config/Constants.php``. If you use these constants, define them in -``app/Config/Constants.php``. Or use the new class constants ``CodeIgniter\Events\Events::PRIORITY_LOW``, -``CodeIgniter\Events\Events::PRIORITY_NORMAL`` and ``CodeIgniter\Events\Events::PRIORITY_HIGH``. - -composer.json -============= - -.. note:: This procedure is not required in v4.5.0 or later. - -If you use Composer, installed CodeIgniter v4.1.9 or earlier, and there are ``App\\`` and ``Config\\`` namespaces in -your ``/composer.json``'s ``autoload.psr-4`` like the following, you need to remove these lines, and run -``composer dump-autoload``. - -.. code-block:: text - - { - ... - "autoload": { - "psr-4": { - "App\\": "app", <-- Remove this line - "Config\\": "app/Config" <-- Remove this line - } - }, - ... - } - -Breaking Changes -**************** - -- The ``system/bootstrap.php`` file no longer returns a ``CodeIgniter`` instance, and does not load the ``.env`` file - (now handled in ``index.php`` and ``spark``). If you have code that expects these behaviors, it will no longer work - and must be modified. This has been changed to make - `Preloading `_ easier to implement. - -Breaking Enhancements -********************* - -- The method signature of ``Validation::setRule()`` has been changed. The ``string`` typehint on the ``$rules`` - parameter was removed. Extending classes should likewise remove the typehint so as not to break LSP. -- The method signatures of ``CodeIgniter\Database\BaseBuilder::join()`` and ``CodeIgniter\Database\*\Builder::join()`` - have been changed. The ``string`` typehint on the ``$cond`` parameter was removed. Extending classes should likewise - remove the typehint so as not to break LSP. - -Project Files -************* - -Numerous files in the **project space** (root, app, public, writable) received updates. Due to these files being outside -of the **system** scope, they will not be changed without your intervention. There are some third-party CodeIgniter -modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -.. note:: Except in very rare cases for bug fixes, no changes made to files for the project space will break your - application. All changes noted here are optional until the next major version, and any mandatory changes will be - covered in the sections above. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -* ``app/Config/Routes.php`` - - * To make the default configuration more secure, auto-routing has been changed to disabled by default. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* **app/Config/App.php** -* **app/Config/Constants.php** -* **app/Config/ContentSecurityPolicy.php** -* **app/Config/Database.php** -* **app/Config/Events.php** -* **app/Config/Feature.php** -* **app/Config/Filters.php** -* **app/Config/Format.php** -* **app/Config/Logger.php** -* **app/Config/Mimes.php** -* **app/Config/Publisher.php** -* **app/Config/Routes.php** -* **app/Config/Security.php** -* **app/Config/Validation.php** -* **app/Config/View.php** -* **app/Controllers/BaseController.php** -* **app/Views/errors/html/debug.css** -* **app/Views/errors/html/debug.js** -* **app/Views/errors/html/error_404.php** -* **app/Views/errors/html/error_exception.php** -* **app/Views/errors/html/production.php** -* **app/Views/welcome_message.php** -* **app/index.html** -* **preload.php** -* **public/index.php** -* spark diff --git a/user_guide_src/source/installation/upgrade_421.rst b/user_guide_src/source/installation/upgrade_421.rst deleted file mode 100644 index b9a132204500..000000000000 --- a/user_guide_src/source/installation/upgrade_421.rst +++ /dev/null @@ -1,90 +0,0 @@ -############################# -Upgrading from 4.2.0 to 4.2.1 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Mandatory File Changes -********************** - -app/Config/Mimes.php -==================== - -- The mapping of file extensions to MIME types in **app/Config/Mimes.php** was updated to fix a bug. Also, the logic of - ``Mimes::getExtensionFromType()`` was changed. - -Breaking Changes -**************** - -.. _upgrade-421-get_cookie: - -get_cookie() -============ - -If there is a cookie with a prefixed name and a cookie with the same name without a prefix, the previous -``get_cookie()`` had the tricky behavior of returning the cookie without the prefix. - -For example, when ``Config\Cookie::$prefix`` is ``prefix_`` and there are two cookies, ``test`` and ``prefix_test``: - -.. code-block:: php - - $_COOKIES = [ - 'test' => 'Non CI Cookie', - 'prefix_test' => 'CI Cookie', - ]; - -Previously, ``get_cookie()`` returned the following: - -.. code-block:: php - - get_cookie('test'); // returns "Non CI Cookie" - get_cookie('prefix_test'); // returns "CI Cookie" - -Now this bug has been fixed, and the behavior has changed as follows: - -.. code-block:: php - - get_cookie('test'); // returns "CI Cookie" - get_cookie('prefix_test'); // returns null - get_cookie('test', false, null); // returns "Non CI Cookie" - -If you depend on the previous behavior, you need to change your code. - -.. note:: In the example above, if there is only one cookie ``prefix_test``, the previous ``get_cookie('test')`` also - returned ``"CI Cookie"``. - -Breaking Enhancements -********************* - - -Project Files -************* - -Numerous files in the **project space** (root, app, public, writable) received updates. Due to these files being outside -of the **system** scope, they will not be changed without your intervention. There are some third-party CodeIgniter -modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -.. note:: Except in very rare cases for bug fixes, no changes made to files for the project space will break your - application. All changes noted here are optional until the next major version, and any mandatory changes will be - covered in the sections above. - -Content Changes -=============== - - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* **app/Config/Mimes.php** diff --git a/user_guide_src/source/installation/upgrade_4210.rst b/user_guide_src/source/installation/upgrade_4210.rst deleted file mode 100644 index f1c06fb5356b..000000000000 --- a/user_guide_src/source/installation/upgrade_4210.rst +++ /dev/null @@ -1,26 +0,0 @@ -############################## -Upgrading from 4.2.9 to 4.2.10 -############################## - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Project Files -************* - -Version 4.2.10 did not alter any executable code in project files. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* **composer.json** diff --git a/user_guide_src/source/installation/upgrade_4211.rst b/user_guide_src/source/installation/upgrade_4211.rst deleted file mode 100644 index 814f20579f88..000000000000 --- a/user_guide_src/source/installation/upgrade_4211.rst +++ /dev/null @@ -1,70 +0,0 @@ -############################### -Upgrading from 4.2.10 to 4.2.11 -############################### - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -.. _upgrade-4211-proxyips: - -Config\\App::$proxyIPs -====================== - -The config value format has been changed. Now you must set your proxy IP address and the HTTP header name for the client -IP address pair as an array:: - - public $proxyIPs = [ - '10.0.1.200' => 'X-Forwarded-For', - '192.168.5.0/24' => 'X-Forwarded-For', - ]; - -``ConfigException`` will be thrown for a config value in the old format. - -.. _upgrade-4211-session-key: - -Session Handler Key Changes -=========================== - -The key of the session data record for :ref:`sessions-databasehandler-driver`, :ref:`sessions-memcachedhandler-driver` -and :ref:`sessions-redishandler-driver` has changed. Therefore, any existing session data will be invalidated after the -upgrade if you are using these session handlers. - -- When using ``DatabaseHandler``, the ``id`` column value in the session table now contains the session cookie name - (``Config\App::$sessionCookieName``). -- When using ``MemcachedHandler`` or ``RedisHandler``, the key value contains the session cookie name - (``Config\App::$sessionCookieName``). - -There is a maximum length for the ``id`` column and Memcached key (250 bytes). If the following values exceed those -maximum lengths, the session will not work properly. - -- the session cookie name, delimiter, and session id (32 characters by default) when using ``DatabaseHandler`` -- the prefix (``ci_session``), session cookie name, delimiters, and session id when using ``MemcachedHandler`` - -Project Files -************* - -Version 4.2.11 did not alter any executable code in project files. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* **app/Config/App.php** -* **app/Config/Autoload.php** -* **app/Config/Logger.php** -* **app/Config/Toolbar.php** -* **app/Views/welcome_message.php** -* **composer.json** -* **phpunit.xml.dist** diff --git a/user_guide_src/source/installation/upgrade_4212.rst b/user_guide_src/source/installation/upgrade_4212.rst deleted file mode 100644 index 217dc26ef9ad..000000000000 --- a/user_guide_src/source/installation/upgrade_4212.rst +++ /dev/null @@ -1,29 +0,0 @@ -############################### -Upgrading from 4.2.11 to 4.2.12 -############################### - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Project Files -************* - -Version 4.2.12 did not alter any executable code in project files. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* **app/Config/Cache.php** -* **app/Config/Migrations.php** -* **app/Controllers/BaseController.php** -* **composer.json** diff --git a/user_guide_src/source/installation/upgrade_422.rst b/user_guide_src/source/installation/upgrade_422.rst deleted file mode 100644 index ea2d4cf5e760..000000000000 --- a/user_guide_src/source/installation/upgrade_422.rst +++ /dev/null @@ -1,73 +0,0 @@ -############################# -Upgrading from 4.2.1 to 4.2.2 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -Web Page Caching Bug Fix -======================== - -- :doc:`../general/caching` now caches the Response data after :ref:`after-filters` are executed. -- For example, if you enable :ref:`secureheaders`, the Response headers are now sent when the page comes from the cache. - -.. important:: If you have written **code based on this bug** that assumes changes to the Response in "after" filters - are not cached then **sensitive information could be cached and compromised**. If this is the case, change your code - to disable caching of the page. - -Others -====== - -- The method ``Forge::createTable()`` no longer executes a ``CREATE TABLE IF NOT EXISTS``. When ``$ifNotExists`` is - true, if the table is not found in ``$db->tableExists($table)`` then ``CREATE TABLE`` is executed. -- The second parameter ``$ifNotExists`` of ``Forge::_createTable()`` is deprecated. It is no longer used and will be - removed in a future release. -- When you use :php:func:`random_string()` with the first parameter ``'crypto'``, if you set the second parameter - ``$len`` to an odd number, ``InvalidArgumentException`` will now be thrown. Change the parameter to an even number. - -Breaking Enhancements -********************* - - -Project Files -************* - -Numerous files in the **project space** (root, app, public, writable) received updates. Due to these files being outside -of the **system** scope, they will not be changed without your intervention. There are some third-party CodeIgniter -modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -.. note:: Except in very rare cases for bug fixes, no changes made to files for the project space will break your - application. All changes noted here are optional until the next major version, and any mandatory changes will be - covered in the sections above. - -Content Changes -=============== - -* **app/Views/errors/html/error_404.php** -* **app/Views/welcome_message.php** -* **public/index.php** -* spark - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* **app/Config/App.php** -* **app/Config/Constants.php** -* **app/Config/Logger.php** -* **app/Config/Paths.php** -* **app/Views/errors/html/error_404.php** -* **app/Views/welcome_message.php** diff --git a/user_guide_src/source/installation/upgrade_423.rst b/user_guide_src/source/installation/upgrade_423.rst deleted file mode 100644 index c1066abbd761..000000000000 --- a/user_guide_src/source/installation/upgrade_423.rst +++ /dev/null @@ -1,18 +0,0 @@ -############################# -Upgrading from 4.2.2 to 4.2.3 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Project Files -************* - -Version 4.2.3 is an internal change for security measures and requires no intervention in projects. diff --git a/user_guide_src/source/installation/upgrade_425.rst b/user_guide_src/source/installation/upgrade_425.rst deleted file mode 100644 index 02efbeb858b2..000000000000 --- a/user_guide_src/source/installation/upgrade_425.rst +++ /dev/null @@ -1,18 +0,0 @@ -############################# -Upgrading from 4.2.3 to 4.2.5 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Project Files -************* - -Version 4.2.5 did not alter any project files. diff --git a/user_guide_src/source/installation/upgrade_426.rst b/user_guide_src/source/installation/upgrade_426.rst deleted file mode 100644 index c7d11d34b850..000000000000 --- a/user_guide_src/source/installation/upgrade_426.rst +++ /dev/null @@ -1,32 +0,0 @@ -############################# -Upgrading from 4.2.5 to 4.2.6 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - - -Project Files -************* - -A few files in the **project space** (root, app, public, writable) received cosmetic updates. You need not touch these -files at all. There are some third-party CodeIgniter modules available to assist with merging changes to the project -space: `Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* **app/Config/App.php** -* **app/Config/ContentSecurityPolicy.php** -* **app/Config/Routes.php** -* **app/Config/Validation.php** diff --git a/user_guide_src/source/installation/upgrade_427.rst b/user_guide_src/source/installation/upgrade_427.rst deleted file mode 100644 index 215254d6cf5b..000000000000 --- a/user_guide_src/source/installation/upgrade_427.rst +++ /dev/null @@ -1,73 +0,0 @@ -############################# -Upgrading from 4.2.6 to 4.2.7 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -set_cookie() -============ - -Due to a bug, :php:func:`set_cookie()` and :php:meth:`CodeIgniter\\HTTP\\Response::setCookie()` in the previous versions -did not use the ``$secure`` and ``$httponly`` values in ``Config\Cookie``. The following code did not issue a cookie -with the secure flag even if you set ``$secure = true`` in ``Config\Cookie``:: - - helper('cookie'); - - $cookie = [ - 'name' => $name, - 'value' => $value, - ]; - set_cookie($cookie); - // or - $this->response->setCookie($cookie); - -But now the values in ``Config\Cookie`` are used for the options that are not specified. The above code issues a cookie -with the secure flag if you set ``$secure = true`` in ``Config\Cookie``. - -If your code depends on this bug, please change it to explicitly specify the necessary options:: - - $cookie = [ - 'name' => $name, - 'value' => $value, - 'secure' => false, // Set explicitly - 'httponly' => false, // Set explicitly - ]; - set_cookie($cookie); - // or - $this->response->setCookie($cookie); - -Others -====== - -- ``Time::__toString()`` is now locale-independent. It returns database-compatible strings like '2022-09-07 12:00:00' in - any locale. Most locales are not affected by this change. But in a few locales like ``ar``, ``fa``, - ``Time::__toString()`` (or ``(string) $time`` or implicit casting to a string) no longer returns a localized datetime - string. If you want to get a localized datetime string, use :ref:`Time::toDateTimeString() ` - instead. -- The logic of Validation rule ``required_without`` has been changed to validate each array item separately when - validating fields with asterisk (``*``), and the method signature of the rule method has also been changed. Extending - classes should likewise update the parameters so as not to break LSP. - -Project Files -************* - -Version 4.2.7 did not alter any executable code in project files. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* **app/Common.php** diff --git a/user_guide_src/source/installation/upgrade_428.rst b/user_guide_src/source/installation/upgrade_428.rst deleted file mode 100644 index d1f92962cdea..000000000000 --- a/user_guide_src/source/installation/upgrade_428.rst +++ /dev/null @@ -1,29 +0,0 @@ -############################# -Upgrading from 4.2.7 to 4.2.8 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Project Files -************* - -The following files had changes to code or behavior that merit updating in your projects: - -* **app/Views/errors/html/error_exception.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -* **app/Config/Logger.php** -* **app/Views/errors/html/error_exception.php** diff --git a/user_guide_src/source/installation/upgrade_430.rst b/user_guide_src/source/installation/upgrade_430.rst deleted file mode 100644 index 0b6efe5708e1..000000000000 --- a/user_guide_src/source/installation/upgrade_430.rst +++ /dev/null @@ -1,445 +0,0 @@ -############################## -Upgrading from 4.2.12 to 4.3.0 -############################## - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Composer Version -**************** - -.. important:: If you use Composer, CodeIgniter v4.3.0 requires Composer 2.0.14 or later. - -If you are using an older version of Composer, upgrade your ``composer`` tool, and delete the **vendor/** directory, and -run ``composer update`` again. - -The procedure, for example, is as follows: - -.. code-block:: console - - composer self-update - rm -rf vendor/ - composer update - -Mandatory File Changes -********************** - -spark -===== - -The following files received significant changes and **you must merge the updated versions** with your application: - -- ``spark`` - -.. important:: If you do not update this file, Spark commands will not work at all after running ``composer update``. - - The upgrade procedure, for example, is as follows: - - .. code-block:: console - - composer update - cp vendor/codeigniter4/framework/spark . - -Config Files -============ - -app/Config/Kint.php -------------------- - -- **app/Config/Kint.php** has been updated for Kint 5.0. -- You need to replace: - - - ``Kint\Renderer\Renderer`` with ``Kint\Renderer\AbstractRenderer`` - - ``Renderer::SORT_FULL`` with ``AbstractRenderer::SORT_FULL`` - -app/Config/Exceptions.php -------------------------- - -- If you are using PHP 8.2, you need to add new properties ``$logDeprecations`` and ``$deprecationLogLevel``. - -Mock Config Classes -------------------- - -- If you are using the following Mock Config classes in testing, you need to update the corresponding Config files in - **app/Config**: - - - ``MockAppConfig`` (``Config\App``) - - ``MockCLIConfig`` (``Config\App``) - - ``MockSecurityConfig`` (``Config\Security``) - -- Add **types** to the properties in these Config classes. You may need to fix the property values to match the property - types. - -composer.json -============= - -If you installed CodeIgniter manually, and are using Composer, you need to remove the following lines, and run -``composer update``. - -.. code-block:: text - - { - ... - "require": { - ... - "kint-php/kint": "^4.2", <-- Remove this line - ... - }, - ... - "scripts": { - "post-update-cmd": [ - "CodeIgniter\\ComposerScripts::postUpdate" <-- Remove this line - ], - "test": "phpunit" - }, - ... - } - -Breaking Changes -**************** - -Database Exception Changes -========================== - -- The exception classes may be changed when database errors occur. If you catch the exceptions, you must confirm that - your code can catch the exceptions. -- Now a few exceptions will be thrown even if ``CI_DEBUG`` is false. -- During transactions, exceptions are not thrown by default even if ``DBDebug`` is true. If you want exceptions to be - thrown, you need to call ``transException(true)``. See :ref:`transactions-throwing-exceptions`. -- See :ref:`exceptions-when-database-errors-occur` for details. - -HTTP Status Code and Exit Code of Uncaught Exceptions -===================================================== - -- If you expect *Exception code* as *HTTP status code*, the HTTP status code will be changed. In that case, you need to - implement ``HTTPExceptionInterface`` in the Exception. See :ref:`error-specify-http-status-code`. -- If you expect *Exit code* based on *Exception code*, the Exit code will be changed. In that case, you need to - implement ``HasExitCodeInterface`` in the Exception. See :ref:`error-specify-exit-code`. - -redirect()->withInput() and Validation Errors -============================================= - -``redirect()->withInput()`` and Validation errors had an undocumented behavior. If you redirect with ``withInput()``, -CodeIgniter stores the validation errors in the session, and you can get the errors in the redirected page from a -validation object *before a new validation is run*:: - - // In the controller - if (! $this->validate($rules)) { - return redirect()->back()->withInput(); - } - - // In the view of the redirected page - listErrors() ?> - -This behavior was a bug and was fixed in v4.3.0. - -If you have code that depends on the bug, you need to change the code. Use the new Form helpers, -:php:func:`validation_errors()`, :php:func:`validation_list_errors()` and :php:func:`validation_show_error()` to display -Validation Errors, instead of the Validation object. - -Validation Changes -================== - -- ``ValidationInterface`` has been changed. Implementing classes should likewise add the methods and the parameters so - as not to break LSP. See :ref:`v430-validation-changes` for details. -- The return value of ``Validation::loadRuleGroup()`` has been changed from ``null`` to ``[]`` when the ``$group`` is - empty. Update the code if you depend on the behavior. - -Time Fixes -========== - -- Due to bug fixes, some methods in :doc:`Time <../libraries/time>` have changed from mutable behavior to immutable; - ``Time`` now extends ``DateTimeImmutable``. See :ref:`ChangeLog ` for details. -- If you need the behavior of ``Time`` before the modification, a compatible ``TimeLegacy`` class has been added. Please - replace all ``Time`` with ``TimeLegacy`` in your application code. -- But ``TimeLegacy`` is deprecated. So we recommend you update your code. - -E.g.:: - - // Before - $time = Time::now(); - // ... - if ($time instanceof DateTime) { - // ... - } - - // After - $time = Time::now(); - // ... - if ($time instanceof DateTimeInterface) { - // ... - } - -:: - - // Before - $time1 = new Time('2022-10-31 12:00'); - $time2 = $time1->modify('+1 day'); - echo $time1; // 2022-11-01 12:00:00 - echo $time2; // 2022-11-01 12:00:00 - - // After - $time1 = new Time('2022-10-31 12:00'); - $time2 = $time1->modify('+1 day'); - echo $time1; // 2022-10-31 12:00:00 - echo $time2; // 2022-11-01 12:00:00 - -.. _upgrade-430-stream-filter: - -Capturing STDERR and STDOUT streams in Tests -============================================ - -The way error and output streams are captured has changed. Now instead of:: - - use CodeIgniter\Test\Filters\CITestStreamFilter; - - protected function setUp(): void - { - CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - } - -you need to use:: - - use CodeIgniter\Test\Filters\CITestStreamFilter; - - protected function setUp(): void - { - CITestStreamFilter::registration(); - CITestStreamFilter::addOutputFilter(); - CITestStreamFilter::addErrorFilter(); - } - - protected function tearDown(): void - { - CITestStreamFilter::removeOutputFilter(); - CITestStreamFilter::removeErrorFilter(); - } - -Or use the trait ``CodeIgniter\Test\StreamFilterTrait``. See :ref:`testing-cli-output`. - -Interface Changes -================= - -Some interfaces have been fixed. See :ref:`v430-interface-changes` for details. - -Foreign Key Data -================ - -- The data structure returned by ``BaseConnection::getForeignKeyData()`` has been changed. You will need to adjust any - code depending on this method to use the new structure. - -Example: ``tableprefix_table_column1_column2_foreign`` - -The data returned has the following structure:: - - /** - * @return array[ - * {constraint_name} => - * stdClass[ - * 'constraint_name' => string, - * 'table_name' => string, - * 'column_name' => string[], - * 'foreign_table_name' => string, - * 'foreign_column_name' => string[], - * 'on_delete' => string, - * 'on_update' => string, - * 'match' => string - * ] - * ] - */ - -Breaking Enhancements -********************* - -Multiple Domain Support -======================= - -- If you set ``Config\App::$allowedHostnames``, URL-related functions such as :php:func:`base_url()`, - :php:func:`current_url()`, :php:func:`site_url()` will return the URL with the hostname set in - ``Config\App::$allowedHostnames`` if the current URL matches. - -Database -======== - -- The return type of ``CodeIgniter\Database\Database::loadForge()`` has been changed to ``Forge``. Extending classes - should likewise change the type. -- The return type of ``CodeIgniter\Database\Database::loadUtils()`` has been changed to ``BaseUtils``. Extending classes - should likewise change the type. -- The second parameter ``$index`` of ``BaseBuilder::updateBatch()`` has changed to ``$constraints``. It now accepts - types array, string, or ``RawSql``. Extending classes should likewise change types. -- The ``$set`` parameter of ``BaseBuilder::insertBatch()`` and ``BaseBuilder::updateBatch()`` now accepts an object of a - single row of data. Extending classes should likewise change the type. -- The third parameter ``$index`` of ``BaseBuilder::_updateBatch()`` has changed to ``$values``, and the parameter type - has changed to ``array``. Extending classes should likewise change the type. -- The ``Model::update()`` method now raises a ``DatabaseException`` if it generates an SQL statement without a WHERE - clause. If you need to update all records in a table, use Query Builder instead. E.g., - ``$model->builder()->update($data)``. - -.. _upgrade-430-honeypot-and-csp: - -Honeypot and CSP -================ - -When CSP is enabled, the id attribute ``id="hpc"`` will be injected into the container tag for the Honeypot field to -hide the field. If the id is already used in your views, you need to change it with ``Config\Honeypot::$containerId``. -And you can remove ``style="display:none"`` in ``Config\Honeypot::$container``. - -Others -====== - -- **Helper:** Since void HTML elements (e.g. ````) in ``html_helper``, ``form_helper`` or common functions have - been changed to be HTML5-compatible by default, if you need to be compatible with XHTML, you must set the ``$html5`` - property in **app/Config/DocTypes.php** to ``false``. -- **CLI:** Since the launch of Spark Commands was extracted from ``CodeIgniter\CodeIgniter``, there may be problems - running these commands if the ``Services::codeigniter()`` service has been overridden. - -Project Files -************* - -Numerous files in the **project space** (root, app, public, writable) received updates. Due to these files being outside -of the **system** scope, they will not be changed without your intervention. There are some third-party CodeIgniter -modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -.. _upgrade_430_config: - -Config ------- - -- **app/Config/App.php** - - - The new property ``$allowedHostnames`` is added to set allowed hostnames in the site URL other than the hostname in - the ``$baseURL``. See :ref:`v430-multiple-domain-support`. - - The property ``$appTimezone`` has been changed to ``UTC`` to avoid being affected by daylight saving time. - -- **app/Config/Autoload.php** - - - The new property ``$helpers`` is added to autoload helpers. - -- **app/Config/Database.php** - - - ``$default['DBDebug']`` and ``$test['DBDebug']`` are changed to ``true`` by default. See - :ref:`exceptions-when-database-errors-occur`. - -- **app/Config/DocTypes.php** - - - The property ``$html5`` to determine whether to remove the solidus (``/``) character for void HTML elements (e.g. - ````) is added, and set to ``true`` by default for HTML5 compatibility. - -- **app/Config/Encryption.php** - - - The new properties ``$rawData``, ``$encryptKeyInfo``, and ``$authKeyInfo`` are added for CI3 Encryption - compatibility. See :ref:`encryption-compatible-with-ci3`. - -- **app/Config/Exceptions.php** - - - Two additional public properties were added: ``$logDeprecations`` and ``$deprecationLogLevel``. See - :ref:`logging_deprecation_warnings` for details. - -- **app/Config/Honeypot.php** - - - The new property ``$containerId`` is added to set the id attribute value for the container tag when CSP is enabled. - - The ``input`` tag in the property ``$template`` value has been changed to be HTML5-compatible. - -- **app/Config/Logger.php** - - - The property ``$threshold`` has been changed to ``9`` in environments other than ``production``. - -- **app/Config/Modules.php** - - - The new property ``$composerPackages`` is added to limit Composer package Auto-Discovery for better performance. - -- **app/Config/Routes.php** - - - Due to the fact that the approach to running Spark Commands has changed, there is no longer a need to load the - internal routes of the framework (``SYSTEMPATH . 'Config/Routes.php'``). - -- **app/Config/Security.php** - - - Changed the value of the property ``$redirect`` to ``false`` to prevent redirection when a CSRF check fails. This is - to make it easier to recognize that it is a CSRF error. - -- **app/Config/Session.php** - - - Added to handle session configuration. - -- **app/Config/Validation.php** - - - The default Validation Rules have been changed to Strict Rules for better security. See - :ref:`validation-traditional-and-strict-rules`. - -View Files ----------- - -The following view files have been changed to HTML5-compatible tags. Also, error messages are now defined in the -**Errors** language file. - -- **app/Views/errors/html/error_404.php** -- **app/Views/errors/html/error_exception.php** -- **app/Views/errors/html/production.php** -- **app/Views/welcome_message.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime. All atomic type properties in ``Config`` classes have been typed: - -* **app/Config/App.php** -* **app/Config/Autoload.php** -* **app/Config/CURLRequest.php** -* **app/Config/Cache.php** -* **app/Config/ContentSecurityPolicy.php** -* **app/Config/Cookie.php** -* **app/Config/Database.php** -* **app/Config/DocTypes.php** -* **app/Config/Email.php** -* **app/Config/Encryption.php** -* **app/Config/Exceptions.php** -* **app/Config/Feature.php** -* **app/Config/Filters.php** -* **app/Config/Format.php** -* **app/Config/Generators.php** -* **app/Config/Honeypot.php** -* **app/Config/Images.php** -* **app/Config/Kint.php** -* **app/Config/Logger.php** -* **app/Config/Migrations.php** -* **app/Config/Mimes.php** -* **app/Config/Modules.php** -* **app/Config/Pager.php** -* **app/Config/Paths.php** -* **app/Config/Routes.php** -* **app/Config/Security.php** -* **app/Config/Session.php** -* **app/Config/Toolbar.php** -* **app/Config/UserAgents.php** -* **app/Config/Validation.php** -* **app/Views/errors/html/error_404.php** -* **app/Views/errors/html/error_exception.php** -* **app/Views/errors/html/production.php** -* **app/Views/welcome_message.php** -* **composer.json** -* env -* **phpunit.xml.dist** -* spark diff --git a/user_guide_src/source/installation/upgrade_431.rst b/user_guide_src/source/installation/upgrade_431.rst deleted file mode 100644 index ae5a0090378c..000000000000 --- a/user_guide_src/source/installation/upgrade_431.rst +++ /dev/null @@ -1,80 +0,0 @@ -############################# -Upgrading from 4.3.0 to 4.3.1 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Composer Version -**************** - -.. important:: If you use Composer, CodeIgniter v4.3 requires Composer 2.0.14 or later. - -If you are using an older version of Composer, upgrade your ``composer`` tool, and delete the **vendor/** directory, and -run ``composer update`` again. - -The procedure, for example, is as follows: - -.. code-block:: console - - composer self-update - rm -rf vendor/ - composer update - -Mandatory File Changes -********************** - -Config Files -============ - -app/Config/Email.php --------------------- - -- If you updated **app/Config/Email.php** when upgrading to v4.3.0, you must set the default values to ``$fromEmail``, - ``$fromName``, ``$recipients``, ``$SMTPHost``, ``$SMTPUser`` and ``$SMTPPass`` to apply environment variable - (**.env**) values. -- If no default values are set, setting environment variables for them will not be reflected in the Config object. - -app/Config/Exceptions.php -------------------------- - -- If you are using PHP 8.2, you need to add new properties ``$logDeprecations`` and ``$deprecationLogLevel``. - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Email.php** - - - Set the default value ``''`` to ``$fromEmail``, ``$fromName``, ``$recipients``, ``$SMTPHost``, ``$SMTPUser`` and - ``$SMTPPass`` to apply environment variable (**.env**) values. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Email.php** -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_432.rst b/user_guide_src/source/installation/upgrade_432.rst deleted file mode 100644 index 25b0e4ca3c7d..000000000000 --- a/user_guide_src/source/installation/upgrade_432.rst +++ /dev/null @@ -1,95 +0,0 @@ -############################# -Upgrading from 4.3.1 to 4.3.2 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -base_url() -========== - -The :php:func:`base_url()` behavior has been fixed. In previous versions, when you called ``base_url()`` -**without an argument**, it returned baseURL without a trailing slash (``/``). Now it returns baseURL with a trailing -slash. For example: - -- before: ``http://example.com`` -- after: ``http://example.com/`` - -If you have code that calls ``base_url()`` without an argument, you may need to adjust the URLs. - -.. _upgrade-432-uri-string: - -uri_string() -============ - -The :php:func:`uri_string()` behavior has been fixed. In previous versions, when you navigated to the baseURL, it -returned ``/``. Now it returns an empty string (``''``). - -If you have code that calls ``uri_string()``, you may need to adjust it. - -.. note:: :php:func:`uri_string()` returns a URI path relative to baseURL. It is not a full URI path if the baseURL - contains subfolders. If you use it for HTML links, it is better to use it with :php:func:`site_url()` like - ``site_url(uri_string())``. - -Mandatory File Changes -********************** - -composer.json -============= - -If you have installed CodeIgniter manually and are using or planning to use Composer, remove the following line: - -.. code-block:: text - - { - ... - "scripts": { - "post-update-cmd": [ - "CodeIgniter\\ComposerScripts::postUpdate" <-- Remove this line - ], - "test": "phpunit" - }, - ... - } - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -- **app/Config/Mimes.php** -- **app/Views/errors/html/error_exception.php** -- **composer.json** -- **public/.htaccess** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/App.php** -- **app/Config/Mimes.php** -- **app/Views/errors/html/error_exception.php** -- **composer.json** -- **public/.htaccess** diff --git a/user_guide_src/source/installation/upgrade_433.rst b/user_guide_src/source/installation/upgrade_433.rst deleted file mode 100644 index 1164badc439e..000000000000 --- a/user_guide_src/source/installation/upgrade_433.rst +++ /dev/null @@ -1,46 +0,0 @@ -############################# -Upgrading from 4.3.2 to 4.3.3 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Encryption.php** - - - The missing property ``$cipher`` is added for CI3 Encryption compatibility. See - :ref:`encryption-compatible-with-ci3`. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Common.php** -- **app/Config/Encryption.php** -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_434.rst b/user_guide_src/source/installation/upgrade_434.rst deleted file mode 100644 index 2da1b9f9e38d..000000000000 --- a/user_guide_src/source/installation/upgrade_434.rst +++ /dev/null @@ -1,63 +0,0 @@ -############################# -Upgrading from 4.3.3 to 4.3.4 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -Redirect Status Code -==================== - -- Due to a bug fix, the status codes of redirects may be changed. See - :ref:`ChangeLog v4.3.4 ` and if the code is not what you want, - :ref:`specify status codes `. - -Forge::modifyColumn() and NULL -============================== - -A bug fix may have changed the NULL constraint in the result of :ref:`$forge->modifyColumn() `. -See :ref:`Change Log `. To set the desired NULL constraint, change ``Forge::modifyColumn()`` to -always specify the ``null`` key. - -Note that the bug may have changed unexpected NULL constraints in previous versions. - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Generators.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/App.php** -- **app/Config/Generators.php** -- **composer.json** -- **public/index.php** diff --git a/user_guide_src/source/installation/upgrade_435.rst b/user_guide_src/source/installation/upgrade_435.rst deleted file mode 100644 index e1db39c8648c..000000000000 --- a/user_guide_src/source/installation/upgrade_435.rst +++ /dev/null @@ -1,74 +0,0 @@ -############################# -Upgrading from 4.3.4 to 4.3.5 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -Validation Placeholders -======================= - -To use :ref:`validation-placeholders` securely, please remember to create a validation rule for the field you will use -as a placeholder. - -E.g., if you have the following code:: - - $validation->setRules([ - 'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,{id}]', - ]); - -You need to add the rules for ``{id}``:: - - $validation->setRules([ - 'id' => 'max_length[19]|is_natural_no_zero', // Add this - 'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,{id}]', - ]); - -Session::stop() -=============== - -Prior to v4.3.5, the ``Session::stop()`` method did not destroy the session due to a bug. This method has been modified -to destroy the session, and is now deprecated because it is exactly the same as the ``Session::destroy()`` method. So -use the :ref:`Session::destroy ` method instead. - -If you have code that depends on the bug, replace it with ``session_regenerate_id(true)``. - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Generators.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/App.php** -- **app/Config/Generators.php** -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_436.rst b/user_guide_src/source/installation/upgrade_436.rst deleted file mode 100644 index 7f69ba6cc4ec..000000000000 --- a/user_guide_src/source/installation/upgrade_436.rst +++ /dev/null @@ -1,38 +0,0 @@ -############################# -Upgrading from 4.3.5 to 4.3.6 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -- ``AutoRouterInterface::getRoute()`` has a new second parameter ``string $httpVerb``. If you implement it, add the - parameter. - -Breaking Enhancements -********************* - -- The method signatures of ``ValidationInterface::check()`` and ``Validation::check()`` have been changed. If you - implement or extend them, update the signatures. - -Project Files -************* - -Version 4.3.6 did not alter any executable code in project files. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_437.rst b/user_guide_src/source/installation/upgrade_437.rst deleted file mode 100644 index bbea3ef2efc4..000000000000 --- a/user_guide_src/source/installation/upgrade_437.rst +++ /dev/null @@ -1,88 +0,0 @@ -############################# -Upgrading from 4.3.6 to 4.3.7 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Breaking Changes -**************** - -.. _upgrade-437-feature-testing: - -Feature Testing Request Body -============================ - -If you call: - -1. :ref:`withBody() ` -2. and :ref:`withBodyFormat() ` -3. and pass the ``$params`` to :ref:`call() ` (or shorthand methods) - -the priority for a Request body has been changed. In the unlikely event that you have test code affected by this change, -modify it. - -For example, now the ``$params`` is used to build the request body, and the ``$body`` is not used:: - - $this->withBody($body)->withBodyFormat('json')->call('post', $params) - -Previously, the ``$body`` was used for the request body. - -Return value of Validation::loadRuleGroup() -=========================================== - -The return value of ``Validation::loadRuleGroup()`` has been changed from "**rules array**" to "**array** of -**rules array** and **customErrors array**" (``[rules, customErrors]``). - -If you use the method, update the code like the following:: - - $rules = $this->validation->loadRuleGroup($rules); - ↓ - [$rules, $customErrors] = $this->validation->loadRuleGroup($rules); - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Kint.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/App.php** -- **app/Config/Autoload.php** -- **app/Config/Cache.php** -- **app/Config/ContentSecurityPolicy.php** -- **app/Config/Filters.php** -- **app/Config/Kint.php** -- **app/Config/Logger.php** -- **app/Config/Migrations.php** -- **app/Config/Modules.php** -- **app/Config/Paths.php** -- **app/Controllers/BaseController.php** -- **app/Controllers/Home.php** -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_438.rst b/user_guide_src/source/installation/upgrade_438.rst deleted file mode 100644 index 93c59a50cb98..000000000000 --- a/user_guide_src/source/installation/upgrade_438.rst +++ /dev/null @@ -1,41 +0,0 @@ -############################# -Upgrading from 4.3.7 to 4.3.8 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **composer.json** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_440.rst b/user_guide_src/source/installation/upgrade_440.rst deleted file mode 100644 index 6dd03327c0cc..000000000000 --- a/user_guide_src/source/installation/upgrade_440.rst +++ /dev/null @@ -1,313 +0,0 @@ -############################# -Upgrading from 4.3.8 to 4.4.0 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -SECURITY -******** - -When Using $this->validate() -============================ - -There was a known potential vulnerability in :ref:`$this->validate() ` in the Controller to bypass -validation. The attack could allow developers to misinterpret unvalidated empty data as validated and proceed with -processing. - -The :ref:`Validation::getValidated() ` method has been added to ensure that validated -data is obtained. - -Therefore, when you use ``$this->validate()`` in your Controllers, you should use the new ``Validation::getValidated()`` -method to get the validated data. - -.. literalinclude:: ../libraries/validation/045.php - :lines: 2- - -Breaking Changes -**************** - -.. _upgrade-440-uri-setsegment: - -URI::setSegment() Change -======================== - -Due to a bug, in previous versions an exception was not thrown if the last segment ``+2`` was specified. This bug has -been fixed. - -If your code depends on this bug, fix the segment number. - -.. literalinclude:: upgrade_440/002.php - :lines: 2- - -Site URI Changes -================ - -- Because of the rework for the current URI determination, the framework may return site URIs or the URI paths slightly - differently than in previous versions. It may break your test code. Update assertions if the existing tests fail. -- When your baseURL has sub-directories and you get the relative path to baseURL of the current URI by the - ``URI::getPath()`` method, you must use the new ``SiteURI::getRoutePath()`` method instead. - -See :ref:`v440-site-uri-changes` for details. - -When You Extend Exceptions -========================== - -If you are extending ``CodeIgniter\Debug\Exceptions`` and have not overridden the ``exceptionHandler()`` method, -defining the new ``Config\Exceptions::handler()`` method in your **app/Config/Exceptions.php** will cause the specified -Exception Handler to be executed. - -Your overridden code will no longer be executed, so make any necessary changes by defining your own exception handler. - -See :ref:`custom-exception-handlers` for details. - -Auto Routing (Improved) and translateURIDashes -============================================== - -When using Auto Routing (Improved) and ``$translateURIDashes`` is true (``$routes->setTranslateURIDashes(true)``), in -previous versions due to a bug two URIs corresponded to a single controller method, one URI for dashes (e.g., -**foo-bar**) and one URI for underscores (e.g., **foo_bar**). - -This bug was fixed and now URIs for underscores (**foo_bar**) are not accessible. - -If you have links to URIs for underscores (**foo_bar**), update them with URIs for dashes (**foo-bar**). - -When Passing Classname with Namespace to Factories -================================================== - -The behavior of passing a classname with a namespace to Factories has been changed. See -:ref:`ChangeLog ` for details. - -If you have code like ``model(\Myth\Auth\Models\UserModel::class)`` or ``model('Myth\Auth\Models\UserModel')`` (the code -may be in the third-party packages), and you expect to load your ``App\Models\UserModel``, you need to define the -classname to be loaded before the first loading of that class:: - - Factories::define('models', 'Myth\Auth\Models\UserModel', 'App\Models\UserModel'); - -See :ref:`factories-defining-classname-to-be-loaded` for details. - -Interface Changes -================= - -Some interface changes have been made. Classes that implement them should update their APIs to reflect the changes. See -:ref:`v440-interface-changes` for details. - -Method Signature Changes -======================== - -Some method signature changes have been made. Classes that extend them should update their APIs to reflect the changes. -See :ref:`v440-method-signature-changes` for details. - -Also, the parameter types of some constructors and ``Services::security()`` have changed. If you call them with the -parameters, change the parameter values. See :ref:`v440-parameter-type-changes` for details. - -RouteCollection::$routes -======================== - -The array structure of the protected property ``$routes`` has been modified for performance. - -If you extend ``RouteCollection`` and use the ``$routes``, update your code to match the new array structure. - -Mandatory File Changes -********************** - -index.php and spark -=================== - -The following files received significant changes and **you must merge the updated versions** with your application: - -- ``public/index.php`` (see also :ref:`v440-codeigniter-and-exit`) -- ``spark`` - -.. important:: If you don't update the above files, CodeIgniter will not work properly after running - ``composer update``. - - The upgrade procedure, for example, is as follows: - - .. code-block:: console - - composer update - cp vendor/codeigniter4/framework/public/index.php public/index.php - cp vendor/codeigniter4/framework/spark spark - -Config Files -============ - -app/Config/App.php ------------------- - -The property ``$proxyIPs`` must be an array. If you don't use proxy servers, it must be -``public array $proxyIPs = [];``. - -.. _upgrade-440-config-routing: - -app/Config/Routing.php ----------------------- - -To clean up the routing system, the following changes were made: - -- New **app/Config/Routing.php** file that holds the settings that used to be in the Routes file. -- The **app/Config/Routes.php** file was simplified so that it only contains the routes without settings and verbiage to - clutter the file. -- The environment-specific routes files are no longer loaded automatically. - -So you need to do the following: - -1. Copy **app/Config/Routing.php** from the new framework to your **app/Config** directory, and configure it. -2. Remove all settings in **app/Config/Routes.php** that are no longer needed. -3. If you use the environment-specific routes files, add them to the ``$routeFiles`` property in - **app/Config/Routing.php**. - -app/Config/Toolbar.php ----------------------- - -You need to add the new properties ``$watchedDirectories`` and ``$watchedExtensions`` for -:ref:`debug-toolbar-hot-reload`:: - - --- a/app/Config/Toolbar.php - +++ b/app/Config/Toolbar.php - @@ -88,4 +88,31 @@ class Toolbar extends BaseConfig - * `$maxQueries` defines the maximum amount of queries that will be stored. - */ - public int $maxQueries = 100; - + - + /** - + * -------------------------------------------------------------------------- - + * Watched Directories - + * -------------------------------------------------------------------------- - + * - + * Contains an array of directories that will be watched for changes and - + * used to determine if the hot-reload feature should reload the page or not. - + * We restrict the values to keep performance as high as possible. - + * - + * NOTE: The ROOTPATH will be prepended to all values. - + */ - + public array $watchedDirectories = [ - + 'app', - + ]; - + - + /** - + * -------------------------------------------------------------------------- - + * Watched File Extensions - + * -------------------------------------------------------------------------- - + * - + * Contains an array of file extensions that will be watched for changes and - + * used to determine if the hot-reload feature should reload the page or not. - + */ - + public array $watchedExtensions = [ - + 'php', 'css', 'js', 'html', 'svg', 'json', 'env', - + ]; - } - - -app/Config/Events.php ---------------------- - -You need to add the code to add a route for :ref:`debug-toolbar-hot-reload`:: - - --- a/app/Config/Events.php - +++ b/app/Config/Events.php - @@ -4,6 +4,7 @@ namespace Config; - - use CodeIgniter\Events\Events; - use CodeIgniter\Exceptions\FrameworkException; - +use CodeIgniter\HotReloader\HotReloader; - - /* - * -------------------------------------------------------------------- - @@ -44,5 +45,11 @@ Events::on('pre_system', static function () { - if (CI_DEBUG && ! is_cli()) { - Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect'); - Services::toolbar()->respond(); - + // Hot Reload route - for framework use on the hot reloader. - + if (ENVIRONMENT === 'development') { - + Services::routes()->get('__hot-reload', static function () { - + (new HotReloader())->run(); - + }); - + } - } - }); - -app/Config/Cookie.php ---------------------- - -The Cookie config items in **app/Config/App.php** are no longer used. - -1. Copy **app/Config/Cookie.php** from the new framework to your **app/Config** directory, and configure it. -2. Remove the properties (from ``$cookiePrefix`` to ``$cookieSameSite``) in **app/Config/App.php**. - -app/Config/Security.php ------------------------ - -The CSRF config items in **app/Config/App.php** are no longer used. - -1. Copy **app/Config/Security.php** from the new framework to your **app/Config** directory, and configure it. -2. Remove the properties (from ``$CSRFTokenName`` to ``$CSRFSameSite``) in **app/Config/App.php**. - -app/Config/Session.php ----------------------- - -The Session config items in **app/Config/App.php** are no longer used. - -1. Copy **app/Config/Session.php** from the new framework to your **app/Config** directory, and configure it. -2. Remove the properties (from ``$sessionDriver`` to ``$sessionDBGroup``) in **app/Config/App.php**. - -Breaking Enhancements -********************* - -- **Routing:** The method signature of ``RouteCollection::__construct()`` has been changed. The third parameter - ``Routing $routing`` has been added. Extending classes should likewise add the parameter so as not to break LSP. -- **Validation:** The method signature of ``Validation::check()`` has been changed. The ``string`` typehint on the - ``$rule`` parameter was removed. Extending classes should likewise remove the typehint so as not to break LSP. - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/CURLRequest.php** - - - The default value of :ref:`$shareOptions ` has been changed to ``false``. - -- **app/Config/Exceptions.php** - - - Added the new method ``handler()`` that defines custom Exception Handlers. See :ref:`custom-exception-handlers`. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/App.php** -- **app/Config/CURLRequest.php** -- **app/Config/Cookie.php** -- **app/Config/Database.php** -- **app/Config/Events.php** -- **app/Config/Exceptions.php** -- **app/Config/Filters.php** -- **app/Config/Routes.php** -- **app/Config/Routing.php** -- **app/Config/Toolbar.php** -- **public/index.php** -- spark diff --git a/user_guide_src/source/installation/upgrade_440/002.php b/user_guide_src/source/installation/upgrade_440/002.php deleted file mode 100644 index 9cabdfcfcff3..000000000000 --- a/user_guide_src/source/installation/upgrade_440/002.php +++ /dev/null @@ -1,12 +0,0 @@ -setSegment(4, 'three'); -// The URI will be http://example.com/one/two/three - -// After: -$uri->setSegment(4, 'three'); // Will throw Exception -$uri->setSegment(3, 'three'); -// The URI will be http://example.com/one/two/three diff --git a/user_guide_src/source/installation/upgrade_441.rst b/user_guide_src/source/installation/upgrade_441.rst deleted file mode 100644 index 003be47a208e..000000000000 --- a/user_guide_src/source/installation/upgrade_441.rst +++ /dev/null @@ -1,41 +0,0 @@ -############################# -Upgrading from 4.4.0 to 4.4.1 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -Version 4.4.1 did not alter any executable code in project files. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Autoload.php** -- **app/Config/DocTypes.php** -- **app/Config/Email.php** -- **app/Config/ForeignCharacters.php** -- **app/Config/Mimes.php** -- **app/Config/Modules.php** -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_442.rst b/user_guide_src/source/installation/upgrade_442.rst deleted file mode 100644 index e94d66d4a3c4..000000000000 --- a/user_guide_src/source/installation/upgrade_442.rst +++ /dev/null @@ -1,32 +0,0 @@ -############################# -Upgrading from 4.4.1 to 4.4.2 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Migrations.php** -- **app/Config/View.php** -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_443.rst b/user_guide_src/source/installation/upgrade_443.rst deleted file mode 100644 index 65b545a83d1f..000000000000 --- a/user_guide_src/source/installation/upgrade_443.rst +++ /dev/null @@ -1,45 +0,0 @@ -############################# -Upgrading from 4.4.2 to 4.4.3 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Mandatory File Changes -********************** - -error_exception.php -=================== - -The following file received significant changes and **you must merge the updated version** with your application: - -- **app/Views/errors/html/error_exception.php** - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Boot/development.php** -- **app/Config/Boot/production.php** -- **app/Config/Boot/testing.php** -- **app/Config/Filters.php** -- **app/Views/errors/html/error_404.php** -- **app/Views/errors/html/error_exception.php** diff --git a/user_guide_src/source/installation/upgrade_444.rst b/user_guide_src/source/installation/upgrade_444.rst deleted file mode 100644 index dc56a3338948..000000000000 --- a/user_guide_src/source/installation/upgrade_444.rst +++ /dev/null @@ -1,97 +0,0 @@ -############################# -Upgrading from 4.4.3 to 4.4.4 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -********************** -Mandatory File Changes -********************** - -Error Files -=========== - -Update the following files to show correct error messages: - -- **app/Views/errors/cli/error_exception.php** -- **app/Views/errors/html/error_exception.php** - -**************** -Breaking Changes -**************** - -.. _upgrade-444-validation-with-dot-array-syntax: - -Validation with Dot Array Syntax -================================ - -If you are using :ref:`dot array syntax ` in validation rules, a bug where ``*`` would -validate data in incorrect dimensions has been fixed. - -In previous versions, the rule key ``contacts.*.name`` captured data with any level like ``contacts.*.name``, -``contacts.*.*.name``, ``contacts.*.*.*.name``, etc., incorrectly. - -The following code explains the details: - -.. literalinclude:: upgrade_444/001.php - :lines: 2- - -If you have code that depends on the bug, fix the rule key. - -Validation rules matches and differs -==================================== - -Because bugs have been fixed in the case where ``matches`` and ``differs`` in the Strict and Traditional rules validate -data of non-string types, if you are using these rules and validate non-string data, the validation results might be -changed (fixed). - -Note that Traditional Rules should not be used to validate data that is not a string. - -The use of the ``ssl_key`` option in CURLRequest was removed -============================================================ - -The CURLRequest option ``ssl_key`` is not recognized anymore. If in use, the option ``ssl_key`` must be replaced with -the option ``verify`` in order to define the path to a CA bundle for CURLRequest. - -The CURLRequest option ``verify`` can also take *boolean* values as usual. - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/App.php** -- **app/Config/Autoload.php** -- **app/Config/Boot/development.php** -- **app/Config/Boot/testing.php** -- **app/Config/Cache.php** -- **app/Config/Email.php** -- **app/Config/Filters.php** -- **app/Config/Kint.php** -- **app/Config/Modules.php** -- **app/Config/Publisher.php** -- **app/Config/Session.php** -- **app/Views/errors/cli/error_exception.php** -- **app/Views/errors/html/error_exception.php** -- **composer.json** -- env -- spark diff --git a/user_guide_src/source/installation/upgrade_444/001.php b/user_guide_src/source/installation/upgrade_444/001.php deleted file mode 100644 index 0c7c3622a84e..000000000000 --- a/user_guide_src/source/installation/upgrade_444/001.php +++ /dev/null @@ -1,38 +0,0 @@ - [ - 'name' => 'Joe Smith', - 'just' => [ - 'friends' => [ - ['name' => 'SATO Taro'], - ['name' => 'Li Ming'], - ['name' => 'Heinz Müller'], - ], - ], - ], -]; - -$validation->setRules( - ['contacts.*.name' => 'required|max_length[8]'], -); - -$validation->run($data); // false - -d($validation->getErrors()); -/* - Before: Captured `contacts.*.*.*.name` incorrectly. - [ - contacts.just.friends.0.name => "The contacts.*.name field cannot exceed 8 characters in length.", - contacts.just.friends.2.name => "The contacts.*.name field cannot exceed 8 characters in length.", - ] - - After: Captures no data for `contacts.*.name`. - [ - contacts.*.name => string (38) "The contacts.*.name field is required.", - ] -*/ diff --git a/user_guide_src/source/installation/upgrade_445.rst b/user_guide_src/source/installation/upgrade_445.rst deleted file mode 100644 index 105cc2523534..000000000000 --- a/user_guide_src/source/installation/upgrade_445.rst +++ /dev/null @@ -1,31 +0,0 @@ -############################# -Upgrading from 4.4.4 to 4.4.5 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_446.rst b/user_guide_src/source/installation/upgrade_446.rst deleted file mode 100644 index cd845acfd573..000000000000 --- a/user_guide_src/source/installation/upgrade_446.rst +++ /dev/null @@ -1,50 +0,0 @@ -############################# -Upgrading from 4.4.5 to 4.4.6 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -**************** -Breaking Changes -**************** - -Time::createFromTimestamp() Timezone Change -=========================================== - -When you do not specify a timezone, now :ref:`Time::createFromTimestamp() ` returns a Time -instance with the app's timezone. - -If you want to keep the timezone UTC, you need to call ``setTimezone('UTC')``:: - - use CodeIgniter\I18n\Time; - - $time = Time::createFromTimestamp(1501821586)->setTimezone('UTC'); - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/App.php** -- **app/Config/Routing.php** -- **app/Views/welcome_message.php** -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_447.rst b/user_guide_src/source/installation/upgrade_447.rst deleted file mode 100644 index adfed54419e8..000000000000 --- a/user_guide_src/source/installation/upgrade_447.rst +++ /dev/null @@ -1,134 +0,0 @@ -############################# -Upgrading from 4.4.6 to 4.4.7 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -********************** -Mandatory File Changes -********************** - -URI Security -============ - -A feature to check that URIs do not contain disallowed strings has been added. This check is equivalent to the URI -Security found in CodeIgniter 3. - -We recommend you enable this feature. Add the following to **app/Config/App.php**:: - - public string $permittedURIChars = 'a-z 0-9~%.:_\-'; - -See :ref:`urls-uri-security` for details. - -Error Files -=========== - -The error page has been updated. Please update the following files: - -- **app/Views/errors/html/debug.css** -- **app/Views/errors/html/error_exception.php** - -**************** -Breaking Changes -**************** - -.. _upgrade-447-filter-paths: - -Paths in Controller Filters -=========================== - -A bug where URI paths processed by :doc:`../incoming/filters` were not URL-decoded has been fixed. - -.. note:: :doc:`Router <../incoming/routing>` processes URL-decoded URI paths. - -``Config\Filters`` has some places to specify the URI paths. If the paths have different values when URL-decoded, change -them to the URL-decoded values. - -For example: - -.. code-block:: php - - public array $globals = [ - 'before' => [ - 'csrf' => ['except' => '%E6%97%A5%E6%9C%AC%E8%AA%9E/*'], - ], - // ... - ]; - -↓ - -.. code-block:: php - - public array $globals = [ - 'before' => [ - 'csrf' => ['except' => '日本語/*'], - ], - // ... - ]; - -Time::difference() and DST -========================== - -In previous versions, when comparing dates with ``Time::difference()``, unexpected results were returned if the date -included a day different from 24 hours due to Daylight Saving Time (DST). See -:ref:`Note in Times and Dates ` for details. - -This bug has been fixed, so date comparisons will now be shifted by one day in such cases. - -In the unlikely event that you wish to maintain the behavior of the previous versions, change the time zone of both -dates being compared to UTC before passing them to ``Time::difference()``. - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/App.php** - - - The property ``$permittedURIChars`` was added. See :ref:`urls-uri-security` for details. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/App.php** -- **app/Config/Cache.php** -- **app/Config/ContentSecurityPolicy.php** -- **app/Config/Database.php** -- **app/Config/Exceptions.php** -- **app/Config/Filters.php** -- **app/Config/Format.php** -- **app/Config/Logger.php** -- **app/Config/Mimes.php** -- **app/Config/Routing.php** -- **app/Config/Toolbar.php** -- **app/Config/Validation.php** -- **app/Config/View.php** -- **app/Controllers/BaseController.php** -- **app/Views/errors/html/debug.css** -- **app/Views/errors/html/error_exception.php** -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_448.rst b/user_guide_src/source/installation/upgrade_448.rst deleted file mode 100644 index 3ed4aa7e7a86..000000000000 --- a/user_guide_src/source/installation/upgrade_448.rst +++ /dev/null @@ -1,33 +0,0 @@ -############################# -Upgrading from 4.4.7 to 4.4.8 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/.htaccess** -- **public/.htaccess** -- **writable/.htaccess** diff --git a/user_guide_src/source/installation/upgrade_450.rst b/user_guide_src/source/installation/upgrade_450.rst deleted file mode 100644 index ddcf183d18cc..000000000000 --- a/user_guide_src/source/installation/upgrade_450.rst +++ /dev/null @@ -1,358 +0,0 @@ -############################# -Upgrading from 4.4.8 to 4.5.0 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -Mandatory File Changes -********************** - -index.php and spark -=================== - -The following files received significant changes and **you must merge the updated versions** with your application: - -- ``public/index.php`` -- ``spark`` - -.. important:: If you don't update the above files, CodeIgniter will not work properly after running - ``composer update``. - - The upgrade procedure, for example, is as follows: - - .. code-block:: console - - composer update - cp vendor/codeigniter4/framework/public/index.php public/index.php - cp vendor/codeigniter4/framework/spark spark - -Breaking Changes -**************** - -.. _upgrade-450-lowercase-http-method-name: - -Lowercase HTTP Method Name -========================== - -Request::getMethod() --------------------- - -For historical reasons, ``Request::getMethod()`` returned HTTP method names in lower case by default. - -But the method token is case-sensitive because it might be used as a gateway to object-based systems with case-sensitive -method names. By convention, standardized methods are defined in all-uppercase US-ASCII letters. See -https://www.rfc-editor.org/rfc/rfc9110#name-overview. - -Now the deprecated ``$upper`` parameter in ``Request::getMethod()`` has been removed, and ``getMethod()`` returns the -HTTP method name as-is. That is, uppercase like "GET", "POST", and so on. - -If you want lowercase HTTP method names, use PHP's ``strtolower()`` function:: - - strtolower($request->getMethod()) - -And you should use uppercase HTTP method names in your app code. - -app/Config/Filters.php ----------------------- - -You should update the keys to uppercase in ``$methods`` in **app/Config/Filters.php**:: - - public array $methods = [ - 'POST' => ['invalidchars', 'csrf'], - 'GET' => ['csrf'], - ]; - -CURLRequest::request() ----------------------- - -In previous versions, you could pass lowercase HTTP methods to the ``request()`` method. But this bug has been fixed. - -Now you must pass the correct HTTP method names like ``GET``, ``POST``. Otherwise, you will get an error response:: - - $client = \Config\Services::curlrequest(); - $response = $client->request('get', 'https://www.google.com/', [ - 'http_errors' => false, - ]); - $response->getStatusCode(); // In previous versions: 200 - // In this version: 405 - -.. _upgrade-450-nested-route-groups-and-options: - -Nested Route Groups and Options -=============================== - -A bug that prevented options passed to outer ``group()`` from being merged with options in inner ``group()`` has been -fixed. - -Check and correct your route configuration as it could change the values of the options applied. - -For example, - -.. code-block:: php - - $routes->group('admin', ['filter' => 'csrf'], static function ($routes) { - $routes->get('/', static function () { - // ... - }); - - $routes->group('users', ['namespace' => 'Users'], static function ($routes) { - $routes->get('/', static function () { - // ... - }); - }); - }); - -Now the ``csrf`` filter is executed for both the route ``admin`` and ``admin/users``. In previous versions, it was -executed only for the route ``admin``. See also :ref:`routing-nesting-groups`. - -.. _upgrade-450-filter-execution-order: - -Filter Execution Order -====================== - -The order in which Controller Filters are executed has changed. If you wish to maintain the same execution order as in -previous versions, set ``Config\Feature::$oldFilterOrder`` to ``true``. See also :ref:`filter-execution-order`. - -1. The order of execution of filter groups has been changed. - - Before Filters:: - - Previous: route → globals → methods → filters - Now: globals → methods → filters → route - - After Filters:: - - Previous: route → globals → filters - Now: route → filters → globals - -2. The After Filters in *Route* filters and *Filters* filters execution order is now reversed. - - When you have the following configuration: - - .. code-block:: php - - // In app/Config/Routes.php - $routes->get('/', 'Home::index', ['filter' => ['route1', 'route2']]); - - // In app/Config/Filters.php - public array $filters = [ - 'filter1' => ['before' => '*', 'after' => '*'], - 'filter2' => ['before' => '*', 'after' => '*'], - ]; - - Before Filters:: - - Previous: route1 → route2 → filter1 → filter2 - Now: filter1 → filter2 → route1 → route2 - - After Filters:: - - Previous: route1 → route2 → filter1 → filter2 - Now: route2 → route1 → filter2 → filter1 - -.. _upgrade-450-api-response-trait: - -API\\ResponseTrait and String Data -================================== - -In previous versions, if you passed string data to a trait method, the framework returned an HTML response, even if the -response format was determined to be JSON. - -Now if you pass string data, it returns a JSON response correctly. See also -:ref:`api-response-trait-handling-response-types`. - -You can keep the behavior in previous versions if you set the ``$stringAsHtml`` property to ``true`` in your controller. - -FileLocator::findQualifiedNameFromPath() -======================================== - -In previous versions, ``FileLocator::findQualifiedNameFromPath()`` returned Fully Qualified Classnames with a leading -``\``. Now the leading ``\`` has been removed. - -If you have code that expects a leading ``\``, fix it. - -BaseModel::getIdValue() -======================= - -The ``BaseModel::getIdValue()`` method has been changed to ``abstract``, and the implementation has been removed. - -If you extend ``BaseModel``, implement the ``getIdValue()`` method in the child class. - -Factories -========= - -:doc:`../concepts/factories` has been changed to a final class. In the unlikely event that you have inherited Factories, -stop inheriting and copy the code into your Factories class. - -Auto Routing (Legacy) -===================== - -In previous versions, the controller filters might be executed even when the corresponding controller was not found. - -This bug has been fixed and now a ``PageNotFoundException`` will be thrown and the filters will not be executed if the -controller is not found. - -If you have code that depends on this bug, for example if you expect global filters to be executed even for non-existent -pages, use the new :ref:`v450-required-filters`. - -Method Signature Changes -======================== - -Some method signature changes have been made. Classes that extend them should update their APIs to reflect the changes. -See :ref:`ChangeLog ` for details. - -Removed Deprecated Items -======================== - -Some deprecated items have been removed. If you are still using these items, or extending these classes, upgrade your -code. See :ref:`ChangeLog ` for details. - -Breaking Enhancements -********************* - -.. _upgrade-450-404-override: - -404 Override Status Code -======================== - -In previous versions, :ref:`404-override` returned responses with the status code ``200`` by default. Now it returns -``404`` by default. - -If you want ``200``, you need to set it in the controller:: - - $routes->set404Override(static function () { - response()->setStatusCode(200); - - echo view('my_errors/not_found.html'); - }); - -Validation::run() Signature -=========================== - -The method signatures of ``Validation::run()`` and ``ValidationInterface::run()`` have been changed. The ``?string`` -typehint on the ``$dbGroup`` parameter was removed. Extending classes should likewise remove the typehint so as not to -break LSP. - -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -app/Config/Filters.php -^^^^^^^^^^^^^^^^^^^^^^ - -Required Filters have been added, so the following changes were made. See also :ref:`ChangeLog `. - -The base class has been changed:: - - class Filters extends \CodeIgniter\Config\Filters - -The following items are added in the ``$aliases`` property:: - - public array $aliases = [ - // ... - 'forcehttps' => \CodeIgniter\Filters\ForceHTTPS::class, - 'pagecache' => \CodeIgniter\Filters\PageCache::class, - 'performance' => \CodeIgniter\Filters\PerformanceMetrics::class, - ]; - -A new property ``$required`` is added, and set as follows:: - - public array $required = [ - 'before' => [ - 'forcehttps', // Force Global Secure Requests - 'pagecache', // Web Page Caching - ], - 'after' => [ - 'pagecache', // Web Page Caching - 'performance', // Performance Metrics - 'toolbar', // Debug Toolbar - ], - ]; - -The ``'toolbar'`` in the ``$globals['after']`` was removed. - -Others -^^^^^^ - -- **app/Config/Boot/production.php** - - - The default error level to ``error_reporting()`` has been changed to ``E_ALL & ~E_DEPRECATED``. - -- **app/Config/Cors.php** - - - Added to handle CORS configuration. - -- **app/Config/Database.php** - - - The default value of ``charset`` in ``$default`` has been changed to ``utf8mb4``. - - The default value of ``DBCollat`` in ``$default`` has been changed to ``utf8mb4_general_ci``. - - The default value of ``DBCollat`` in ``$tests`` has been changed to ``''``. - -- **app/Config/Feature.php** - - - ``Config\Feature::$oldFilterOrder`` has been added. See :ref:`filter-execution-order`. - - ``Config\Feature::$limitZeroAsAll`` has been added. See :ref:`v450-query-builder-limit-0-behavior`. - - ``Config\Feature::$multipleFilters`` has been removed, because now :ref:`multiple-filters` are always enabled. - -- **app/Config/Kint.php** - - - It no longer extends ``BaseConfig`` because enabling :ref:`factories-config-caching` could cause errors. - -- **app/Config/Optimize.php** - - - Added to handle optimization configuration. - -- **app/Config/Security.php** - - - The property ``$redirect`` has been changed to ``true`` in the ``production`` environment. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Autoload.php** -- **app/Config/Boot/production.php** -- **app/Config/Cache.php** -- **app/Config/Cors.php** -- **app/Config/Database.php** -- **app/Config/Feature.php** -- **app/Config/Filters.php** -- **app/Config/Generators.php** -- **app/Config/Kint.php** -- **app/Config/Optimize.php** -- **app/Config/Routing.php** -- **app/Config/Security.php** -- **app/Config/Session.php** -- **app/Views/errors/cli/error_exception.php** -- **app/Views/errors/html/error_exception.php** -- **app/Views/welcome_message.php** -- **composer.json** -- env -- **phpunit.xml.dist** -- **preload.php** -- **public/index.php** -- spark diff --git a/user_guide_src/source/installation/upgrade_451.rst b/user_guide_src/source/installation/upgrade_451.rst deleted file mode 100644 index 35522cf0c889..000000000000 --- a/user_guide_src/source/installation/upgrade_451.rst +++ /dev/null @@ -1,38 +0,0 @@ -############################# -Upgrading from 4.5.0 to 4.5.1 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- .gitignore -- **composer.json** -- **phpunit.xml.dist** -- **tests/.htaccess** -- **tests/index.html** -- **writable/debugbar/.gitkeep** (Removed) -- **writable/debugbar/index.html** -- **writable/index.html** diff --git a/user_guide_src/source/installation/upgrade_452.rst b/user_guide_src/source/installation/upgrade_452.rst deleted file mode 100644 index ceb0e9147949..000000000000 --- a/user_guide_src/source/installation/upgrade_452.rst +++ /dev/null @@ -1,40 +0,0 @@ -############################# -Upgrading from 4.5.1 to 4.5.2 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/DocTypes.php** -- **app/Config/Exceptions.php** -- **preload.php** -- spark -- **writable/.htaccess** -- **writable/cache/index.html** -- **writable/debugbar/index.html** -- **writable/index.html** -- **writable/logs/index.html** -- **writable/session/index.html** diff --git a/user_guide_src/source/installation/upgrade_453.rst b/user_guide_src/source/installation/upgrade_453.rst deleted file mode 100644 index 94b6cff52fba..000000000000 --- a/user_guide_src/source/installation/upgrade_453.rst +++ /dev/null @@ -1,42 +0,0 @@ -############################# -Upgrading from 4.5.2 to 4.5.3 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **composer.json** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_454.rst b/user_guide_src/source/installation/upgrade_454.rst deleted file mode 100644 index fe0b8a470974..000000000000 --- a/user_guide_src/source/installation/upgrade_454.rst +++ /dev/null @@ -1,32 +0,0 @@ -############################# -Upgrading from 4.5.3 to 4.5.4 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Events.php** -- **composer.json** diff --git a/user_guide_src/source/installation/upgrade_455.rst b/user_guide_src/source/installation/upgrade_455.rst deleted file mode 100644 index 7ca9ff25463b..000000000000 --- a/user_guide_src/source/installation/upgrade_455.rst +++ /dev/null @@ -1,42 +0,0 @@ -############################# -Upgrading from 4.5.4 to 4.5.5 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **preload.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **preload.php** diff --git a/user_guide_src/source/installation/upgrade_456.rst b/user_guide_src/source/installation/upgrade_456.rst deleted file mode 100644 index 654ad95ad82e..000000000000 --- a/user_guide_src/source/installation/upgrade_456.rst +++ /dev/null @@ -1,35 +0,0 @@ -############################# -Upgrading from 4.5.5 to 4.5.6 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Events.php** -- **app/Config/Format.php** -- **app/Controllers/BaseController.php** -- **app/Views/errors/cli/error_exception.php** -- **app/Views/errors/html/error_exception.php** diff --git a/user_guide_src/source/installation/upgrade_457.rst b/user_guide_src/source/installation/upgrade_457.rst deleted file mode 100644 index 26ffa8371a3e..000000000000 --- a/user_guide_src/source/installation/upgrade_457.rst +++ /dev/null @@ -1,31 +0,0 @@ -############################# -Upgrading from 4.5.6 to 4.5.7 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Views/errors/cli/error_exception.php** diff --git a/user_guide_src/source/installation/upgrade_458.rst b/user_guide_src/source/installation/upgrade_458.rst deleted file mode 100644 index ca5e74c1a9f0..000000000000 --- a/user_guide_src/source/installation/upgrade_458.rst +++ /dev/null @@ -1,39 +0,0 @@ -############################# -Upgrading from 4.5.7 to 4.5.8 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **preload.php** -- **public/index.php** -- spark diff --git a/user_guide_src/source/installation/upgrade_460.rst b/user_guide_src/source/installation/upgrade_460.rst deleted file mode 100644 index 8177bababc94..000000000000 --- a/user_guide_src/source/installation/upgrade_460.rst +++ /dev/null @@ -1,226 +0,0 @@ -############################# -Upgrading from 4.5.8 to 4.6.0 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -**************** -Breaking Changes -**************** - -Exception Changes -================= - -Some classes have changed the exception classes that are thrown. Some exception classes have changed parent classes. See -:ref:`ChangeLog ` for details. - -If you have code that catches these exceptions, change the exception classes. - -.. _upgrade-460-time-create-from-timestamp: - -Time::createFromTimestamp() Timezone Change -=========================================== - -When you do not explicitly pass a timezone, now :ref:`Time::createFromTimestamp() ` returns a -Time instance with **UTC**. From v4.4.6 to before v4.6.0, a Time instance with the currently set default timezone was -returned. - -This behavior change normalizes behavior with changes in PHP 8.4, which adds a new -``DateTimeInterface::createFromTimestamp()`` method. - -If you want to keep the default timezone, you need to pass the timezone as the second parameter:: - - use CodeIgniter\I18n\Time; - - $time = Time::createFromTimestamp(1501821586, date_default_timezone_get()); - -.. _upgrade-460-time-keeps-microseconds: - -Time keeps Microseconds -======================= - -In previous versions, :doc:`Time <../libraries/time>` lost microseconds in some cases. But the bugs have been fixed. - -The results of the ``Time`` comparison may differ due to these fixes: - -.. literalinclude:: upgrade_460/006.php - :lines: 2- - -In such a case, you need to remove the microseconds: - -.. literalinclude:: upgrade_460/007.php - :lines: 2- - -The following cases now keep microseconds: - -.. literalinclude:: upgrade_460/002.php - :lines: 2- - -.. literalinclude:: upgrade_460/003.php - :lines: 2- - -Note that ``Time`` with the current time already held microseconds before this change. - -.. literalinclude:: upgrade_460/004.php - :lines: 2- - -Also, methods that return an ``int`` still lose the microseconds. - -.. literalinclude:: upgrade_460/005.php - :lines: 2- - -.. _upgrade-460-time-set-timestamp: - -Time::setTimestamp() Behavior Fix -================================= - -In previous versions, calling ``Time::setTimestamp()`` on a Time instance with a timezone other than the default -timezone might return a Time instance with the wrong date/time. - -This bug has been fixed, and it now behaves in the same way as ``DateTimeImmutable``: - -.. literalinclude:: upgrade_460/008.php - :lines: 2- - -Note that if you use the default timezone, the behavior is not changed: - -.. literalinclude:: upgrade_460/009.php - :lines: 2- - -.. _upgrade-460-registrars-with-dirty-hack: - -Registrars with Dirty Hack -========================== - -To prevent Auto-Discovery of :ref:`registrars` from running twice, when a registrar class is loaded or instantiated, if -it instantiates a Config class (which extends ``CodeIgniter\Config\BaseConfig``), ``ConfigException`` will be raised. - -This is because if Auto-Discovery of Registrars is performed twice, duplicate values may be added to properties of -Config classes. - -All registrar classes (**Config/Registrar.php** in all namespaces) must be modified so that they do not instantiate any -Config class when loaded or instantiated. - -If the packages/modules you are using provide such registrar classes, the registrar classes in the packages/modules need -to be fixed. - -The following is an example of code that will no longer work: - -.. literalinclude:: upgrade_460/001.php - -.. _upgrade-460-sid-change: - -Session ID (SID) Change -======================= - -Now :doc:`../libraries/sessions` forces the use of the PHP default 32-character SIDs, with 4 bits of entropy per -character. This change is to match the behavior of PHP 9. - -In other words, the following settings are always used: - -.. code-block:: ini - - session.sid_bits_per_character = 4 - session.sid_length = 32 - -In previous versions, the PHP ini settings were respected. So this change may change your SID length. - -If you cannot accept this change, customize the Session library. - -Interface Changes -================= - -Some interface changes have been made. Classes that implement them should update their APIs to reflect the changes. See -:ref:`ChangeLog ` for details. - -Method Signature Changes -======================== - -Some method signature changes have been made. Classes that extend them should update their APIs to reflect the changes. -See :ref:`ChangeLog ` for details. - -Removed Deprecated Items -======================== - -Some deprecated items have been removed. If you are still using these items, or extending these classes, upgrade your -code. See :ref:`ChangeLog ` for details. - -********************* -Breaking Enhancements -********************* - -.. _upgrade-460-filters-changes: - -Filters Changes -=============== - -The ``Filters`` class has been changed to allow multiple runs of the same filter with different arguments in before or -after. - -If you are extending ``Filters``, you will need to modify it to conform to the following changes: - -- The structure of the array properties ``$filters`` and ``$filtersClasses`` has been changed. -- The properties ``$arguments`` and ``$argumentsClass`` are no longer used. -- ``Filters`` has been changed so that the same filter class is not instantiated multiple times. If a filter class is - used both before and after, the same instance is used. - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -There are some third-party CodeIgniter modules available to assist with merging changes to the project space: -`Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Feature.php** - - - ``Config\Feature::$autoRoutesImproved`` has been changed to ``true``. - - ``Config\Feature::$strictLocaleNegotiation`` has been added. - -- **app/Config/Routing.php** - - - ``Config\Routing::$translateUriToCamelCase`` has been changed to ``true``. - -- **app/Config/Kint.php** - - - ``Config\Kint::$richSort`` has been removed. Kint in v6 no longer uses ``AbstractRenderer::SORT_FULL``. Leaving this - property in your code will cause a runtime error due to the undefined constant. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Cache.php** -- **app/Config/Constants.php** -- **app/Config/Database.php** -- **app/Config/Feature.php** -- **app/Config/Format.php** -- **app/Config/Kint.php** -- **app/Config/Routing.php** -- **app/Config/Security.php** -- **app/Views/errors/html/debug.css** -- **app/Views/errors/html/error_400.php** -- **preload.php** -- **public/index.php** -- spark diff --git a/user_guide_src/source/installation/upgrade_460/001.php b/user_guide_src/source/installation/upgrade_460/001.php deleted file mode 100644 index 6d55ef67d336..000000000000 --- a/user_guide_src/source/installation/upgrade_460/001.php +++ /dev/null @@ -1,33 +0,0 @@ - [ - 'module_pager' => 'MyModule\Views\Pager', - ], - ]; - } - - public static function hack(): void - { - $config = config('Cache'); - - // Does something. - } -} - -Registrar::hack(); // Bad. When this class is loaded, Config\Cache will be instantiated. diff --git a/user_guide_src/source/installation/upgrade_460/002.php b/user_guide_src/source/installation/upgrade_460/002.php deleted file mode 100644 index 91747d7b5464..000000000000 --- a/user_guide_src/source/installation/upgrade_460/002.php +++ /dev/null @@ -1,8 +0,0 @@ -format('Y-m-d H:i:s.u'); -// Before: 2024-07-09 09:13:34.000000 -// After: 2024-07-09 09:13:34.654321 diff --git a/user_guide_src/source/installation/upgrade_460/003.php b/user_guide_src/source/installation/upgrade_460/003.php deleted file mode 100644 index 65914ece9c7c..000000000000 --- a/user_guide_src/source/installation/upgrade_460/003.php +++ /dev/null @@ -1,8 +0,0 @@ -format('Y-m-d H:i:s.u'); -// Before: 2024-07-26 21:05:57.000000 -// After: 2024-07-26 21:05:57.857235 diff --git a/user_guide_src/source/installation/upgrade_460/004.php b/user_guide_src/source/installation/upgrade_460/004.php deleted file mode 100644 index dab6489fd68b..000000000000 --- a/user_guide_src/source/installation/upgrade_460/004.php +++ /dev/null @@ -1,8 +0,0 @@ -format('Y-m-d H:i:s.u'); -// Before: 2024-07-26 21:39:32.249072 -// After: 2024-07-26 21:39:32.249072 diff --git a/user_guide_src/source/installation/upgrade_460/005.php b/user_guide_src/source/installation/upgrade_460/005.php deleted file mode 100644 index a5e80c09b778..000000000000 --- a/user_guide_src/source/installation/upgrade_460/005.php +++ /dev/null @@ -1,9 +0,0 @@ -getTimestamp(); // 1704110400 - -$time2 = new Time('2024-01-01 12:00:00.654321'); -echo $time2->getTimestamp(); // 1704110400 diff --git a/user_guide_src/source/installation/upgrade_460/006.php b/user_guide_src/source/installation/upgrade_460/006.php deleted file mode 100644 index 316d802ada48..000000000000 --- a/user_guide_src/source/installation/upgrade_460/006.php +++ /dev/null @@ -1,10 +0,0 @@ -equals($time2); -// Before: true -// After: false diff --git a/user_guide_src/source/installation/upgrade_460/007.php b/user_guide_src/source/installation/upgrade_460/007.php deleted file mode 100644 index d6b6e78e6c38..000000000000 --- a/user_guide_src/source/installation/upgrade_460/007.php +++ /dev/null @@ -1,17 +0,0 @@ -format('Y-m-d H:i:s'), - $time1->getTimezone(), -); - -$time1->equals($time2); -// Before: true -// After: true diff --git a/user_guide_src/source/installation/upgrade_460/008.php b/user_guide_src/source/installation/upgrade_460/008.php deleted file mode 100644 index 5a778de09c53..000000000000 --- a/user_guide_src/source/installation/upgrade_460/008.php +++ /dev/null @@ -1,18 +0,0 @@ -setTimestamp($stamp); - -echo $time2->format('Y-m-d H:i:s P'); -// Before: 2024-08-20 00:00:00 -05:00 -// After: 2024-08-19 19:00:00 -05:00 diff --git a/user_guide_src/source/installation/upgrade_460/009.php b/user_guide_src/source/installation/upgrade_460/009.php deleted file mode 100644 index f00daa0b63b0..000000000000 --- a/user_guide_src/source/installation/upgrade_460/009.php +++ /dev/null @@ -1,18 +0,0 @@ -setTimestamp($stamp); - -echo $time2->format('Y-m-d H:i:s P'); -// Before: 2024-08-20 00:00:00 -05:00 -// After: 2024-08-20 00:00:00 -05:00 diff --git a/user_guide_src/source/installation/upgrade_461.rst b/user_guide_src/source/installation/upgrade_461.rst deleted file mode 100644 index 9e30c9026c39..000000000000 --- a/user_guide_src/source/installation/upgrade_461.rst +++ /dev/null @@ -1,55 +0,0 @@ -############################# -Upgrading from 4.6.0 to 4.6.1 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Mimes.php** - - - ``Config\Mimes::$mimes`` has been updated to include the ``application/octet-stream`` and ``model/stl`` MIME types - for the ``.stl`` file extension. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Autoload.php** -- **app/Config/Cache.php** -- **app/Config/DocTypes.php** -- **app/Config/Mimes.php** -- **app/Config/Modules.php** -- **app/Config/Optimize.php** -- **app/Config/Paths.php** -- **app/Views/errors/html/debug.css** -- **preload.php** -- **public/index.php** -- spark diff --git a/user_guide_src/source/installation/upgrade_462.rst b/user_guide_src/source/installation/upgrade_462.rst deleted file mode 100644 index 1f5cf25371f2..000000000000 --- a/user_guide_src/source/installation/upgrade_462.rst +++ /dev/null @@ -1,63 +0,0 @@ -############################# -Upgrading from 4.6.1 to 4.6.2 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Autoload.php** -- **app/Config/Cache.php** -- **app/Config/Cookie.php** -- **app/Config/DocTypes.php** -- **app/Config/Logger.php** -- **app/Config/Mimes.php** -- **app/Config/Modules.php** -- **app/Config/Optimize.php** -- **app/Config/Paths.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Autoload.php** -- **app/Config/Cache.php** -- **app/Config/Cookie.php** -- **app/Config/DocTypes.php** -- **app/Config/Logger.php** -- **app/Config/Mimes.php** -- **app/Config/Modules.php** -- **app/Config/Optimize.php** -- **app/Config/Paths.php** -- **app/Views/errors/html/debug.css** -- **app/Views/errors/html/error_exception.php** -- **preload.php** -- **public/index.php** -- spark diff --git a/user_guide_src/source/installation/upgrade_463.rst b/user_guide_src/source/installation/upgrade_463.rst deleted file mode 100644 index 615ac79615f3..000000000000 --- a/user_guide_src/source/installation/upgrade_463.rst +++ /dev/null @@ -1,43 +0,0 @@ -############################# -Upgrading from 4.6.2 to 4.6.3 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Filters.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Filters.php** -- **preload.php** diff --git a/user_guide_src/source/installation/upgrade_464.rst b/user_guide_src/source/installation/upgrade_464.rst deleted file mode 100644 index f698bc84207b..000000000000 --- a/user_guide_src/source/installation/upgrade_464.rst +++ /dev/null @@ -1,46 +0,0 @@ -############################# -Upgrading from 4.6.3 to 4.6.4 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Database.php** - - - Added the ``synchronous`` key for ``Config\Database::$tests``. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Database.php** -- **app/Controllers/BaseController.php** -- **preload.php** diff --git a/user_guide_src/source/installation/upgrade_465.rst b/user_guide_src/source/installation/upgrade_465.rst deleted file mode 100644 index fcf822fd2b22..000000000000 --- a/user_guide_src/source/installation/upgrade_465.rst +++ /dev/null @@ -1,42 +0,0 @@ -############################# -Upgrading from 4.6.4 to 4.6.5 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- No config files were changed in this release. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- No project files were changed in this release. diff --git a/user_guide_src/source/installation/upgrade_470.rst b/user_guide_src/source/installation/upgrade_470.rst deleted file mode 100644 index 2b88d6b6149c..000000000000 --- a/user_guide_src/source/installation/upgrade_470.rst +++ /dev/null @@ -1,153 +0,0 @@ -############################# -Upgrading from 4.6.x to 4.7.0 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -**************** -Breaking Changes -**************** - -PHP 8.2 Required -================ - -The minimum PHP requirement has been updated to **PHP 8.2**. - -If your current runtime is older than PHP 8.2, upgrade PHP first before upgrading CodeIgniter. - -Validation ``regex_match`` Placeholders -======================================= - -Placeholders in the ``regex_match`` validation rule must now use double curly braces. - -If you previously used single braces like ``regex_match[/^{placeholder}$/]``, update it to: -``regex_match[/^{{placeholder}}$/]``. - -This avoids ambiguity with regex quantifiers such as ``{1,3}``. - -Model Primary Key Validation Timing and Exceptions -================================================== - -The ``insertBatch()`` and ``updateBatch()`` methods now honor model settings like ``updateOnlyChanged`` and -``allowEmptyInserts``. This change ensures consistent handling across all insert/update operations. - -Primary key values are now validated before database queries in ``insert()``/``insertBatch()`` (without auto-increment), -``update()``, and ``delete()``. - -Invalid primary key values now throw ``InvalidArgumentException`` instead of database-layer ``DatabaseException``. - -If your code catches ``DatabaseException`` for invalid primary keys, update it to handle ``InvalidArgumentException`` as -well. - -Entity Change Detection Is Now Deep -=================================== - -``Entity::hasChanged()`` and ``Entity::syncOriginal()`` now perform deep comparison for arrays and objects. - -If you relied on the previous shallow (reference-based) behavior, review your entity update flows and tests because -nested changes are now detected. - -Also, ``Entity::toRawArray()`` now recursively converts arrays of entities when ``$recursive`` is ``true``. - -Encryption Handler Key State -============================ - -``OpenSSLHandler`` and ``SodiumHandler`` no longer mutate the handler's internal key when a key is passed via -``$params`` to ``encrypt()``/``decrypt()``. - -If your code depended on passing a key once and reusing it implicitly later, move to explicit key configuration in -``Config\Encryption`` (or pass a custom config when creating the encrypter service). - -Interface Changes -================= - -Some interface changes have been made. Classes that implement framework interfaces should update their APIs to reflect -these changes. - -See :ref:`ChangeLog ` for details. - -Method Signature Changes -======================== - -Some method signature changes have been made. Classes that extend framework classes should update their method -signatures to keep LSP compatibility. - -See :ref:`ChangeLog ` for details. - -Property Signature Changes -========================== - -Some property type signatures have changed (for example nullable ``Entity::$dataCaster``). If you extend these classes, -update your code accordingly. - -See :ref:`ChangeLog ` for details. - -Removed Deprecated Items -======================== - -Some deprecated items have been removed. If your app still uses or extends these APIs, update your code before -upgrading. - -See :ref:`ChangeLog ` for details. - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Migrations.php** - - - ``Config\Migrations::$lock`` has been added, with a default value set to ``false``. - -These files are new in this release: - -- **app/Config/Hostnames.php** -- **app/Config/WorkerMode.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/CURLRequest.php** -- **app/Config/Cache.php** -- **app/Config/ContentSecurityPolicy.php** -- **app/Config/Email.php** -- **app/Config/Encryption.php** -- **app/Config/Format.php** -- **app/Config/Hostnames.php** -- **app/Config/Images.php** -- **app/Config/Migrations.php** -- **app/Config/Optimize.php** -- **app/Config/Paths.php** -- **app/Config/Routing.php** -- **app/Config/Session.php** -- **app/Config/Toolbar.php** -- **app/Config/UserAgents.php** -- **app/Config/View.php** -- **app/Config/WorkerMode.php** -- **public/index.php** -- spark diff --git a/user_guide_src/source/installation/upgrade_471.rst b/user_guide_src/source/installation/upgrade_471.rst deleted file mode 100644 index 24fb68366769..000000000000 --- a/user_guide_src/source/installation/upgrade_471.rst +++ /dev/null @@ -1,73 +0,0 @@ -############################# -Upgrading from 4.7.0 to 4.7.1 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -********************** -Mandatory File Changes -********************** - -Worker Mode -=========== - -If you are using Worker Mode, you must update **public/frankenphp-worker.php** after upgrading. The easiest way is to -re-run the install command: - -.. code-block:: console - - php spark worker:install --force - -********************* -Breaking Enhancements -********************* - -Database Connection Property Casting -==================================== - -``BaseConnection`` now casts string values coming from ``.env`` overrides to match the declared type of each connection -property. This affects properties that are ``null`` in the config array and then set via ``.env`` - such as SQLite3's -``synchronous`` or ``busyTimeout`` - which previously arrived as strings and were stored without conversion. - -If you extended the SQLite3 handler, review your custom typed properties and update them if needed. - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/WorkerMode.php** - - - ``Config\WorkerMode::$resetEventListeners`` has been added, with a default value set to ``[]``. See - :ref:`worker-mode-reset-event-listeners` for details. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Database.php** -- **app/Config/WorkerMode.php** diff --git a/user_guide_src/source/installation/upgrade_472.rst b/user_guide_src/source/installation/upgrade_472.rst deleted file mode 100644 index 606c702d6cac..000000000000 --- a/user_guide_src/source/installation/upgrade_472.rst +++ /dev/null @@ -1,42 +0,0 @@ -############################# -Upgrading from 4.7.1 to 4.7.2 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- No config files were changed in this release. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- No project files were changed in this release. diff --git a/user_guide_src/source/installation/upgrade_473.rst b/user_guide_src/source/installation/upgrade_473.rst deleted file mode 100644 index 63cbb9ed0953..000000000000 --- a/user_guide_src/source/installation/upgrade_473.rst +++ /dev/null @@ -1,76 +0,0 @@ -############################# -Upgrading from 4.7.2 to 4.7.3 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -********************** -Mandatory File Changes -********************** - -Worker Mode -=========== - -If you are using Worker Mode, you must update **public/frankenphp-worker.php** after upgrading. The easiest way is to -re-run the install command: - -.. code-block:: console - - php spark worker:install --force - -**************** -Breaking Changes -**************** - -File Validation -=============== - -The ``ext_in`` file upload validation rule now checks the client filename extension and verifies that the detected MIME -type is associated with that extension. Previously, ``ext_in`` only checked the MIME-derived guessed extension. - -This means files with no client filename extension, or files whose client filename extension does not match the detected -MIME type, now fail ``ext_in`` validation. If your application intentionally accepts such files, remove ``ext_in`` from -those validation rules and use a custom validation rule that matches your application's requirements. - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/Database.php** -- **app/Config/Events.php** -- **app/Config/Routes.php** -- **app/Config/View.php** - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/Database.php** -- **app/Config/Events.php** -- **app/Config/Routes.php** -- **app/Config/View.php** diff --git a/user_guide_src/source/installation/upgrade_474.rst b/user_guide_src/source/installation/upgrade_474.rst deleted file mode 100644 index 02a4dcd66854..000000000000 --- a/user_guide_src/source/installation/upgrade_474.rst +++ /dev/null @@ -1,69 +0,0 @@ -############################# -Upgrading from 4.7.3 to 4.7.4 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -**************** -Breaking Changes -**************** - -HTTPS Detection Behind Proxies -============================== - -For security reasons, ``IncomingRequest::isSecure()`` no longer trusts the ``X-Forwarded-Proto`` and ``Front-End-Https`` -headers unless the request comes from a trusted proxy. See the -`Security advisory GHSA-7wmf-pw8j-mc78 `_ -for more information. - -If your application runs behind a reverse proxy or load balancer that terminates TLS, you must register the proxy in -``Config\App::$proxyIPs``, e.g.:: - - public array $proxyIPs = [ - '10.0.1.200' => 'X-Forwarded-For', - '192.168.5.0/24' => 'X-Forwarded-For', - ]; - -Otherwise, ``isSecure()``, ``force_https()``, and ``Config\App::$forceGlobalSecureRequests`` will treat such requests as -non-HTTPS, which may result in redirect loops. - -.. note:: On dual-stack servers, a proxy's IPv4 address may be reported as an IPv4-mapped IPv6 address (e.g., - ``::ffff:192.168.5.21``), which does not match an IPv4 entry such as ``192.168.5.0/24``. In that case, add the - IPv4-mapped form to ``Config\App::$proxyIPs``, e.g., ``::ffff:192.168.5.21`` or ``::ffff:192.168.5.0/120``. - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- No config files were changed in this release. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- No project files were changed in this release. diff --git a/user_guide_src/source/installation/upgrade_475.rst b/user_guide_src/source/installation/upgrade_475.rst deleted file mode 100644 index 901b61553e5d..000000000000 --- a/user_guide_src/source/installation/upgrade_475.rst +++ /dev/null @@ -1,117 +0,0 @@ -############################# -Upgrading from 4.7.4 to 4.7.5 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -**************** -Breaking Changes -**************** - -.. _upgrade-475-view-parser-values: - -View Parser No Longer Parses Substituted Values -=============================================== - -For security reasons, the ``Parser`` now treats every substituted value strictly as data. A value that contains Parser -syntax, such as ``{name}``, ``{!name!}`` or ``{name|upper}``, is rendered literally and is never parsed again by a later -substitution pass. See the -`Security advisory GHSA-vgrf-mv2j-gp8w `_ -for more information. - -Previously, such a value could be parsed again, depending on the order of the keys in the data array. This behavior was -never documented, but code that relied on it will now output the placeholders literally. For example, the following used -to render ``

Hello, Bob!

`` and now renders ``

Hello, {name}!

``: - -.. code-block:: php - - $parser->setData([ - 'greeting' => 'Hello, {name}!', - 'name' => 'Bob', - ])->renderString('

{greeting}

'); - -If you need to insert a rendered template fragment into another template, render the fragment first and pass the result -as a value, using the ``{! !}`` syntax so it is not escaped again: - -.. code-block:: php - - $greeting = $parser->setData(['name' => 'Bob'])->renderString('Hello, {name}!'); - - $parser->setData(['greeting' => $greeting])->renderString('

{! greeting !}

'); - -Built-in Parser Plugin Output -============================= - -The output of built-in Parser plugins is now treated as rendered data and is not processed again as Parser syntax. This -prevents values such as URLs and validation messages from introducing variable or plugin instructions. Applications that -relied on placeholders within built-in plugin output must render those fragments explicitly. Custom plugins that -transform template code retain their existing behavior and are responsible for keeping untrusted data separate from -Parser syntax. - -File Upload Validation -====================== - -The ``is_image``, ``mime_in``, and ``ext_in`` rules now reject client filenames with a PHP handler extension before the -final extension, including extensions revealed by ``sanitize_filename()`` (for example, ``shell.p$hp.gif`` becomes -``shell.php.gif``). Filenames ending in dots, including dots followed by spaces, are also rejected. - -These checks apply regardless of the file's contents or the intended meaning of its name. For example, both -``shell.php.gif`` and an innocent PHP logo named ``logo.php.gif`` fail validation, even if the latter contains only a -GIF image. Rename such files before uploading, for example to ``logo-php.gif``. Choosing a generated filename when -saving the file does not bypass these validation checks, which run against the client filename before the file is saved. - -**************** -Behavior Changes -**************** - -CURLRequest Options After a Failed Request -========================================== - -When ``Config\CURLRequest::$shareOptions`` is ``false``, request-specific options are now reset even when the request -throws an exception. Per-request ``baseURI`` and ``delay`` values are also reset after both successful and failed -requests. Constructor defaults remain available for subsequent requests. - -If your application retries a failed request, pass its options again and reapply any settings made with ``setAuth()``, -``setBody()``, ``setForm()``, or ``setJSON()``. Do not rely on credentials or body data from the failed request -remaining on the client. - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- **app/Config/View.php** - - - ``Config\View::$restrictParserConditionals`` has been added, with a default value set to ``false``. See - :ref:`parser-restricting-conditionals` for details. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- **app/Config/View.php** -- **app/Controllers/BaseController.php** diff --git a/user_guide_src/source/installation/upgrade_476.rst b/user_guide_src/source/installation/upgrade_476.rst deleted file mode 100644 index da70bc0cb16a..000000000000 --- a/user_guide_src/source/installation/upgrade_476.rst +++ /dev/null @@ -1,138 +0,0 @@ -############################# -Upgrading from 4.7.5 to 4.7.6 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -**************** -Breaking Changes -**************** - -.. _upgrade-476-cache-delete-matching: - -File Cache ``deleteMatching()`` No Longer Matches Subdirectories -================================================================ - -For security reasons, ``FileHandler::deleteMatching()`` now matches the pattern against the names of files in the cache -directory only. See the -`Security advisory GHSA-9hf2-g3w9-pfmp `_ -for more information. - -Previously, the pattern was appended to the cache path and passed to ``glob()``, so a pattern containing a directory -separator, such as ``dir/key_*``, also deleted matching files in a subdirectory of the cache directory. Such a pattern -now never matches anything and the method returns ``0``. - -Most applications are not affected. The File handler stores every cache item directly in the cache directory, and the -default ``Config\Cache::$reservedCharacters`` forbid ``/`` and ``\`` in cache keys, so cache items could not be stored -in subdirectories. If your application places its own files in subdirectories of the cache directory and removed them -with ``deleteMatching()``, delete them directly instead, for example with the :php:func:`delete_files()` helper -function. - -.. _upgrade-476-model-replace: - -Model Field Protection for ``replace()`` -======================================== - -For security reasons, ``Model::replace()`` now applies field protection: - -- With protection enabled, fields outside ``$allowedFields`` are discarded except for a supplied primary key. Define a - non-empty list of fields callers may assign. -- Non-empty input reduced by filtering to no data or only its primary key now raises a ``DataException``. Review calls - to ensure they supply allowed data. -- For trusted operations requiring other columns, explicitly disable protection with ``protect(false)`` and restore it - with ``protect(true)`` afterward. - -See :ref:`model-replace` for details and replacement-specific precautions. - -.. _upgrade-476-named-binds: - -Named Binds Are No Longer Replaced Inside Quoted Values -======================================================= - -For security reasons, named bind placeholders (``:name:``) are now replaced only where the SQL parser would see them as -part of the query. A placeholder that appears inside a quoted string (``'...'``, ``"..."``, ``$$...$$`` on PostgreSQL, -``q'[...]'`` on Oracle), inside a quoted identifier (backticks, ``"..."``, and ``[...]`` on SQL Server and SQLite), or -inside a SQL comment (``--``, ``/* */``, and ``#`` on MySQL) is now left untouched. This makes named binds behave the -same way as question mark binds, which have always ignored markers inside quoted strings. See the -`Security advisory GHSA-25rf-99hr-7pmr `_ -for more information. - -Previously, such placeholders were replaced as well, so a value that was already escaped and rendered into the query -(for example a subquery, a custom ``where()`` string built with ``$db->escape()``, or the ``WHERE`` binds of -``deleteBatch()``) could be mixed with the value of another bind. - -This change only concerns queries that place a placeholder inside a quoted string, a quoted identifier, or a comment. -With the default escaping, such a placeholder never produced the intended SQL, because the quotes of the escaped value -ended up inside the literal or identifier (for example ``LIKE '%:name:%'`` compiled to ``LIKE '%'Rick'%'``). In -practice, the only working queries that change their behavior are those that disable escaping for a bind, either with -the third parameter of ``$db->query()`` or by passing a ``RawSql`` value, and rely on the placeholder being replaced -inside a quoted string, a quoted identifier, or a comment: the placeholder is now left in the query literally. For -example, the following used to search for ``%Rick%`` and now searches for the literal string ``%:name:%``: - -.. code-block:: php - - $db->query("SELECT * FROM users WHERE name LIKE '%:name:%'", ['name' => ['Rick', false]], false); - -Move the quotes into the bound value instead, so that the value is escaped as a whole: - -.. code-block:: php - - $db->query('SELECT * FROM users WHERE name LIKE :name:', ['name' => '%Rick%']); - -********************* -Breaking Enhancements -********************* - -**************** -Behavior Changes -**************** - -Filename Sanitization -===================== - -``sanitize_filename()`` and ``Security::sanitizeFilename()`` now remove all backslashes. Single backslashes between -ordinary characters were already removed in previous versions, so paths such as ``folder\file.txt`` produce the same -result. Ordinary filenames and relative paths with forward slashes are also unchanged. Results can differ for repeated -backslashes, literal ``\0`` sequences, and inputs where removing backslashes exposes sequences stripped by the -sanitizer. - -Use forward slashes (``/``) for relative paths passed with ``$relativePath = true``, including on Windows. If your -application stores or compares sanitized filenames created from these inputs, check for changed results and possible -filename collisions. - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope, they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- No config files were changed in this release. - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- No project files were changed in this release. diff --git a/user_guide_src/source/installation/upgrade_477.rst b/user_guide_src/source/installation/upgrade_477.rst deleted file mode 100644 index ece51ec2a795..000000000000 --- a/user_guide_src/source/installation/upgrade_477.rst +++ /dev/null @@ -1,54 +0,0 @@ -############################# -Upgrading from 4.7.6 to 4.7.7 -############################# - -Please refer to the upgrade instructions corresponding to your installation method. - -- :ref:`Composer Installation App Starter Upgrading ` -- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` -- :ref:`Manual Installation Upgrading ` - -.. contents:: - :local: - :depth: 2 - -********************** -Mandatory File Changes -********************** - -**************** -Breaking Changes -**************** - -********************* -Breaking Enhancements -********************* - -************* -Project Files -************* - -Some files in the **project space** (root, app, public, writable) received updates. Due to these files being outside of -the **system** scope they will not be changed without your intervention. - -.. note:: There are some third-party CodeIgniter modules available to assist with merging changes to the project space: - `Explore on Packagist `_. - -Content Changes -=============== - -The following files received significant changes (including deprecations or visual adjustments) and it is recommended -that you merge the updated versions with your application: - -Config ------- - -- @TODO - -All Changes -=========== - -This is a list of all files in the **project space** that received changes; many will be simple comments or formatting -that have no effect on the runtime: - -- @TODO diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst deleted file mode 100644 index 7b6265d5dd8b..000000000000 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ /dev/null @@ -1,240 +0,0 @@ -######################### -Upgrading from 3.x to 4.x -######################### - -CodeIgniter 4 is a rewrite of the framework and is not backwards compatible. It is more appropriate to think of -converting your app, rather than upgrading it. Once you have done that, upgrading from one version of CodeIgniter 4 to -the next will be straightforward. - -The "lean, mean and simple" philosophy has been retained, but the implementation has a lot of differences, compared to -CodeIgniter 3. - -There is no 12-step checklist for upgrading. Instead, start with a copy of CodeIgniter 4 in a new project folder, -:doc:`however you wish to install and use it `, and then convert and integrate your app components. -We'll try to point out the most important considerations here. - -To upgrade your project, there are two major tasks you have to work on. First of all, there are some general adjustments -which are significant to every project and have to be handled. The second is the libraries, which make up CodeIgniter -and contain some of the most important functions. These libraries operate separately from each other, so you have to -look at them one by one. - -**Do read the user guide** before embarking on a project conversion! - -.. contents:: - :local: - :depth: 2 - -General Adjustments -******************* - -Downloads -========= - -- CI4 is still available as a :doc:`ready-to-run zip or tarball <../installation/installing_manual>`. -- It can also be installed using :doc:`Composer <../installation/installing_composer>`. - -Namespaces -========== - -- CI4 is built for PHP 8.2+, and everything in the framework is namespaced, except for the helper and lang files. - -Application Structure -===================== - -.. important:: - **index.php** is no longer in the root of the project! It has been moved inside the **public** folder, for better - security and separation of components. - - This means that you should configure your web server to "point" to your project's **public** folder, and not to the - project root. - - If you use Shared Hosting, see :ref:`deployment-to-shared-hosting-services`. - -- The **application** folder is renamed as **app** and the framework still has **system** folders, with the same - interpretation as before. -- The framework now provides for a **public** folder, intended as the document root for your app. -- The ``defined('BASEPATH') OR exit('No direct script access allowed');`` line is not necessary because files outside - the **public** folder are not accessible in the standard configuration. And CI4 no longer defines the constant - ``BASEPATH``, so remove the line in all files. -- There is also a **writable** folder, to hold cache data, logs, and session data. -- The **app** folder looks very similar to **application** for CI3, with some name changes, and some subfolders moved to - the **writable** folder. -- There is no longer a nested **application/core** folder, as we have a different mechanism for extending framework - components (see below). - -Routing -======= - -- The Auto Routing is disabled by default. You need to :ref:`define all routes ` by default. -- If you want to use the Auto Routing in the same way as CI3, you need to enable :ref:`auto-routing-legacy`. -- CI4 also has an optional new more secure :ref:`auto-routing-improved`. - -Model, View and Controller -========================== - -- CodeIgniter is based on the MVC concept. Thus, the changes to the Model, View and Controller are among the most - important things you have to handle. -- In CodeIgniter 4, models are now located in **app/Models** and you have to add the lines ``namespace App\Models;`` - along with ``use CodeIgniter\Model;`` right after the opening php tag. The last step is to replace - ``extends CI_Model`` with ``extends Model``. -- The views of CodeIgniter 4 have been moved to **app/Views**. Furthermore, you have to change the syntax of loading - views from ``$this->load->view('directory_name/file_name')`` to ``echo view('directory_name/file_name');``. -- Controllers of CodeIgniter 4 have to be moved to **app/Controllers**. After that, add ``namespace App\Controllers;`` - after the opening php tag. Lastly, replace ``extends CI_Controller`` with ``extends BaseController``. -- For more information, we recommend the following upgrade guides, which will give you some step-by-step instructions to - convert the MVC classes in CodeIgniter4: - -.. toctree:: - :titlesonly: - - upgrade_models - upgrade_views - upgrade_controllers - -Core Class Changes -================== - -- Input - - - CI3's `Input `_ corresponds to CI4's - :doc:`IncomingRequest `. - - For historical reasons, CI3 and CI4 used incorrect HTTP method names like "get", "post". Since v4.5.0, CI4 uses the - correct HTTP method names like "GET", "POST". - -- Output - - - CI3's `Output `_ corresponds to CI4's - :doc:`Responses `. - -Class Loading -============= - -- There is no longer a CodeIgniter "superobject", with framework component references magically injected as properties - of your controller. -- Classes are instantiated where needed, and framework components are managed by :doc:`../concepts/services`. -- The :doc:`Autoloader <../concepts/autoloader>` automatically handles PSR-4 style class locating, within the ``App`` - (**app** folder) and ``CodeIgniter`` (i.e., **system** folder) top level namespaces, with Composer autoloading - support. -- You can configure the class loading to support whatever application structure you are most comfortable with, including - the "HMVC" style. -- CI4 provides :doc:`../concepts/factories` that can load a class and share the instance like ``$this->load`` in CI3. - -Libraries -========= - -- Your app classes can still go inside **app/Libraries**, but they don't have to. -- Instead of CI3's ``$this->load->library('x');`` you can now use ``$this->x = new \App\Libraries\X();``, following - namespaced conventions for your component. Alternatively, you can use :doc:`../concepts/factories`: - ``$this->x = \CodeIgniter\Config\Factories::libraries('X');``. - -Helpers -======= - -- :doc:`Helpers <../general/helpers>` are pretty much the same as before, though some have been simplified. -- Since v4.3.0, you can autoload helpers via **app/Config/Autoload.php**, as in CI3. -- Some helpers from CodeIgniter 3 no longer exist in Version 4. For all these helpers, you have to find a new way to - implement your functions. These helpers are - `CAPTCHA Helper `_, - `Email Helper `_, - `Path Helper `_, and - `Smiley Helper `_. -- `Download Helper `_ in CI3 was removed. You need - to use the Response object where you are using ``force_download()``. See :ref:`force-file-download`. -- `Language Helper `_ in CI3 was removed. But - ``lang()`` is always available in CI4. See :php:func:`lang()`. -- `Typography Helper `_ in CI3 will be - :doc:`Typography Library <../libraries/typography>` in CI4. -- `Directory Helper `_ and - `File Helper `_ in CI3 will be - :doc:`../helpers/filesystem_helper` in CI4. -- `String Helper `_ functions in CI3 are included in - :doc:`../helpers/text_helper` in CI4. -- In CI4, ``redirect()`` is completely changed from CI3's. - - - `redirect() Documentation CodeIgniter 3.x `_ - - :php:func:`redirect() Documentation CodeIgniter 4.x ` - - In CI4, :php:func:`redirect()` returns a ``RedirectResponse`` instance instead of redirecting and terminating script - execution. You must return it from Controllers or Controller Filters. - - Cookies and Headers you set before calling ``redirect()`` are not automatically carried over to a - ``RedirectResponse``. You need to call ``withCookies()`` or ``withHeaders()`` manually if you want to send them. - - You need to change CI3's ``redirect('login/form')`` to ``return redirect()->to('login/form')``. - -Hooks -===== - -- `Hooks `_ have been replaced by :doc:`../extending/events`. -- Instead of CI3's ``$hook['post_controller_constructor']`` you now use - ``Events::on('post_controller_constructor', ['MyClass', 'MyFunction']);``, with the namespace - ``CodeIgniter\Events\Events;``. -- Events are always enabled, and are available globally. -- The hook points ``pre_controller`` and ``post_controller`` have been removed. Use :doc:`../incoming/filters` instead. -- The hook points ``display_override`` and ``cache_override`` have been removed because the base methods have been - removed. -- The hook point ``post_system`` has moved to just before sending the final rendered page. - -Error Handling -============== - -- The behavior in CI4 has been slightly changed. - - - In CI3 the behavior is set in the **index.php** file: - - - errors with the error level set by ``error_reporting()`` are logged (but depending on the ``log_threshold`` - setting, they may not be written to the log file). - - errors with an error level of ``E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR`` stop framework - processing, regardless of the error level set in ``error_reporting()``. - - - In CI4, the behavior is set in the **app/Config/Boot/{environment}.php** file: - - - errors with the error level set by ``error_reporting()`` are logged (but depending on the - ``Config\Logger::$threshold`` setting, they may not be written to the log file). - - all errors that are not ignored by ``error_reporting()`` will stop the framework processing. - -Extending the Framework -======================= - -- You don't need a **core** folder to hold ``MY_...`` framework component extensions or replacements. -- You don't need ``MY_X`` classes inside your libraries folder to extend or replace CI4 pieces. -- Make any such classes where you like, and add appropriate service methods in **app/Config/Services.php** to load your - components instead of the default ones. -- See :doc:`../extending/core_classes` for details. - -Upgrading Libraries -******************* - -- Your app classes can still go inside **app/Libraries**, but they don't have to. -- Instead of CI3's ``$this->load->library('x');`` you can now use ``$this->x = new \App\Libraries\X();``, following - namespaced conventions for your component. Alternatively, you can use :doc:`../concepts/factories`: - ``$this->x = \CodeIgniter\Config\Factories::libraries('X');``. -- Some libraries from CodeIgniter 3 no longer exist in Version 4. For all these libraries, you have to find a new way to - implement your functions. These libraries are - `Calendaring `_, - `FTP `_, - `Javascript `_, - `Shopping Cart `_, - `Trackback `_, - `XML-RPC /-Server `_, and - `Zip Encoding `_. -- All the other libraries, which exist in both CodeIgniter versions, can be upgraded with some adjustments. The most - important and most used libraries received an Upgrade Guide, which will help you with simple steps and examples to - adjust your code. - -.. toctree:: - :titlesonly: - - upgrade_configuration - upgrade_database - upgrade_emails - upgrade_encryption - upgrade_file_upload - upgrade_html_tables - upgrade_images - upgrade_localization - upgrade_migrations - upgrade_responses - upgrade_pagination - upgrade_routing - upgrade_security - upgrade_sessions - upgrade_validations - upgrade_view_parser diff --git a/user_guide_src/source/installation/upgrade_configuration.rst b/user_guide_src/source/installation/upgrade_configuration.rst deleted file mode 100644 index 1127845b564c..000000000000 --- a/user_guide_src/source/installation/upgrade_configuration.rst +++ /dev/null @@ -1,51 +0,0 @@ -Upgrade Configuration -##################### - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `Config Documentation CodeIgniter 3.x `_ -- :doc:`Configuration Documentation CodeIgniter 4.x ` - -What has been changed -===================== - -- In CI4, the configurations are now stored in classes which extend ``CodeIgniter\Config\BaseConfig``. -- The **application/config/config.php** in CI3 will be **app/Config/App.php** and some other files like - **app/Config/Security.php** for the specific classes. -- Within the configuration class, the config values are stored in public class properties. -- The method to fetch config values has been changed. - -Upgrade Guide -============= - -1. You have to change the values in the default CI4 config files according to the changes in the CI3 files. The config - names are pretty much the same as in CI3. -2. If you are using custom config files in your CI3 project you have to create those files as new PHP classes in your - CI4 project in **app/Config**. These classes should be in the ``Config`` namespace and should extend - ``CodeIgniter\Config\BaseConfig``. -3. Once you have created all custom config classes, you have to copy the variables from the CI3 config into the new CI4 - config class as public class properties. -4. Now, you have to change the config fetching syntax everywhere you fetch config values. The CI3 syntax is something - like ``$this->config->item('item_name');``. You have to change this into ``config('MyConfig')->item_name;``. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -Path: **application/config/site.php**: - -.. literalinclude:: upgrade_configuration/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -Path: **app/Config/Site.php**: - -.. literalinclude:: upgrade_configuration/001.php diff --git a/user_guide_src/source/installation/upgrade_configuration/001.php b/user_guide_src/source/installation/upgrade_configuration/001.php deleted file mode 100644 index fdbbfe4eff0a..000000000000 --- a/user_guide_src/source/installation/upgrade_configuration/001.php +++ /dev/null @@ -1,11 +0,0 @@ -`_ -- :doc:`Controller Documentation CodeIgniter 4.x ` - -What has been changed -===================== - -- Since namespaces have been added to CodeIgniter 4, the controllers must be changed to support namespaces. -- The constructor of CI4 Controller does not automatically load core classes into the properties. -- CI4's Controller has a special constructor :ref:`initController() `. -- CI4 provides :doc:`Request ` and :doc:`Responses ` objects for you to - work with - more powerful than the CI3 way. -- If you want a base controller (``MY_Controller`` in CI3), use **app/Controllers/BaseController.php**. -- Calling ``echo`` within Controllers, as in CI3, is still supported, but it is recommended that a string or Response - object be returned from Controllers. - -Upgrade Guide -============= - -1. First, move all controller files to the folder **app/Controllers**. -2. Add this line just after the opening php tag: ``namespace App\Controllers;`` -3. Replace ``extends CI_Controller`` with ``extends BaseController``. -4. Remove the line ``defined('BASEPATH') OR exit('No direct script access allowed');`` if it exists. - -If you use sub-directories in your controller structure, you have to change the namespace accordingly. - -For example, if you have a version 3 controller located in **application/controllers/users/auth/Register.php**, the -namespace has to be ``namespace App\Controllers\Users\Auth;`` and the controller path in version 4 should look like -this: **app/Controllers/Users/Auth/Register.php**. Make sure to capitalize the first letters of the sub-directories. - -After that, you have to insert a ``use`` statement below the namespace definition in order to extend the -``BaseController``: ``use App\Controllers\BaseController;`` - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -Path: **application/controllers**: - -.. literalinclude:: upgrade_controllers/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -Path: **app/Controllers**: - -.. literalinclude:: upgrade_controllers/001.php diff --git a/user_guide_src/source/installation/upgrade_controllers/001.php b/user_guide_src/source/installation/upgrade_controllers/001.php deleted file mode 100644 index b90fe63c538f..000000000000 --- a/user_guide_src/source/installation/upgrade_controllers/001.php +++ /dev/null @@ -1,11 +0,0 @@ -`_ -- :doc:`Working with Databases Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- The functionality in CI3 is basically the same as in CI4. -- `Database Caching `_ functionality known from CI3 was - removed. -- The method names have changed to camelCase and the :doc:`Query Builder <../database/query_builder>` now needs to be - initialized before you can run queries on it. - -Upgrade Guide -============= -1. Add your database credentials to **app/Config/Database.php**. The options are pretty much the same as in CI3. Only - some names have changed slightly. -2. Everywhere you have used the database, you have to replace ``$this->load->database();`` with ``$db = db_connect();``. -3. If you use multiple databases, use the following code to load additional databases: - ``$db = db_connect('group_name');``. -4. Now you have to change all database queries. The most important change here is to replace ``$this->db`` with just - ``$db`` and adjust the method name and ``$db``. Here are some examples: - - - ``$this->db->query('YOUR QUERY HERE');`` to ``$db->query('YOUR QUERY HERE');`` - - ``$this->db->simple_query('YOUR QUERY')`` to ``$db->simpleQuery('YOUR QUERY')`` - - ``$this->db->escape("something")`` to ``$db->escape("something");`` - - ``$this->db->affected_rows();`` to ``$db->affectedRows();`` - - ``$query->result();`` to ``$query->getResult();`` - - ``$query->result_array();`` to ``$query->getResultArray();`` - - ``echo $this->db->count_all('my_table');`` to ``echo $db->table('my_table')->countAll();`` - -5. To use the new Query Builder Class, you have to initialize the builder: ``$builder = $db->table('mytable');``. After - that, you can run the queries on the ``$builder``. Here are some examples: - - - ``$this->db->get()`` to ``$builder->get();`` - - ``$this->db->get_where('mytable', array('id' => $id), $limit, $offset);`` to - ``$builder->getWhere(['id' => $id], $limit, $offset);`` - - ``$this->db->select('title, content, date');`` to ``$builder->select('title, content, date');`` - - ``$this->db->select_max('age');`` to ``$builder->selectMax('age');`` - - ``$this->db->join('comments', 'comments.id = blogs.id');`` to - ``$builder->join('comments', 'comments.id = blogs.id');`` - - ``$this->db->having('user_id', 45);`` to ``$builder->having('user_id', 45);`` - -6. CI4 does not provide the `Database Caching `_ layer - known from CI3, so if you need to cache the result, use :doc:`../libraries/caching` instead. -7. If you use ``limit(0)`` in Query Builder, CI4 returns all records instead of no records due to a bug. But since - v4.5.0, you can change the incorrect behavior with a setting. So change the setting. See - :ref:`v450-query-builder-limit-0-behavior` for details. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_database/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_database/001.php diff --git a/user_guide_src/source/installation/upgrade_database/001.php b/user_guide_src/source/installation/upgrade_database/001.php deleted file mode 100644 index 18a1e627fe80..000000000000 --- a/user_guide_src/source/installation/upgrade_database/001.php +++ /dev/null @@ -1,8 +0,0 @@ -table('mytable'); - -$query = $builder->select('title') - ->where('id', $id) - ->limit(10, 20) - ->get(); diff --git a/user_guide_src/source/installation/upgrade_database/ci3sample/001.php b/user_guide_src/source/installation/upgrade_database/ci3sample/001.php deleted file mode 100644 index 5dd7b11a60e7..000000000000 --- a/user_guide_src/source/installation/upgrade_database/ci3sample/001.php +++ /dev/null @@ -1,6 +0,0 @@ -db->select('title') - ->where('id', $id) - ->limit(10, 20) - ->get('mytable'); diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst deleted file mode 100644 index 83d18f76bf96..000000000000 --- a/user_guide_src/source/installation/upgrade_emails.rst +++ /dev/null @@ -1,41 +0,0 @@ -Upgrade Emails -############## - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `Email Documentation CodeIgniter 3.x `_ -- :doc:`Email Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- Only small things like the method names and the loading of the library have changed. -- The behavior when using the SMTP protocol has been slightly changed. You may not be able to communicate with your SMTP - server properly if you use the CI3 settings. See :ref:`email-ssl-tls-for-smtp` and :ref:`email-preferences`. - -Upgrade Guide -============= -1. Within your class, change ``$this->load->library('email');`` to ``$email = service('email');``. -2. From then on, you have to change ``$this->email`` to ``$email`` in every line starting with it. -3. The methods in the Email class are named slightly differently. All methods, except for ``send()``, ``attach()``, - ``printDebugger()`` and ``clear()``, have ``set`` as a prefix followed by the previous method name. ``bcc()`` is now - ``setBcc()`` and so on. -4. The config attributes in **app/Config/Email.php** have changed. You should have a look at the - :ref:`setting-email-preferences` for a list of the new attributes. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_emails/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_emails/001.php diff --git a/user_guide_src/source/installation/upgrade_emails/001.php b/user_guide_src/source/installation/upgrade_emails/001.php deleted file mode 100644 index f7873714bab5..000000000000 --- a/user_guide_src/source/installation/upgrade_emails/001.php +++ /dev/null @@ -1,13 +0,0 @@ -setFrom('your@example.com', 'Your Name'); -$email->setTo('someone@example.com'); -$email->setCC('another@another-example.com'); -$email->setBCC('them@their-example.com'); - -$email->setSubject('Email Test'); -$email->setMessage('Testing the email class.'); - -$email->send(); diff --git a/user_guide_src/source/installation/upgrade_emails/ci3sample/001.php b/user_guide_src/source/installation/upgrade_emails/ci3sample/001.php deleted file mode 100644 index e9144bb87f6e..000000000000 --- a/user_guide_src/source/installation/upgrade_emails/ci3sample/001.php +++ /dev/null @@ -1,13 +0,0 @@ -load->library('email'); - -$this->email->from('your@example.com', 'Your Name'); -$this->email->to('someone@example.com'); -$this->email->cc('another@another-example.com'); -$this->email->bcc('them@their-example.com'); - -$this->email->subject('Email Test'); -$this->email->message('Testing the email class.'); - -$this->email->send(); diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst deleted file mode 100644 index fd8a3ef8ed96..000000000000 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ /dev/null @@ -1,41 +0,0 @@ -Upgrade Encryption -################## - -.. contents:: - :local: - :depth: 2 - -Documentation -************* - -- `Encryption Library Documentation CodeIgniter 3.x `_ -- :doc:`Encryption Service Documentation CodeIgniter 4.x ` - -What has been changed -********************* - -- Support for ``MCrypt`` has been dropped, as that has been deprecated as of PHP 7.2. - -Upgrade Guide -************* - -1. Within your configs, ``$config['encryption_key'] = 'abc123';`` moved from **application/config/config.php** to - ``public $key = 'abc123';`` in **app/Config/Encryption.php**. -2. If you need to decrypt data encrypted with CI3's Encryption, configure settings to maintain compatibility. See - :ref:`encryption-compatible-with-ci3`. -3. Wherever you have used the encryption library, you have to replace ``$this->load->library('encryption');`` with - ``$encrypter = service('encrypter');`` and change the methods for encrypting and decrypting like in the following - code example. - -Code Example -************ - -CodeIgniter Version 3.x -======================= - -.. literalinclude:: upgrade_encryption/ci3sample/001.php - -CodeIgniter Version 4.x -======================= - -.. literalinclude:: upgrade_encryption/001.php diff --git a/user_guide_src/source/installation/upgrade_encryption/001.php b/user_guide_src/source/installation/upgrade_encryption/001.php deleted file mode 100644 index 695d69e24a28..000000000000 --- a/user_guide_src/source/installation/upgrade_encryption/001.php +++ /dev/null @@ -1,9 +0,0 @@ -encrypt($plainText); - -// Outputs: This is a plain-text message! -echo $encrypter->decrypt($ciphertext); diff --git a/user_guide_src/source/installation/upgrade_encryption/ci3sample/001.php b/user_guide_src/source/installation/upgrade_encryption/ci3sample/001.php deleted file mode 100644 index b20ba8aec855..000000000000 --- a/user_guide_src/source/installation/upgrade_encryption/ci3sample/001.php +++ /dev/null @@ -1,9 +0,0 @@ -load->library('encryption'); - -$plain_text = 'This is a plain-text message!'; -$ciphertext = $this->encryption->encrypt($plain_text); - -// Outputs: This is a plain-text message! -echo $this->encryption->decrypt($ciphertext); diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst deleted file mode 100644 index 9fcefee6a599..000000000000 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ /dev/null @@ -1,38 +0,0 @@ -Upgrade Working with Uploaded Files -################################### - -.. contents:: - :local: - :depth: 2 - -Documentation -============= -- `File Uploading Class Documentation CodeIgniter 3.x `_ -- :doc:`Working with Uploaded Files Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- The functionality of the file upload has changed a lot. You can now check if the file got uploaded without errors and - moving / storing files is simpler. - -Upgrade Guide -============= -In CI4 you access uploaded files with ``$file = $this->request->getFile('userfile')``. From there you can validate if -the file got uploaded successfully with ``$file->isValid()``. To store the file you could use -``$path = $this->request->getFile('userfile')->store('head_img/', 'user_name.jpg');``. This will store the file in -**writable/uploads/head_img/user_name.jpg**. - -You have to change your file uploading code to match the new methods. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_file_upload/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_file_upload/001.php diff --git a/user_guide_src/source/installation/upgrade_file_upload/001.php b/user_guide_src/source/installation/upgrade_file_upload/001.php deleted file mode 100644 index ca2c85372ca2..000000000000 --- a/user_guide_src/source/installation/upgrade_file_upload/001.php +++ /dev/null @@ -1,33 +0,0 @@ - ' ']); - } - - public function do_upload() - { - $this->validateData([], [ - 'userfile' => [ - 'uploaded[userfile]', - 'max_size[userfile,100]', - 'mime_in[userfile,image/png,image/jpg,image/gif]', - 'ext_in[userfile,png,jpg,gif]', - 'max_dims[userfile,1024,768]', - ], - ]); - - $file = $this->request->getFile('userfile'); - - if (! $path = $file->store()) { - return view('upload_form', ['error' => 'upload failed']); - } - $data = ['upload_file_path' => $path]; - - return view('upload_success', $data); - } -} diff --git a/user_guide_src/source/installation/upgrade_file_upload/ci3sample/001.php b/user_guide_src/source/installation/upgrade_file_upload/ci3sample/001.php deleted file mode 100644 index f6bb20c64de3..000000000000 --- a/user_guide_src/source/installation/upgrade_file_upload/ci3sample/001.php +++ /dev/null @@ -1,36 +0,0 @@ -load->helper(array('form', 'url')); - } - - public function index() - { - $this->load->view('upload_form', array('error' => ' ' )); - } - - public function do_upload() - { - $config['upload_path'] = './uploads/'; - $config['allowed_types'] = 'png|jpg|gif'; - $config['max_size'] = 100; - $config['max_width'] = 1024; - $config['max_height'] = 768; - - $this->load->library('upload', $config); - - if (! $this->upload->do_upload('userfile')) { - $error = array('error' => $this->upload->display_errors()); - - $this->load->view('upload_form', $error); - } else { - $data = array('upload_data' => $this->upload->data()); - - $this->load->view('upload_success', $data); - } - } -} diff --git a/user_guide_src/source/installation/upgrade_html_tables.rst b/user_guide_src/source/installation/upgrade_html_tables.rst deleted file mode 100644 index 44d2ef955b1a..000000000000 --- a/user_guide_src/source/installation/upgrade_html_tables.rst +++ /dev/null @@ -1,38 +0,0 @@ -Upgrade HTML Tables -################### - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `HTML Table Documentation CodeIgniter 3.x `_ -- :doc:`HTML Table Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- Only small things like the method names and the loading of the library have changed. - -Upgrade Guide -============= -1. Within your class, change ``$this->load->library('table');`` to ``$table = new \CodeIgniter\View\Table();``. -2. From then on, you have to change ``$this->table`` to ``$table`` in every line starting with it. For example: - ``echo $this->table->generate($query);`` will become ``echo $table->generate($query);`` -3. The methods in the HTML Table class could be named slightly differently. The most important change in the naming is - the switch from underscored method names to camelCase. The method ``set_heading()`` from version 3 is now named - ``setHeading()`` and so on. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_html_tables/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_html_tables/001.php diff --git a/user_guide_src/source/installation/upgrade_html_tables/001.php b/user_guide_src/source/installation/upgrade_html_tables/001.php deleted file mode 100644 index 0d0679305409..000000000000 --- a/user_guide_src/source/installation/upgrade_html_tables/001.php +++ /dev/null @@ -1,11 +0,0 @@ -setHeading('Name', 'Color', 'Size'); - -$table->addRow('Fred', 'Blue', 'Small'); -$table->addRow('Mary', 'Red', 'Large'); -$table->addRow('John', 'Green', 'Medium'); - -echo $table->generate(); diff --git a/user_guide_src/source/installation/upgrade_html_tables/ci3sample/001.php b/user_guide_src/source/installation/upgrade_html_tables/ci3sample/001.php deleted file mode 100644 index 5e607318c36f..000000000000 --- a/user_guide_src/source/installation/upgrade_html_tables/ci3sample/001.php +++ /dev/null @@ -1,11 +0,0 @@ -load->library('table'); - -$this->table->set_heading('Name', 'Color', 'Size'); - -$this->table->add_row('Fred', 'Blue', 'Small'); -$this->table->add_row('Mary', 'Red', 'Large'); -$this->table->add_row('John', 'Green', 'Medium'); - -echo $this->table->generate(); diff --git a/user_guide_src/source/installation/upgrade_images.rst b/user_guide_src/source/installation/upgrade_images.rst deleted file mode 100644 index 457286a19f0f..000000000000 --- a/user_guide_src/source/installation/upgrade_images.rst +++ /dev/null @@ -1,40 +0,0 @@ -Upgrade Image Manipulation Class -################################ - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `Image Manipulation Class Documentation CodeIgniter 3.x `_ -- :doc:`Image Manipulation Class Documentation CodeIgniter 4.x <../libraries/images>` - -What has been changed -===================== -- The preferences passed to the constructor or ``initialize()`` method in CI3 have been changed to be specified in the - new methods in CI4. -- Some preferences like ``create_thumb`` are removed. -- In CI4, the ``save()`` method must be called to save the manipulated image. -- The ``display_errors()`` method has been removed, and an exception will be thrown if an error occurs. - -Upgrade Guide -============= -1. Within your class, change ``$this->load->library('image_lib');`` to ``$image = \Config\Services::image();``. -2. Change the preferences passed to the constructor or ``initialize()`` method to be specified in the corresponding - methods. -3. Call the ``save()`` method to save the file. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_images/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_images/001.php diff --git a/user_guide_src/source/installation/upgrade_images/001.php b/user_guide_src/source/installation/upgrade_images/001.php deleted file mode 100644 index c40e9b8076a9..000000000000 --- a/user_guide_src/source/installation/upgrade_images/001.php +++ /dev/null @@ -1,8 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->resize(75, 50, true) - ->save('/path/to/image/mypic_thumb.jpg'); diff --git a/user_guide_src/source/installation/upgrade_images/ci3sample/001.php b/user_guide_src/source/installation/upgrade_images/ci3sample/001.php deleted file mode 100644 index 94a8553a5e2a..000000000000 --- a/user_guide_src/source/installation/upgrade_images/ci3sample/001.php +++ /dev/null @@ -1,12 +0,0 @@ -load->library('image_lib', $config); - -$this->image_lib->resize(); diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst deleted file mode 100644 index ece453050b49..000000000000 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ /dev/null @@ -1,42 +0,0 @@ -Upgrade Localization -#################### - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `Language Documentation CodeIgniter 3.x `_ -- :doc:`Localization Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- In CI4 the language files return the language lines as an array. - -Upgrade Guide -============= -1. Specify the default language in **Config/App.php**: - - .. literalinclude:: upgrade_localization/001.php - -2. Now move your language files to **app/Language/**. -3. After that you have to change the syntax within the language files. Below in the Code Example you will see how the - language array within the file should look. -4. Remove from every file the language loader ``$this->lang->load($file, $lang);``. -5. Replace the method to load the language line ``$this->lang->line('error_email_missing')`` with - ``echo lang('Errors.errorEmailMissing');``. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_localization/ci3sample/002.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_localization/002.php diff --git a/user_guide_src/source/installation/upgrade_localization/001.php b/user_guide_src/source/installation/upgrade_localization/001.php deleted file mode 100644 index 4b0a000e3e44..000000000000 --- a/user_guide_src/source/installation/upgrade_localization/001.php +++ /dev/null @@ -1,14 +0,0 @@ - 'You must submit an email address', - 'errorURLMissing' => 'You must submit a URL', - 'errorUsernameMissing' => 'You must submit a username', - 'nested' => [ - 'error' => [ - 'message' => 'A specific error message', - ], - ], -]; - -// ... - -echo lang('Errors.errorEmailMissing'); diff --git a/user_guide_src/source/installation/upgrade_localization/ci3sample/002.php b/user_guide_src/source/installation/upgrade_localization/ci3sample/002.php deleted file mode 100644 index 9c2b650415d9..000000000000 --- a/user_guide_src/source/installation/upgrade_localization/ci3sample/002.php +++ /dev/null @@ -1,11 +0,0 @@ -lang->load('error', $lang); -echo $this->lang->line('error_email_missing'); diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst deleted file mode 100644 index c9e86a7fb8ba..000000000000 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ /dev/null @@ -1,87 +0,0 @@ -Upgrade Migrations -################## - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `Database Migrations Documentation CodeIgniter 3.x `_ -- :doc:`Database Migrations Documentation CodeIgniter 4.x ` - -What has been changed -===================== - -- First of all, the sequential naming (``001_create_users``, ``002_create_posts``) of migrations is no longer supported. - Version 4 of CodeIgniter only supports the timestamp scheme (``20121031100537_create_users``, - ``20121031500638_create_posts``). If you have used sequential naming, you have to rename each migration file. -- The migration table definition was changed. If you upgrade from CI3 to CI4 and use the same database, you need to - upgrade the migration table definition and its data. -- The migration procedure has also been changed. You can now migrate the database with a simple CLI command: - -.. code-block:: console - - php spark migrate - -Upgrade Guide -============= - -1. If your v3 project uses sequential migration names, you have to change those to timestamp names. -2. You have to move all migration files to the new folder **app/Database/Migrations**. -3. Remove the line ``defined('BASEPATH') OR exit('No direct script access allowed');`` if it exists. -4. Add this line just after the opening php tag: ``namespace App\Database\Migrations;``. -5. Below the ``namespace App\Database\Migrations;`` line add this line: ``use CodeIgniter\Database\Migration;`` -6. Replace ``extends CI_Migration`` with ``extends Migration``. -7. The method names within the ``Forge`` class have been changed to use camelCase. For example: - - - ``$this->dbforge->add_field`` to ``$this->forge->addField`` - - ``$this->dbforge->add_key`` to ``$this->forge->addKey`` - - ``$this->dbforge->create_table`` to ``$this->forge->createTable`` - - ``$this->dbforge->drop_table`` to ``$this->forge->dropTable`` - -8. (optional) You can change the array syntax from ``array(...)`` to ``[...]`` -9. Upgrade the migration table, if you use the same database. - - - **(development)** Run the CI4 migration in the development environment or similar, with a brand-new database, to - create the new migration table. - - **(development)** Export the migration table. - - **(production)** Drop (or rename) the existing CI3 migration table. - - **(production)** Import the new migration table and the data. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -Path: **application/migrations**: - -.. literalinclude:: upgrade_migrations/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -Path: **app/Database/Migrations**: - -.. literalinclude:: upgrade_migrations/001.php - -Search & Replace -================ - -You can use the following table to search & replace your old CI3 files. - -+------------------------------+----------------------------+ -| Search | Replace | -+==============================+============================+ -| extends CI_Migration | extends Migration | -+------------------------------+----------------------------+ -| $this->dbforge->add_field | $this->forge->addField | -+------------------------------+----------------------------+ -| $this->dbforge->add_key | $this->forge->addKey | -+------------------------------+----------------------------+ -| $this->dbforge->create_table | $this->forge->createTable | -+------------------------------+----------------------------+ -| $this->dbforge->drop_table | $this->forge->dropTable | -+------------------------------+----------------------------+ diff --git a/user_guide_src/source/installation/upgrade_migrations/001.php b/user_guide_src/source/installation/upgrade_migrations/001.php deleted file mode 100644 index 3f73906231f1..000000000000 --- a/user_guide_src/source/installation/upgrade_migrations/001.php +++ /dev/null @@ -1,35 +0,0 @@ -forge->addField([ - 'blog_id' => [ - 'type' => 'INT', - 'constraint' => 5, - 'unsigned' => true, - 'auto_increment' => true, - ], - 'blog_title' => [ - 'type' => 'VARCHAR', - 'constraint' => '100', - ], - 'blog_description' => [ - 'type' => 'TEXT', - 'null' => true, - ], - ]); - $this->forge->addKey('blog_id', true); - $this->forge->createTable('blog'); - } - - public function down() - { - $this->forge->dropTable('blog'); - } -} diff --git a/user_guide_src/source/installation/upgrade_migrations/ci3sample/001.php b/user_guide_src/source/installation/upgrade_migrations/ci3sample/001.php deleted file mode 100644 index 2437a8d5fa99..000000000000 --- a/user_guide_src/source/installation/upgrade_migrations/ci3sample/001.php +++ /dev/null @@ -1,33 +0,0 @@ -dbforge->add_field(array( - 'blog_id' => array( - 'type' => 'INT', - 'constraint' => 5, - 'unsigned' => true, - 'auto_increment' => true, - ), - 'blog_title' => array( - 'type' => 'VARCHAR', - 'constraint' => '100', - ), - 'blog_description' => array( - 'type' => 'TEXT', - 'null' => true, - ), - )); - $this->dbforge->add_key('blog_id', true); - $this->dbforge->create_table('blog'); - } - - public function down() - { - $this->dbforge->drop_table('blog'); - } -} diff --git a/user_guide_src/source/installation/upgrade_models.rst b/user_guide_src/source/installation/upgrade_models.rst deleted file mode 100644 index 6e558f7ca331..000000000000 --- a/user_guide_src/source/installation/upgrade_models.rst +++ /dev/null @@ -1,68 +0,0 @@ -Upgrade Models -############## - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `Model Documentation CodeIgniter 3.x `_ -- :doc:`Model Documentation CodeIgniter 4.x ` - -What has been changed -===================== - -- The CI4 model has much more functionality, including automatic database connection, basic CRUD, in-model validation, - and automatic pagination. -- Since namespaces have been added to CodeIgniter 4, the models must be changed to support namespaces. - -Upgrade Guide -============= - -1. First, move all model files to the folder **app/Models**. -2. Add this line just after the opening php tag: ``namespace App\Models;``. -3. Below the ``namespace App\Models;`` line add this line: ``use CodeIgniter\Model;``. -4. Replace ``extends CI_Model`` with ``extends Model``. -5. Add the ``protected $table`` property and set the table name. -6. Add the ``protected $allowedFields`` property and set the array of field names to allow to insert/update. -7. Instead of CI3's ``$this->load->model('x');``, you would now use ``$this->x = new X();``, following namespaced - conventions for your component. Alternatively, you can use the :php:func:`model()` function: - ``$this->x = model('X');``. - -If you use sub-directories in your model structure, you have to change the namespace accordingly. For example, if you -have a version 3 model located in **application/models/users/user_contact.php**, the namespace has to be -``namespace App\Models\Users;`` and the model path in version 4 should look like this: -**app/Models/Users/UserContact.php** - -The new Model in CI4 has a lot of built-in methods, for example, the ``find($id)`` method. With this, you can find data -where the primary key is equal to ``$id``. Inserting data is also easier than before. In CI4 there is an -``insert($data)`` method. You can optionally make use of all those built-in methods and migrate your code to the new -methods. - -You can find more information on those methods in :doc:`../models/model`. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -Path: **application/models**: - -.. literalinclude:: upgrade_models/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -Path: **app/Models**: - -.. literalinclude:: upgrade_models/001.php - -The above code is a direct translation from CI3 to CI4. It uses Query Builder directly in the model. Note that when you -use Query Builder directly, you cannot use features in CodeIgniter's Model. - -If you want to use CodeIgniter's Model features, the code will be: - -.. literalinclude:: upgrade_models/002.php diff --git a/user_guide_src/source/installation/upgrade_models/001.php b/user_guide_src/source/installation/upgrade_models/001.php deleted file mode 100644 index a09dfdfbc215..000000000000 --- a/user_guide_src/source/installation/upgrade_models/001.php +++ /dev/null @@ -1,23 +0,0 @@ - $title, - 'slug' => $slug, - 'text' => $text, - ]; - - // Gets the Query Builder for the table, and calls `insert()`. - return $this->builder()->insert($data); - } -} diff --git a/user_guide_src/source/installation/upgrade_models/002.php b/user_guide_src/source/installation/upgrade_models/002.php deleted file mode 100644 index a34937f1f180..000000000000 --- a/user_guide_src/source/installation/upgrade_models/002.php +++ /dev/null @@ -1,26 +0,0 @@ - $title, - 'slug' => $slug, - 'text' => $text, - ]; - - // Uses Model's`insert()` method. - return $this->insert($data); - } -} diff --git a/user_guide_src/source/installation/upgrade_models/ci3sample/001.php b/user_guide_src/source/installation/upgrade_models/ci3sample/001.php deleted file mode 100644 index d9f3a3d7d2d2..000000000000 --- a/user_guide_src/source/installation/upgrade_models/ci3sample/001.php +++ /dev/null @@ -1,15 +0,0 @@ - $title, - 'slug' => $slug, - 'text' => $text, - ); - - return $this->db->insert('news', $data); - } -} diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst deleted file mode 100644 index b24739a96737..000000000000 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ /dev/null @@ -1,44 +0,0 @@ -Upgrade Pagination -################## - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `Pagination Class Documentation CodeIgniter 3.x `_ -- :doc:`Pagination Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- You have to change the views and also the controller in order to use the new pagination library. -- If you want to customize the pagination links, you need to create View Templates. -- In CI4 the pagination uses the actual page number only. You can't use the starting index (offset) for the items, which - is the default in CI3. -- If you use :doc:`CodeIgniter\\Model `, you can use the built-in method in the Model class. - -Upgrade Guide -============= -1. Within the views, change the following: - - - ``pagination->create_links(); ?>`` to ``links() ?>`` - -2. Within the controller, you have to make the following changes: - - - You can use the built-in ``paginate()`` method on every Model. Have a look at the code example below to see how to - set up the pagination on a specific model. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_pagination/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_pagination/001.php diff --git a/user_guide_src/source/installation/upgrade_pagination/001.php b/user_guide_src/source/installation/upgrade_pagination/001.php deleted file mode 100644 index 62710360fca9..000000000000 --- a/user_guide_src/source/installation/upgrade_pagination/001.php +++ /dev/null @@ -1,10 +0,0 @@ - $model->paginate(10), - 'pager' => $model->pager, -]; - -return view('users/index', $data); diff --git a/user_guide_src/source/installation/upgrade_pagination/ci3sample/001.php b/user_guide_src/source/installation/upgrade_pagination/ci3sample/001.php deleted file mode 100644 index 37a6f849c67c..000000000000 --- a/user_guide_src/source/installation/upgrade_pagination/ci3sample/001.php +++ /dev/null @@ -1,13 +0,0 @@ -load->library('pagination'); -$config['base_url'] = base_url().'users/index/'; -$config['total_rows'] = $this->db->count_all('users'); -$config['per_page'] = 10; -$config['uri_segment'] = 3; -$config['attributes'] = array('class' => 'pagination-link'); -$this->pagination->initialize($config); - -$data['users'] = $this->user_model->get_users(FALSE, $config['per_page'], $offset); - -$this->load->view('posts/index', $data); diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst deleted file mode 100644 index 0ae2b33b1ae5..000000000000 --- a/user_guide_src/source/installation/upgrade_responses.rst +++ /dev/null @@ -1,37 +0,0 @@ -Upgrade Output Class -#################### - -.. contents:: - :local: - :depth: 2 - -Documentation -============= -- `Output Class Documentation CodeIgniter 3.x `_ -- :doc:`HTTP Responses Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- The Output class has been changed to the Response class. -- The methods have been renamed. - -Upgrade Guide -============= -1. The methods in the HTTP Response class are named slightly differently. The most important change in the naming is the - switch from underscored method names to camelCase. The method ``set_content_type()`` from version 3 is now named - ``setContentType()`` and so on. -2. In most cases, you have to change ``$this->output`` to ``$this->response`` followed by the method. You can find all - methods in :doc:`../outgoing/response`. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_responses/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_responses/001.php diff --git a/user_guide_src/source/installation/upgrade_responses/001.php b/user_guide_src/source/installation/upgrade_responses/001.php deleted file mode 100644 index 469c1c1467f2..000000000000 --- a/user_guide_src/source/installation/upgrade_responses/001.php +++ /dev/null @@ -1,7 +0,0 @@ -response->setStatusCode(404); - -// ... - -return $this->response->setJSON(['foo' => 'bar']); diff --git a/user_guide_src/source/installation/upgrade_responses/ci3sample/001.php b/user_guide_src/source/installation/upgrade_responses/ci3sample/001.php deleted file mode 100644 index 74ff3a5dc5c8..000000000000 --- a/user_guide_src/source/installation/upgrade_responses/ci3sample/001.php +++ /dev/null @@ -1,9 +0,0 @@ -output->set_status_header(404); - -// ... - -$this->output - ->set_content_type('application/json') - ->set_output(json_encode(array('foo' => 'bar'))); diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst deleted file mode 100644 index 71ab8b05099d..000000000000 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ /dev/null @@ -1,55 +0,0 @@ -Upgrade Routing -############### - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `URI Routing Documentation CodeIgniter 3.x `_ -- :doc:`URI Routing Documentation CodeIgniter 4.x ` - -What has been changed -===================== - -- In CI4 the Auto Routing is disabled by default. -- In CI4 the new more secure :ref:`auto-routing-improved` is introduced. -- In CI4 the routing is no longer configured by setting the routes as an array. -- The Wildcard ``(:any)`` in CI3 will be the Placeholder ``(:segment)`` in CI4. The ``(:any)`` in CI4 matches multiple - segments. See :ref:`URI Routing `. - -Upgrade Guide -============= - -1. If you use the Auto Routing in the same way as CI3, you need to enable :ref:`auto-routing-legacy`. -2. You have to change the syntax of each routing line and append it in **app/Config/Routes.php**. For example: - - - ``$route['journals'] = 'blogs';`` to ``$routes->add('journals', 'Blogs::index');``. This would map to the - ``index()`` method in the ``Blogs`` controller. - - ``$route['product/(:any)'] = 'catalog/product_lookup';`` to - ``$routes->add('product/(:segment)', 'Catalog::productLookup');``. Don't forget to replace ``(:any)`` with - ``(:segment)``. - - ``$route['login/(.+)'] = 'auth/login/$1';`` to ``$routes->add('login/(.+)', 'Auth::login/$1');`` - - .. note:: For backward compatibility, ``$routes->add()`` is used here. But we strongly recommend using - :ref:`routing-http-verb-routes` like ``$routes->get()`` instead of ``$routes->add()`` for security. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ -Path: **application/config/routes.php**: - -.. literalinclude:: upgrade_routing/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ -Path: **app/Config/Routes.php**: - -.. literalinclude:: upgrade_routing/001.php - -.. note:: For backward compatibility, ``$routes->add()`` is used here. But we strongly recommend using - :ref:`routing-http-verb-routes` like ``$routes->get()`` instead of ``$routes->add()`` for security. diff --git a/user_guide_src/source/installation/upgrade_routing/001.php b/user_guide_src/source/installation/upgrade_routing/001.php deleted file mode 100644 index 59450f4863e2..000000000000 --- a/user_guide_src/source/installation/upgrade_routing/001.php +++ /dev/null @@ -1,16 +0,0 @@ -get('/', 'Home::index'); - -$routes->add('posts/index', 'Posts::index'); -$routes->add('teams/create', 'Teams::create'); -$routes->add('teams/update', 'Teams::update'); - -$routes->add('posts/create', 'Posts::create'); -$routes->add('posts/update', 'Posts::update'); -$routes->add('drivers/create', 'Drivers::create'); -$routes->add('drivers/update', 'Drivers::update'); -$routes->add('posts/(:segment)', 'Posts::view/$1'); diff --git a/user_guide_src/source/installation/upgrade_routing/ci3sample/001.php b/user_guide_src/source/installation/upgrade_routing/ci3sample/001.php deleted file mode 100644 index c4facdd8ff03..000000000000 --- a/user_guide_src/source/installation/upgrade_routing/ci3sample/001.php +++ /dev/null @@ -1,14 +0,0 @@ -`_ -- :doc:`Security Documentation CodeIgniter 4.x ` - -.. note:: - If you use the :doc:`../helpers/form_helper` and enable the CSRF filter globally, then :php:func:`form_open()` will - automatically insert a hidden CSRF field in your forms. So you do not have to upgrade this by yourself. - -What has been changed -===================== -- The method to implement CSRF tokens to HTML forms has been changed. - -Upgrade Guide -============= -1. To enable CSRF protection in CI4, you have to enable it in **app/Config/Filters.php**: - - .. literalinclude:: upgrade_security/001.php - -2. Within your HTML forms you have to remove the CSRF input field which looks similar to - ````. -3. Now, within your HTML forms you have to add ```` somewhere in the form body, unless you are using - ``form_open()``. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_security/ci3sample/002.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_security/002.php diff --git a/user_guide_src/source/installation/upgrade_security/001.php b/user_guide_src/source/installation/upgrade_security/001.php deleted file mode 100644 index c7c907966f0b..000000000000 --- a/user_guide_src/source/installation/upgrade_security/001.php +++ /dev/null @@ -1,19 +0,0 @@ - [ - // 'honeypot', - 'csrf', - ], - ]; - - // ... -} diff --git a/user_guide_src/source/installation/upgrade_security/002.php b/user_guide_src/source/installation/upgrade_security/002.php deleted file mode 100644 index 89c3b3882c56..000000000000 --- a/user_guide_src/source/installation/upgrade_security/002.php +++ /dev/null @@ -1,8 +0,0 @@ -
- - - - - - -
diff --git a/user_guide_src/source/installation/upgrade_security/ci3sample/002.php b/user_guide_src/source/installation/upgrade_security/ci3sample/002.php deleted file mode 100644 index 1f8a82a0855f..000000000000 --- a/user_guide_src/source/installation/upgrade_security/ci3sample/002.php +++ /dev/null @@ -1,17 +0,0 @@ - $this->security->get_csrf_token_name(), - 'hash' => $this->security->get_csrf_hash() -); - -?> - -
- - - - - - -
diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst deleted file mode 100644 index 843d2d730f83..000000000000 --- a/user_guide_src/source/installation/upgrade_sessions.rst +++ /dev/null @@ -1,46 +0,0 @@ -Upgrade Sessions -################ - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `Session Library Documentation CodeIgniter 3.x `_ -- :doc:`Session Library Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- Only small things like the method names and the loading of the library have changed. -- The definition of the session table in Database Driver has changed. - -Upgrade Guide -============= -1. Wherever you use the Session Library, replace ``$this->load->library('session');`` with ``$session = session();``. -2. From then on, you have to replace ``$this->session`` with ``$session``, followed by the new method name, in every - line starting with it. - - - To access session data, use the syntax ``$session->item`` or ``$session->get('item')`` instead of the CI3 syntax - ``$this->session->name``. - - To set data, use ``$session->set($array);`` instead of ``$this->session->set_userdata($array);``. - - To remove data, use ``unset($_SESSION['some_name']);`` or ``$session->remove('some_name');`` instead of - ``$this->session->unset_userdata('some_name');``. - - To mark session data as flashdata, which will only be available for the next request, use - ``$session->markAsFlashdata('item');`` instead of ``$this->session->mark_as_flash('item');`` - -3. If you use Database Driver, you need to recreate the session table. See :ref:`sessions-databasehandler-driver`. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_sessions/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_sessions/001.php diff --git a/user_guide_src/source/installation/upgrade_sessions/001.php b/user_guide_src/source/installation/upgrade_sessions/001.php deleted file mode 100644 index 9ac867e4e814..000000000000 --- a/user_guide_src/source/installation/upgrade_sessions/001.php +++ /dev/null @@ -1,8 +0,0 @@ -get('item'); -$session->item; -session('item'); diff --git a/user_guide_src/source/installation/upgrade_sessions/ci3sample/001.php b/user_guide_src/source/installation/upgrade_sessions/ci3sample/001.php deleted file mode 100644 index 73e69c5dfa9f..000000000000 --- a/user_guide_src/source/installation/upgrade_sessions/ci3sample/001.php +++ /dev/null @@ -1,7 +0,0 @@ -load->library('session'); - -$_SESSION['item']; -$this->session->item; -$this->session->userdata('item'); diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst deleted file mode 100644 index 75921df4f524..000000000000 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ /dev/null @@ -1,125 +0,0 @@ -Upgrade Validations -################### - -.. contents:: - :local: - :depth: 2 - -Library Documentation -===================== - -- `Form Validation Documentation CodeIgniter 3.x `_ -- :doc:`Validation Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- If you want to change validation error display, you have to set CI4 - :ref:`validation View templates `. -- CI4 validation has no - `Callbacks `_ - as in CI3. Use :ref:`Callable Rules ` (since v4.5.0) or - :ref:`Closure Rules ` (since v4.3.0) or - :ref:`Rule Classes ` instead. -- In CI3, Callbacks/Callable rules were prioritized, but in CI4, Closure/Callable Rules are not prioritized, and are - checked in the order in which they are listed. -- Since v4.5.0, :ref:`Callable Rules ` have been introduced, but it is a bit different - from CI3's - `Callable `_. -- CI4 validation format rules do not permit an empty string. -- CI4 validation never changes your data. -- Since v4.3.0, :php:func:`validation_errors()` has been introduced, but the API is different from CI3's. - -Upgrade Guide -============= -1. Within the view which contains the form, you have to change: - - - ```` to ```` - -2. Within the controller, you have to change the following: - - - ``$this->load->helper(array('form', 'url'));`` to ``helper('form');`` - - remove the line ``$this->load->library('form_validation');`` - - ``if ($this->form_validation->run() == FALSE)`` to ``if (! $this->validateData($data, $rules))`` where ``$data`` is - the data to validate, typically, the POST data ``$this->request->getPost()``. - - ``$this->load->view('myform');`` to ``return view('myform', ['validation' => $this->validator,]);`` - -3. You have to change the validation rules. The new syntax is to set the rules as an array in the controller: - - .. literalinclude:: upgrade_validations/001.php - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ -Path: **application/views**:: - - - - My Form - - - - - - - -
Username
- - -
Password
- - -
Password Confirm
- - -
Email Address
- - -
- - - - - - -Path: **application/controllers**: - -.. literalinclude:: upgrade_validations/ci3sample/002.php - -CodeIgniter Version 4.x ------------------------ -Path: **app/Views**:: - - - - My Form - - - - - - - -
Username
- - -
Password
- - -
Password Confirm
- - -
Email Address
- - -
- - - - - - -Path: **app/Controllers**: - -.. literalinclude:: upgrade_validations/002.php diff --git a/user_guide_src/source/installation/upgrade_validations/001.php b/user_guide_src/source/installation/upgrade_validations/001.php deleted file mode 100644 index 0ba9b034708f..000000000000 --- a/user_guide_src/source/installation/upgrade_validations/001.php +++ /dev/null @@ -1,7 +0,0 @@ -validateData($data, [ - 'name' => 'required|min_length[3]', - 'email' => 'required|valid_email', - 'phone' => 'required|numeric|max_length[10]', -]); diff --git a/user_guide_src/source/installation/upgrade_validations/002.php b/user_guide_src/source/installation/upgrade_validations/002.php deleted file mode 100644 index b3cd4f9db13d..000000000000 --- a/user_guide_src/source/installation/upgrade_validations/002.php +++ /dev/null @@ -1,23 +0,0 @@ -request->getPost(); - - if (! $this->validateData($data, [ - // Validation rules - ])) { - return view('myform'); - } - - return view('formsuccess'); - } -} diff --git a/user_guide_src/source/installation/upgrade_validations/ci3sample/002.php b/user_guide_src/source/installation/upgrade_validations/ci3sample/002.php deleted file mode 100644 index 3c6505455d91..000000000000 --- a/user_guide_src/source/installation/upgrade_validations/ci3sample/002.php +++ /dev/null @@ -1,19 +0,0 @@ -load->helper(array('form', 'url')); - - $this->load->library('form_validation'); - - // Set validation rules - - if ($this->form_validation->run() == FALSE) { - $this->load->view('myform'); - } else { - $this->load->view('formsuccess'); - } - } -} diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst deleted file mode 100644 index 4fc50dbedb49..000000000000 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ /dev/null @@ -1,37 +0,0 @@ -Upgrade View Parser -################### - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `Template Parser Documentation CodeIgniter 3.x `_ -- :doc:`View Parser Documentation CodeIgniter 4.x ` - -What has been changed -===================== -- You have to change the implementation and loading of the Parser Library. -- The Views can be copied from CI3. Usually, no changes are required there. - -Upgrade Guide -============= -1. Wherever you use the View Parser Library, replace ``$this->load->library('parser');`` with - ``$parser = service('parser');``. -2. You have to change the render part in your controller from ``$this->parser->parse('blog_template', $data);`` to - ``return $parser->setData($data)->render('blog_template');``. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -.. literalinclude:: upgrade_view_parser/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -.. literalinclude:: upgrade_view_parser/001.php diff --git a/user_guide_src/source/installation/upgrade_view_parser/001.php b/user_guide_src/source/installation/upgrade_view_parser/001.php deleted file mode 100644 index 9acf5e9449d8..000000000000 --- a/user_guide_src/source/installation/upgrade_view_parser/001.php +++ /dev/null @@ -1,10 +0,0 @@ - 'My Blog Title', - 'blog_heading' => 'My Blog Heading', -]; - -return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/installation/upgrade_view_parser/ci3sample/001.php b/user_guide_src/source/installation/upgrade_view_parser/ci3sample/001.php deleted file mode 100644 index c44e00968315..000000000000 --- a/user_guide_src/source/installation/upgrade_view_parser/ci3sample/001.php +++ /dev/null @@ -1,11 +0,0 @@ -load->library('parser'); - -$data = array( - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading' -); - -$this->parser - ->parse('blog_template', $data); diff --git a/user_guide_src/source/installation/upgrade_views.rst b/user_guide_src/source/installation/upgrade_views.rst deleted file mode 100644 index 6f15c019ab1c..000000000000 --- a/user_guide_src/source/installation/upgrade_views.rst +++ /dev/null @@ -1,50 +0,0 @@ -Upgrade Views -############# - -.. contents:: - :local: - :depth: 2 - -Documentation -============= - -- `View Documentation CodeIgniter 3.x `_ -- :doc:`View Documentation CodeIgniter 4.x ` - -What has been changed -===================== - -- Your views look much like before, but they are invoked differently: instead of CI3's ``$this->load->view('x');``, you - can use ``return view('x');``. -- CI4 supports :doc:`../outgoing/view_cells` to build your response in pieces, and :doc:`../outgoing/view_layouts` for - page layout. -- The :doc:`Template Parser <../outgoing/view_parser>` is still there, and substantially enhanced. - -Upgrade Guide -============= - -1. First, move all views to the folder **app/Views**. -2. Change the loading syntax of views in every script where you load views: - - - from ``$this->load->view('directory_name/file_name')`` to ``return view('directory_name/file_name');`` - - from ``$content = $this->load->view('file', $data, TRUE);`` to ``$content = view('file', $data);`` - -3. (optional) You can change the echo syntax in views from ```` to ```` -4. Remove the line ``defined('BASEPATH') OR exit('No direct script access allowed');`` if it exists. - -Code Example -============ - -CodeIgniter Version 3.x ------------------------ - -Path: **application/views**: - -.. literalinclude:: upgrade_views/ci3sample/001.php - -CodeIgniter Version 4.x ------------------------ - -Path: **app/Views**: - -.. literalinclude:: upgrade_views/001.php diff --git a/user_guide_src/source/installation/upgrade_views/001.php b/user_guide_src/source/installation/upgrade_views/001.php deleted file mode 100644 index d4d043fea310..000000000000 --- a/user_guide_src/source/installation/upgrade_views/001.php +++ /dev/null @@ -1,17 +0,0 @@ - - - <?= esc($title) ?> - - -

- -

My Todo List

- -
    - -
  • - -
- - - diff --git a/user_guide_src/source/installation/upgrade_views/ci3sample/001.php b/user_guide_src/source/installation/upgrade_views/ci3sample/001.php deleted file mode 100644 index bbabef2d1819..000000000000 --- a/user_guide_src/source/installation/upgrade_views/ci3sample/001.php +++ /dev/null @@ -1,17 +0,0 @@ - - - <?php echo html_escape($title); ?> - - -

- -

My Todo List

- -
    - -
  • - -
- - - diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst deleted file mode 100644 index 471195d91b08..000000000000 --- a/user_guide_src/source/installation/upgrading.rst +++ /dev/null @@ -1,86 +0,0 @@ -################################# -Upgrading From a Previous Version -################################# - -Please read the upgrade notes corresponding to the version you are upgrading from. - -See also :doc:`./backward_compatibility_notes`. - -The manual mentions changes to the **project space**. To perform the update, you need to compare the original files from -**vendor/codeigniter4/framework** or from the ZIP archive and make changes. - -For example, the original **app/Config/App.php** will be located in -**vendor/codeigniter4/framework/app/Config/App.php**. Alternatively, replace it with a new file and add your previous -lines. - -.. note:: If you don't know what version of CodeIgniter you are currently running, you can get it from - :ref:`the Debug Toolbar `, or simply echo the constant ``\CodeIgniter\CodeIgniter::CI_VERSION``. - -.. toctree:: - :titlesonly: - - backward_compatibility_notes - - upgrade_477 - upgrade_476 - upgrade_475 - upgrade_474 - upgrade_473 - upgrade_472 - upgrade_471 - upgrade_470 - upgrade_465 - upgrade_464 - upgrade_463 - upgrade_462 - upgrade_461 - upgrade_460 - upgrade_458 - upgrade_457 - upgrade_456 - upgrade_455 - upgrade_454 - upgrade_453 - upgrade_452 - upgrade_451 - upgrade_450 - upgrade_448 - upgrade_447 - upgrade_446 - upgrade_445 - upgrade_444 - upgrade_443 - upgrade_442 - upgrade_441 - upgrade_440 - upgrade_438 - upgrade_437 - upgrade_436 - upgrade_435 - upgrade_434 - upgrade_433 - upgrade_432 - upgrade_431 - upgrade_430 - upgrade_4212 - upgrade_4211 - upgrade_4210 - upgrade_428 - upgrade_427 - upgrade_426 - upgrade_425 - upgrade_423 - upgrade_422 - upgrade_421 - upgrade_420 - upgrade_418 - upgrade_417 - upgrade_416 - upgrade_415 - upgrade_414 - upgrade_413 - upgrade_412 - upgrade_410 - upgrade_405 - upgrade_404 - upgrade_4xx diff --git a/user_guide_src/source/installation/worker_mode.rst b/user_guide_src/source/installation/worker_mode.rst deleted file mode 100644 index b108f2caa17f..000000000000 --- a/user_guide_src/source/installation/worker_mode.rst +++ /dev/null @@ -1,331 +0,0 @@ -########### -Worker Mode -########### - -.. contents:: - :local: - :depth: 2 - -.. versionadded:: 4.7.0 - -.. important:: Worker Mode is currently **experimental**. The only officially supported worker implementation is - **FrankenPHP**, which is backed by the PHP Foundation. - -************ -Introduction -************ - -What is Worker Mode? -==================== - -Worker Mode is a performance optimization feature that allows CodeIgniter to handle multiple HTTP requests within the -same bootstrapped application. PHP-FPM also reuses worker processes, but normally initializes and tears down the -application for each request. - -Traditional PHP vs Worker Mode ------------------------------- - -**Traditional PHP (PHP-FPM)** - -In traditional PHP, each HTTP request goes through this cycle: - -1. Web server receives the request and passes it to an available PHP-FPM worker process -2. PHP loads the required files, using cached bytecode when OPcache is enabled -3. Framework bootstraps: autoloader, configuration, services, routes -4. Database connections are established -5. Request is processed and response is sent -6. Request resources are released, including non-persistent connections -7. Application state is torn down, and the worker process can handle another request - -This "shared nothing" architecture is simple and safe, but inefficient for high-traffic applications because steps 2-4 -repeat for every single request. - -**Worker Mode** - -In Worker Mode, the lifecycle changes dramatically: - -1. Worker process starts and performs one-time initialization: - - - Loads and parses all required files (cached in OPcache) - - Bootstraps framework: autoloader, configuration, services, routes - - Establishes database and cache connections - -2. For each incoming request: - - - Reuses existing connections and cached resources - - Resets only request-specific state (superglobals, request/response objects) - - Processes request and sends response - - Cleans up request-specific data - -3. Worker continues running, ready for the next request - -This approach eliminates redundant initialization work and connection overhead, resulting in -**2-3x performance improvements** for typical database-driven applications. - -How CodeIgniter Manages State -============================= - -The key challenge in Worker Mode is preventing state from leaking between requests. CodeIgniter handles this through -several mechanisms: - -**Services Reset** - Most services are destroyed and recreated for each request. Only services listed - in ``$persistentServices`` survive between requests. - -**Factories Reset** - All Factories (Models, Config instances) are reset between requests, - ensuring fresh instances without stale data. - -**Superglobals Isolation** - Request data (``$_GET``, ``$_POST``, ``$_SERVER``, etc.) is properly isolated - per request through the Superglobals service. - -**Connection Persistence** - Database and cache connections are validated at request start and reused if healthy. - Unhealthy connections are automatically re-established. - -*************** -Getting Started -*************** - -Installation -============ - -1. Install FrankenPHP following the `official documentation `_ - - You can use a static binary or Docker. Here, we assume a static binary, which can be - `downloaded directly `_. - -2. Install the Worker Mode template files using the spark command: - - .. code-block:: console - - php spark worker:install - - This command creates two files: - - - **Caddyfile** - FrankenPHP configuration file with worker mode enabled - - **public/frankenphp-worker.php** - Worker entry point that handles the request loop - -3. Configure your worker settings in **app/Config/WorkerMode.php** if needed. The defaults are recommended for most - applications. - -.. note:: When changing the project directory, see the section :ref:`renaming-app-directory` and update your - **public/frankenphp-worker.php**. - -Running the Worker -================== - -Start FrankenPHP using the generated Caddyfile: - -.. code-block:: console - - frankenphp run - -The server will start with worker mode enabled, handling requests through the worker entry point. - -To run in the background (daemon mode): - -.. code-block:: console - - frankenphp start - -Uninstalling -============ - -To remove the Worker Mode template files: - -.. code-block:: console - - php spark worker:uninstall - -This removes the **Caddyfile** and **public/frankenphp-worker.php** files. - -********************** -Performance Benchmarks -********************** - -Worker Mode typically provides **2-3x performance improvements** for database-driven applications. The actual gains -depend on your application's characteristics: - -===================== ===================================================================== -Scenario Expected Improvement -===================== ===================================================================== -**Simple endpoints** Applications returning minimal JSON responses show modest - improvements (10-30%), as there's little bootstrap overhead - to eliminate. -**Database queries** Endpoints performing database queries typically see **2-3x** - improvements from connection reuse and reduced initialization - overhead. -**Complex bootstrap** Applications with many services, routes, or configuration see - the largest gains, as this overhead is eliminated entirely. -===================== ===================================================================== - -Worker Count Considerations -=========================== - -Total throughput scales with worker count. Match worker count to your typical concurrency patterns and available CPU -cores. Too few workers limit concurrency; too many waste memory. - -First Request Latency -===================== - -The initial request to each worker is slower due to bootstrap and connection establishment. Subsequent requests benefit -from cached resources and persistent connections. - -************* -Configuration -************* - -All worker mode configuration is managed through the **app/Config/WorkerMode.php** file. - -Configuration Options -===================== - -=========================== ======= ====================================================================== -Option Type Description -=========================== ======= ====================================================================== -**$persistentServices** array Services that persist across requests and are not reset. Services not - in this list are destroyed after each request to prevent state leakage. - Default: ``['autoloader', 'locator', 'exceptions', 'commands', - 'codeigniter', 'superglobals', 'routes', 'cache']`` -**$resetEventListeners** array Event names whose listeners are removed between requests. Use this - when you register event listeners inside other event callbacks rather - than at the top level of **Config/Events.php**, which would cause them - to accumulate across requests. Default: ``[]`` -**$forceGarbageCollection** bool Whether to force garbage collection after each request. - ``true`` (default, recommended): Prevents memory leaks. - ``false``: Relies on PHP's automatic garbage collection. -=========================== ======= ====================================================================== - -Persistent Services -=================== - -The ``$persistentServices`` array controls which services survive between requests. The default configuration includes: - -================ ========================================================================== -Service Purpose -================ ========================================================================== -``autoloader`` PSR-4 autoloading configuration. Safe to persist as class maps don't change. -``locator`` File locator for finding framework files. Caches file paths for performance. -``exceptions`` Exception handler. Stateless, safe to reuse. -``commands`` CLI commands registry. Only used during worker startup. -``codeigniter`` Main application instance. Orchestrates the request/response cycle. -``superglobals`` Superglobals wrapper. Properly isolated per request internally. -``routes`` Router configuration. Route definitions don't change between requests. -``cache`` Cache service. Maintains connections to cache backends (Redis, Memcached). -================ ========================================================================== - -.. warning:: Adding services to ``$persistentServices`` without understanding their state management can cause data - leakage between requests. Only persist services that are truly stateless or manage their own request isolation. - -.. _worker-mode-reset-event-listeners: - -Reset Event Listeners -===================== - -.. versionadded:: 4.7.1 - -Event listeners registered at the top level of **Config/Events.php** are loaded once at worker startup and persist -correctly across requests. However, if you register a listener inside another event's callback, it will be re-registered -on every request and accumulate: - -.. literalinclude:: worker_mode/001.php - -To clean up such listeners between requests, add the event name to ``$resetEventListeners`` in -**app/Config/WorkerMode.php**: - -.. literalinclude:: worker_mode/002.php - -.. note:: The recommended approach is to register listeners at the top level of **Config/Events.php** instead of inside - callbacks. Use ``$resetEventListeners`` only when registering inside a callback is unavoidable. - -********************** -Optimize Configuration -********************** - -The ``app/Config/Optimize.php`` configuration options (Config Caching and File Locator Caching) should **NOT** be used -with Worker Mode. - -These optimizations were designed for traditional PHP where each request starts fresh. In Worker Mode, the persistent -process already provides these benefits naturally, and enabling them can cause issues with stale data. - -.. warning:: Do not enable ``$configCacheEnabled`` or ``$locatorCacheEnabled`` in **app/Config/Optimize.php** when using - Worker Mode. - -OPcache Settings -================ - -Worker Mode benefits significantly from OPcache. Ensure it's enabled and properly configured: - -.. code-block:: ini - - opcache.enable=1 - opcache.memory_consumption=256 - opcache.max_accelerated_files=20000 - opcache.validate_timestamps=0 ; In production only - -************************ -Important Considerations -************************ - -State Management -================ - -Since the PHP process persists across requests, careful attention to state management is essential: - -- **Avoid static properties** for request-specific data, as these persist between requests -- **Be cautious with singletons** that might retain request state -- **Clean up resources** like file handles and database cursors after each request -- **Don't store user data** in class properties that persist across requests - -Registrars -========== - -Config registrars (``Config/Registrar.php`` files) work correctly in Worker Mode. Registrar files are discovered once -when the worker starts, and registrar logic is applied every time a Config class is instantiated. Each request gets a -fresh Config instance with registrars applied. - -Memory Management -================= - -Monitor memory usage: - -.. code-block:: console - - ps aux | grep frankenphp - -If memory grows continuously: - -- Verify garbage collection is enabled (``$forceGarbageCollection = true``) -- Ensure resources are properly closed after use -- Unset large objects when no longer needed -- Check for circular references that prevent garbage collection - -Debugging -========= - -Worker Mode can make debugging more challenging since the process persists across requests: - -- **Restart workers after code changes** - workers don't auto-reload modified files -- **Check logs** in **writable/logs/** for connection and state-related issues -- **Use logging liberally** to trace request flow across the persistent process - -Session and Cache Handlers -========================== - -**File-based handlers** may experience file locking contention between workers. For production environments, consider -using: - -- **Redis** or **Memcached** for sessions and cache -- These provide better concurrency and automatic connection persistence - -Database Connections -==================== - -Database connections are automatically managed: - -- Connections persist across requests for performance -- Connections are validated at the start of each request -- Failed connections are automatically re-established -- Uncommitted transactions are automatically rolled back with a warning logged diff --git a/user_guide_src/source/installation/worker_mode/001.php b/user_guide_src/source/installation/worker_mode/001.php deleted file mode 100644 index 3140208b9e95..000000000000 --- a/user_guide_src/source/installation/worker_mode/001.php +++ /dev/null @@ -1,8 +0,0 @@ -`_. The framework was written for performance -in the real world, with many of the original class libraries, helpers, and subsystems borrowed from the codebase of -`ExpressionEngine `_. It was, for years, developed and maintained by EllisLab, the -ExpressionEngine Development Team and a group of community members called the Reactor Team. - -In 2014, CodeIgniter was acquired by the `British Columbia Institute of Technology `_ and was then -officially announced as a community-maintained project. - -In 2019, the CodeIgniter Foundation was formed to provide a perpetual managing group separate from any other entity to -help ensure the framework's future. diff --git a/user_guide_src/source/intro/index.rst b/user_guide_src/source/intro/index.rst deleted file mode 100644 index 4a8e46835ec8..000000000000 --- a/user_guide_src/source/intro/index.rst +++ /dev/null @@ -1,46 +0,0 @@ -####################### -Welcome to CodeIgniter4 -####################### - -CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure. - -It is an Application Development Framework - a toolkit - for people who build websites using PHP. Its goal is to enable -you to develop projects much faster than you could if you were writing code from scratch, by providing a rich set of -libraries for commonly needed tasks, as well as a simple interface and logical structure to access these libraries. - -CodeIgniter lets you creatively focus on your project by minimizing the amount of code needed for a given task. - -CodeIgniter has been kept as flexible as possible, allowing you to work the way you want, without being forced into -working any certain way. Core parts of the framework can be easily extended or completely replaced to make the system -work the way you need it to. - -In short, CodeIgniter is the malleable framework that tries to provide the tools you need while staying out of the way. - -***************************** -Is CodeIgniter Right for You? -***************************** - -CodeIgniter is right for you if: - -- You want a framework with a small footprint. -- You need exceptional performance. -- You want a framework that incorporates a number of features and techniques to enable you to follow good security - practices easily. -- You want a non-magical framework with source code that is easy to find and read. -- You want a framework that requires nearly zero configuration. -- You want a framework that does not require you to adhere to restrictive coding rules. -- You want a framework that makes it easy to create test code. -- You do not want to be forced to learn a templating language (although a template parser is optionally available if - you desire one). -- You eschew complexity, favoring simple solutions. -- You need clear, thorough documentation. - -.. toctree:: - :hidden: - :titlesonly: - - self - requirements - credits - psr - License Agreement <../license> diff --git a/user_guide_src/source/intro/psr.rst b/user_guide_src/source/intro/psr.rst deleted file mode 100644 index c2b615ac23c1..000000000000 --- a/user_guide_src/source/intro/psr.rst +++ /dev/null @@ -1,47 +0,0 @@ -************** -PSR Compliance -************** - -The `PHP-FIG `_ was created in 2009 to help make code more interoperable between frameworks by -ratifying interfaces, style guides, and more that members were free to implement or not. While CodeIgniter is not a -member of the FIG, we are compatible with a number of their proposals. This guide is meant to list the status of our -compliance with the various accepted, and some draft, proposals. - -**PSR-1: Basic Coding Standard** - -This recommendation covers basic class, method, and file-naming standards. Our -`style guide `_ meets PSR-1 and -adds its own requirements on top of it. - -**PSR-12: Extended Coding Style** - -Our `style guide `_ follows the -recommendation plus a set of our own styling conventions. - -**PSR-3: Logger Interface** - -CodeIgniter's :doc:`Logger ` implements all of the interfaces provided by this PSR. - -**PSR-4: Autoloading Standard** - -This PSR provides a method for organizing files and namespaces to allow for a standard method of autoloading classes. -Our :doc:`Autoloader ` meets the PSR-4 recommendations. - -**PSR-6: Caching Interfaces** - -**PSR-16: SimpleCache Interface** - -While the framework Cache components do not adhere to PSR-6 or PSR-16, a separate set of adapters is available from the -CodeIgniter4 organization as a supplemental module. It is recommended that projects use the native Cache drivers -directly, as the adapters are only intended for compatibility with third-party libraries. For more information, visit -the `CodeIgniter4 Cache repo `_. - -**PSR-7: HTTP Message Interface** - -This PSR standardizes a way of representing the HTTP interactions. While many of the concepts became part of our HTTP -layer, CodeIgniter does not strive for compatibility with this recommendation. - ---- - -If you find any places where we claim to meet a PSR but have failed to implement it correctly, please let us know and we -will get it fixed, or submit a pull request with the required changes. diff --git a/user_guide_src/source/intro/requirements.rst b/user_guide_src/source/intro/requirements.rst deleted file mode 100644 index d8d8dbaecc59..000000000000 --- a/user_guide_src/source/intro/requirements.rst +++ /dev/null @@ -1,87 +0,0 @@ -################### -Server Requirements -################### - -.. contents:: - :local: - :depth: 2 - -*************************** -PHP and Required Extensions -*************************** - -`PHP `_ version 8.2 or newer is required, with the following PHP extensions enabled: - - - `intl `_ - - `mbstring `_ - -.. warning:: - - - The end of life date for PHP 7.4 was November 28, 2022. - - The end of life date for PHP 8.0 was November 26, 2023. - - The end of life date for PHP 8.1 was December 31, 2025. - - **If you are still using a PHP version below 8.2, you should upgrade immediately.** - - The end of life date for PHP 8.2 will be December 31, 2026. - -.. note:: - - - PHP 8.5 requires CodeIgniter 4.7.0 or later. - - PHP 8.4 requires CodeIgniter 4.6.0 or later. - - PHP 8.3 requires CodeIgniter 4.4.4 or later. - - PHP 8.2 requires CodeIgniter 4.2.11 or later. - - PHP 8.1 requires CodeIgniter 4.1.6 or later. - - **Note that we only maintain the latest version.** - -*********************** -Optional PHP Extensions -*********************** - -The following PHP extensions should be enabled on your server: - - - `mysqlnd `_ (if you use MySQL) - - `curl `_ (if you use - :doc:`CURLRequest `) - - `imagick `_ (if you use the ``ImageMagickHandler`` class) - - `gd `_ (if you use the ``GDHandler`` class) - - `simplexml `_ (if you format XML) - -The following PHP extensions are required when you use a Cache server: - - - `memcache `_ (if you use the ``MemcachedHandler`` class - with Memcache) - - `memcached `_ (if you use the ``MemcachedHandler`` class - with Memcached) - - `redis `_ (if you use the ``RedisHandler`` class) - -The following PHP extensions are required when you use PHPUnit: - - - `dom `_ (if you use the :doc:`TestResponse ` - class) - - `libxml `_ (if you use the - :doc:`TestResponse ` class) - - `xdebug `_ (if you use ``CIUnitTestCase::assertHeaderEmitted()``) - -.. _requirements-supported-databases: - -******************* -Supported Databases -******************* - -A database is required for most web application programming. Currently supported databases are: - - - MySQL via the ``MySQLi`` driver (version 5.1 and above only) - - PostgreSQL via the ``Postgre`` driver (version 7.4 and above only) - - SQLite3 via the ``SQLite3`` driver - - Microsoft SQL Server via the ``SQLSRV`` driver (version 2012 and above only) - - Oracle Database via the ``OCI8`` driver (version 12.1 and above only) - -Not all of the drivers have been converted/rewritten for CodeIgniter4. The list below shows the outstanding ones. - - - MySQL (5.1+) via the *pdo* driver - - Oracle via the *pdo* drivers - - PostgreSQL via the *pdo* driver - - MSSQL via the *pdo* driver - - SQLite via the *sqlite* (version 2) and *pdo* drivers - - CUBRID via the *cubrid* and *pdo* drivers - - Interbase/Firebird via the *ibase* and *pdo* drivers - - ODBC via the *odbc* and *pdo* drivers (you should know that ODBC is actually an abstraction layer) diff --git a/user_guide_src/source/libraries/caching.rst b/user_guide_src/source/libraries/caching.rst deleted file mode 100644 index 667706d7c0a6..000000000000 --- a/user_guide_src/source/libraries/caching.rst +++ /dev/null @@ -1,335 +0,0 @@ -############## -Caching Driver -############## - -CodeIgniter features wrappers around some of the most popular forms of fast and dynamic caching. All but file-based -caching have specific server requirements, and a Fatal Exception will be thrown if server requirements are not met. - -.. contents:: - :local: - :depth: 2 - -************* -Example Usage -************* - -The following example shows a common usage pattern within your controllers. - -.. literalinclude:: caching/001.php - -You can grab an instance of the cache engine directly through the global function ``service()``: - -.. literalinclude:: caching/002.php - -.. _libraries-caching-configuring-the-cache: - -********************* -Configuring the Cache -********************* - -All configuration for the cache engine is done in **app/Config/Cache.php**. In that file, the following items are -available. - -$handler -======== - -This is the name of the handler that should be used as the primary handler when starting up the engine. Available names -are: apcu, dummy, file, memcached, redis, predis, wincache. - -$backupHandler -============== - -In the case that the first choice ``$handler`` is not available, this is the next cache handler to load. This is -commonly the ``File`` handler since the file system is always available, but may not fit more complex, multi-server -setups. - -$prefix -======= - -If you have more than one application using the same cache storage, you can add a custom prefix string here that is -prepended to all key names. - -$ttl -==== - -The default number of seconds to save items when none is specified. - -WARNING: This is not used by framework handlers where 60 seconds is hard-coded, but may be useful to projects and -modules. This will replace the hard-coded value in a future release. - -$file -===== - -This is an array of settings specific to the **File** handler to determine how it should save the cache files. - -$memcached -========== - -This is an array of servers that will be used when using the **Memcached** handler. - -$redis -====== - -The settings for the Redis server that you wish to use when using the **Redis** and **Predis** handlers. - -****************** -Command-Line Tools -****************** - -CodeIgniter ships with several :doc:`commands ` that are available from the command line to help -you work with Cache. These tools are not required to use the Cache driver, but might help you. - -cache:clear -=========== - -Clears the current system caches: - -.. code-block:: console - - php spark cache:clear - -cache:info -========== - -Shows file cache information in the current system: - -.. code-block:: console - - php spark cache:info - -.. note:: This command only supports the File cache handler. - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\Cache - -.. php:class:: CacheInterface - - .. php:method:: isSupported() - - :returns: ``true`` if supported, ``false`` if not - :rtype: bool - - .. php:method:: get($key): mixed - - :param string $key: Cache item name - :returns: Item value or ``null`` if not found - :rtype: mixed - - This method will attempt to fetch an item from the cache store. If the item does not exist, the method will - return null. - - Example: - - .. literalinclude:: caching/003.php - - .. php:method:: remember(string $key, int $ttl, Closure $callback) - - :param string $key: Cache item name - :param int $ttl: Time to live in seconds - :param Closure $callback: Callback to invoke when the cache item returns null - :returns: The value of the cache item - :rtype: mixed - - Gets an item from the cache. If ``null`` was returned, this will invoke the callback and save the result. Either - way, this will return the value. - - .. php:method:: save(string $key, $data[, int $ttl = 60]) - - :param string $key: Cache item name - :param mixed $data: the data to save - :param int $ttl: Time To Live, in seconds (default 60) - :returns: ``true`` on success, ``false`` on failure - :rtype: bool - - This method will save an item to the cache store. If saving fails, the method will return ``false``. - - Example: - - .. literalinclude:: caching/004.php - - .. php:method:: delete($key): bool - - :param string $key: name of cached item - :returns: ``true`` on success, ``false`` on failure - :rtype: bool - - This method will delete a specific item from the cache store. If item deletion fails, the method will return - false. - - Example: - - .. literalinclude:: caching/005.php - - .. php:method:: deleteMatching($pattern): integer - - :param string $pattern: glob-style pattern to match cached item keys - :returns: number of deleted items - :rtype: integer - - This method will delete multiple items from the cache store at once by matching their keys against a glob-style - pattern. It will return the total number of deleted items. - - .. important:: This method is only implemented for the File, Redis and Predis handlers. Due to limitations, it - couldn't be implemented for the Memcached and Wincache handlers. - - .. note:: With the File handler, the pattern is matched against cache file names only and cannot match files in - subdirectories. A pattern containing a forward slash (``/``) therefore never matches. - - Example: - - .. literalinclude:: caching/006.php - - For more information on glob-style syntax, please see - `Glob (programming) `_. - - .. php:method:: increment($key[, $offset = 1]): mixed - - :param string $key: Cache ID - :param int $offset: Step/value to add - :returns: New value on success, ``false`` on failure - :rtype: mixed - - Performs atomic incrementation of a raw stored value. - - Example: - - .. literalinclude:: caching/007.php - - .. php:method:: decrement($key[, $offset = 1]): mixed - - :param string $key: Cache ID - :param int $offset: Step/value to reduce by - :returns: New value on success, ``false`` on failure - :rtype: mixed - - Performs atomic decrementation of a raw stored value. - - Example: - - .. literalinclude:: caching/008.php - - .. important:: Memcached counters are unsigned and saturate at ``0`` instead of going negative. Decrementing a - key that does not yet exist initializes it to ``0`` (rather than ``-$offset``, as the File, Redis, and - Predis handlers do), and decrementing an existing counter below ``0`` clamps it at ``0``. - - .. php:method:: clean() - - :returns: ``true`` on success, ``false`` on failure - :rtype: bool - - This method will 'clean' the entire cache. If the deletion of the cache files fails, the method will return - false. - - Example: - - .. literalinclude:: caching/009.php - - .. php:method:: getCacheInfo() - - :returns: Information on the entire cache database - :rtype: mixed - - This method will return information on the entire cache. - - Example: - - .. literalinclude:: caching/010.php - - .. note:: The information returned and the structure of the data are dependent on which adapter is being used. - - .. php:method:: getMetadata(string $key) - - :param string $key: Cache item name - :returns: Metadata for the cached item. ``null`` for missing items, or an array with at least the "expire" key for absolute epoch expiry (``null`` for never expires). - :rtype: array|null - - This method will return detailed information on a specific item in the cache. - - Example: - - .. literalinclude:: caching/011.php - - .. note:: The information returned and the structure of the data are dependent on which adapter is being used. - Some adapters (File, Memcached, Wincache) still return ``false`` for missing items. - - .. php:staticmethod:: validateKey(string $key, string $prefix) - - :param string $key: Potential cache key - :param string $prefix: Optional prefix - :returns: The verified and prefixed key. If the key exceeds the driver's max key length it will be hashed. - :rtype: string - - This method is used by handler methods to check that keys are valid. It will throw an - ``InvalidArgumentException`` for non-strings, invalid characters, and empty lengths. - - Example: - - .. literalinclude:: caching/012.php - -******* -Drivers -******* - -APCu Caching -============ - -APCu is an in-memory key-value store for PHP. - -To use it, you need the `APCu PHP extension `_. - -File-based Caching -================== - -This requires a cache directory to be writable by the application. - -Use this with care, and make sure to benchmark your application, as a point can come where disk I/O will negate positive -gains from caching. - -Memcached Caching -================= - -Memcached servers can be specified in the cache configuration file. Available options are: - -.. literalinclude:: caching/013.php - -For more information on Memcached, please see `https://www.php.net/memcached `_. - -WinCache Caching -================ - -Under Windows, you can also utilize the WinCache driver. - -For more information on WinCache, please see `https://www.php.net/wincache `_. - -Redis Caching -============= - -Redis is an in-memory key-value store which can operate in LRU cache mode. To use it, you need the -`Redis server and phpredis PHP extension `_. - -Config options to connect to the Redis server are stored in the cache configuration file. Available options are: - -.. literalinclude:: caching/014.php - -For more information on Redis, please see `https://redis.io `_. - -Predis Caching -============== - -Predis is a flexible and feature-complete PHP client library for the Redis key-value store. To use it, run the following -from the command line inside your project root: - -.. code-block:: console - - composer require predis/predis - -For more information on Predis, please see `https://github.com/nrk/predis `_. - -Dummy Cache -=========== - -This is a caching backend that will always 'miss.' It stores no data, but lets you keep your caching code in place in -environments that don't support your chosen cache. diff --git a/user_guide_src/source/libraries/caching/001.php b/user_guide_src/source/libraries/caching/001.php deleted file mode 100644 index 5a8e2c69b26d..000000000000 --- a/user_guide_src/source/libraries/caching/001.php +++ /dev/null @@ -1,11 +0,0 @@ -'; - $foo = 'foobarbaz!'; - - // Save into the cache for 5 minutes - cache()->save('foo', $foo, 300); -} - -echo $foo; diff --git a/user_guide_src/source/libraries/caching/002.php b/user_guide_src/source/libraries/caching/002.php deleted file mode 100644 index d1b936cdd842..000000000000 --- a/user_guide_src/source/libraries/caching/002.php +++ /dev/null @@ -1,5 +0,0 @@ -get('foo'); diff --git a/user_guide_src/source/libraries/caching/003.php b/user_guide_src/source/libraries/caching/003.php deleted file mode 100644 index 4913a816e5e2..000000000000 --- a/user_guide_src/source/libraries/caching/003.php +++ /dev/null @@ -1,3 +0,0 @@ -get('my_cached_item'); diff --git a/user_guide_src/source/libraries/caching/004.php b/user_guide_src/source/libraries/caching/004.php deleted file mode 100644 index f343a5bee486..000000000000 --- a/user_guide_src/source/libraries/caching/004.php +++ /dev/null @@ -1,3 +0,0 @@ -save('cache_item_id', 'data_to_cache'); diff --git a/user_guide_src/source/libraries/caching/005.php b/user_guide_src/source/libraries/caching/005.php deleted file mode 100644 index 1d8a3b905588..000000000000 --- a/user_guide_src/source/libraries/caching/005.php +++ /dev/null @@ -1,3 +0,0 @@ -delete('cache_item_id'); diff --git a/user_guide_src/source/libraries/caching/006.php b/user_guide_src/source/libraries/caching/006.php deleted file mode 100644 index 1afc08644ace..000000000000 --- a/user_guide_src/source/libraries/caching/006.php +++ /dev/null @@ -1,4 +0,0 @@ -deleteMatching('prefix_*'); // deletes all items of which keys start with "prefix_" -$cache->deleteMatching('*_suffix'); // deletes all items of which keys end with "_suffix" diff --git a/user_guide_src/source/libraries/caching/007.php b/user_guide_src/source/libraries/caching/007.php deleted file mode 100644 index 6256d6e0e721..000000000000 --- a/user_guide_src/source/libraries/caching/007.php +++ /dev/null @@ -1,5 +0,0 @@ -increment('iterator'); // 'iterator' is now 3 -$cache->increment('iterator', 3); // 'iterator' is now 6 diff --git a/user_guide_src/source/libraries/caching/008.php b/user_guide_src/source/libraries/caching/008.php deleted file mode 100644 index 4e74cbb0a47f..000000000000 --- a/user_guide_src/source/libraries/caching/008.php +++ /dev/null @@ -1,5 +0,0 @@ -decrement('iterator'); // 'iterator' is now 5 -$cache->decrement('iterator', 2); // 'iterator' is now 3 diff --git a/user_guide_src/source/libraries/caching/009.php b/user_guide_src/source/libraries/caching/009.php deleted file mode 100644 index a5a9e5725f23..000000000000 --- a/user_guide_src/source/libraries/caching/009.php +++ /dev/null @@ -1,3 +0,0 @@ -clean(); diff --git a/user_guide_src/source/libraries/caching/010.php b/user_guide_src/source/libraries/caching/010.php deleted file mode 100644 index 22a5cb08b8b9..000000000000 --- a/user_guide_src/source/libraries/caching/010.php +++ /dev/null @@ -1,3 +0,0 @@ -getCacheInfo()); diff --git a/user_guide_src/source/libraries/caching/011.php b/user_guide_src/source/libraries/caching/011.php deleted file mode 100644 index 1fedd92c28b4..000000000000 --- a/user_guide_src/source/libraries/caching/011.php +++ /dev/null @@ -1,3 +0,0 @@ -getMetadata('my_cached_item')); diff --git a/user_guide_src/source/libraries/caching/012.php b/user_guide_src/source/libraries/caching/012.php deleted file mode 100644 index b6a56120731d..000000000000 --- a/user_guide_src/source/libraries/caching/012.php +++ /dev/null @@ -1,5 +0,0 @@ - '127.0.0.1', - 'port' => 11211, - 'weight' => 1, - 'raw' => false, - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/caching/014.php b/user_guide_src/source/libraries/caching/014.php deleted file mode 100644 index c7be7cf0f076..000000000000 --- a/user_guide_src/source/libraries/caching/014.php +++ /dev/null @@ -1,22 +0,0 @@ - '127.0.0.1', - 'password' => null, - 'port' => 6379, - 'async' => false, // specific to Predis and ignored by the native Redis extension - 'persistent' => false, - 'timeout' => 0, - 'database' => 0, - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/cookies.rst b/user_guide_src/source/libraries/cookies.rst deleted file mode 100644 index 22fa0bf665da..000000000000 --- a/user_guide_src/source/libraries/cookies.rst +++ /dev/null @@ -1,514 +0,0 @@ -####### -Cookies -####### - -An **HTTP cookie** (web cookie, browser cookie) is a small piece of data that a server sends to the user's web browser. -The browser may store it and send it back with later requests to the same server. Typically, it's used to tell if two -requests came from the same browser - keeping a user logged in, for example. It remembers stateful information for the -stateless HTTP protocol. - -Cookies are mainly used for three purposes: - -- **Session management**: Logins, shopping carts, game scores, or anything else the server should remember -- **Personalization**: User preferences, themes, and other settings -- **Tracking**: Recording and analyzing user behavior - -To help you efficiently send cookies to browsers, CodeIgniter provides the ``CodeIgniter\Cookie\Cookie`` class to -abstract the cookie interaction. - -.. contents:: - :local: - :depth: 2 - -**************** -Creating Cookies -**************** - -There are currently four ways to create a new ``Cookie`` value object. - -.. literalinclude:: cookies/001.php - -When constructing the ``Cookie`` object, only the ``name`` attribute is required. All others are optional. If the -optional attributes are not modified, their values will be filled with the default values saved in the ``Cookie`` class. - -Overriding Defaults -=================== - -To override the defaults currently stored in the class, you can pass a ``Config\Cookie`` instance or an array of -defaults to the static ``Cookie::setDefaults()`` method. - -.. literalinclude:: cookies/002.php - -Passing the ``Config\Cookie`` instance or an array to ``Cookie::setDefaults()`` will effectively overwrite your defaults -and will persist until new defaults are passed. - -Changing Defaults for a Limited Time ------------------------------------- - -If you do not want this behavior but only want to change defaults for a limited time, you can take advantage of the -return value of ``Cookie::setDefaults()``, which is the old defaults array. - -.. literalinclude:: cookies/003.php - -***************************** -Accessing Cookie's Attributes -***************************** - -Once instantiated, you can easily access a ``Cookie``'s attribute by using one of its getter methods. - -.. literalinclude:: cookies/004.php - -***************** -Immutable Cookies -***************** - -A new ``Cookie`` instance is an immutable value object representation of an HTTP cookie. Since it is immutable, -modifying any of the instance's attributes will not affect the original instance. The modification **always** returns a -new instance. You need to retain this new instance in order to use it. - -.. literalinclude:: cookies/005.php - -******************************** -Validating a Cookie's Attributes -******************************** - -An HTTP cookie is regulated by several specifications that need to be followed in order to be accepted by browsers. -Thus, when creating or modifying certain attributes of the ``Cookie``, these are validated in order to check if they -follow the specifications. - -A ``CookieException`` is thrown if violations were reported. - -Validating the Name Attribute -============================= - -A cookie name can be any US-ASCII character, except for the following: - -- control characters; -- spaces or tabs; -- separator characters, such as ``( ) < > @ , ; : \ " / [ ] ? = { }`` - -If the ``$raw`` parameter is set to ``true``, this validation will be strictly enforced. This is because PHP's -`setcookie() `_ and -`setrawcookie() `_ will reject cookies with invalid names. -Additionally, cookie names cannot be an empty string. - -Validating the Value Attribute -============================== - -If setting the ``$raw`` parameter to ``true``, the cookie value will also be validated. It must not contain control -characters, spaces, tabs, or separator characters (``, ;``) as -`setrawcookie() `_ will reject them. - -Validating the Path Attribute -============================= - -The cookie path must not contain control characters, spaces, tabs, or separator characters (``, ;``) as -`setcookie() `_ and -`setrawcookie() `_ will reject them. - -Validating the Domain Attribute -=============================== - -The cookie domain must not contain control characters, spaces, tabs, or separator characters (``, ;``) as -`setcookie() `_ and -`setrawcookie() `_ will reject them. - -Validating the Prefix Attribute -=============================== - -The cookie prefix must not contain control characters, spaces, tabs, or separator characters -(``= , ; \t \r \n \v \f \0``) as `setcookie() `_ and -`setrawcookie() `_ will reject them. - -When using the ``__Secure-`` prefix, cookies must be set with the ``$secure`` flag set to ``true``. If using the -``__Host-`` prefix, cookies must exhibit the following: - -- ``$secure`` flag set to ``true`` -- ``$domain`` is empty -- ``$path`` must be ``/`` - -Validating the SameSite Attribute -================================= - -The SameSite attribute accepts three values: - -- **Lax**: Cookies are not sent on normal cross-site subrequests (for example, to load images or frames into a - third-party site), but are sent when a user is navigating to the origin site (*i.e.* when following a link). -- **Strict**: Cookies will only be sent in a first-party context and not be sent along with requests initiated by - third-party websites. -- **None**: Cookies will be sent in all contexts, *i.e.* in responses to both first-party and cross-origin requests. - -CodeIgniter, however, allows you to set the SameSite attribute to an empty string. When an empty string is provided, the -default SameSite setting saved in the ``Cookie`` class is used. You can change the default SameSite by using -``Cookie::setDefaults()`` as discussed above. - -Recent cookie specifications have changed such that modern browsers are required to give a default SameSite if nothing -is provided. This default is ``Lax``. If you have set the SameSite to be an empty string and your default SameSite is -also an empty string, your cookie will be given the ``Lax`` value. - -If the SameSite is set to ``None``, you need to make sure that ``Secure`` is also set to ``true``. - -When writing the SameSite attribute, the ``Cookie`` class accepts any of the values case-insensitively. You can also -take advantage of the class's constants to make this easier. - -.. literalinclude:: cookies/006.php - - -*************** -Sending Cookies -*************** - -Set the ``Cookie`` objects in the ``CookieStore`` of the Response object, and the framework will automatically send the -cookies. - -Use :php:meth:`CodeIgniter\\HTTP\\Response::setCookie()` to set: - -.. literalinclude:: cookies/017.php - -You can also use the :php:func:`set_cookie()` helper function: - -.. literalinclude:: cookies/018.php - - -********************** -Using the Cookie Store -********************** - -.. note:: Normally, there is no need to use CookieStore directly. - -The ``CookieStore`` class represents an immutable collection of ``Cookie`` objects. - -Getting the Store from Response -=============================== - -The ``CookieStore`` instance can be accessed from the current ``Response`` object. - -.. literalinclude:: cookies/007.php - -Creating CookieStore -==================== - -CodeIgniter provides three other ways to create a new instance of the ``CookieStore``. - -.. literalinclude:: cookies/008.php - -.. note:: When using the global :php:func:`cookies()` function, the passed ``Cookie`` array will only be considered if - the second argument, ``$getGlobal``, is set to ``false``. - -Checking Cookies in Store -========================= - -There are several ways to check whether a ``Cookie`` object exists in the ``CookieStore`` instance: - -.. literalinclude:: cookies/009.php - -Getting Cookies in Store -======================== - -Retrieving a ``Cookie`` instance in a cookie collection is very easy: - -.. literalinclude:: cookies/010.php - -When getting a ``Cookie`` instance directly from a ``CookieStore``, an invalid name will throw a ``CookieException``. - -.. literalinclude:: cookies/011.php - -When getting a ``Cookie`` instance from the current ``Response``'s cookie collection, an invalid name will just return -``null``. - -.. literalinclude:: cookies/012.php - -If no arguments are supplied when getting cookies from the ``Response``, all ``Cookie`` objects in store will be -displayed. - -.. literalinclude:: cookies/013.php - -.. note:: The helper function :php:func:`get_cookie()` gets the cookie from the current ``Request`` object, not from - ``Response``. This function checks the ``$_COOKIE`` array to see if that cookie is set and fetches it right away. - -Adding/Removing Cookies in Store -================================ - -As previously mentioned, ``CookieStore`` objects are immutable. You need to save the modified instance in order to work -on it. The original instance is left unchanged. - -.. literalinclude:: cookies/014.php - -.. note:: Removing a cookie from the store **DOES NOT** delete it from the browser. If you intend to delete a cookie - *from the browser*, you must put an empty-value cookie with the same name into the store. - -When interacting with the cookies in store in the current ``Response`` object, you can safely add or delete cookies -without worrying about the immutable nature of the cookie collection. The ``Response`` object will replace the instance -with the modified instance. - -.. literalinclude:: cookies/015.php - -Dispatching Cookies in Store -============================ - -.. important:: This method was deprecated as of version 4.1.6 and was removed in 4.6.0. - -More often than not, you do not need to concern yourself with manually sending cookies. CodeIgniter will do this for -you. However, if you really need to manually send cookies, you can use the ``dispatch`` method. Just like when sending -other headers, you need to make sure the headers are not yet sent by checking the value of ``headers_sent()``. - -.. literalinclude:: cookies/016.php - -********************** -Cookie Personalization -********************** - -Sane defaults are already in place inside the ``Cookie`` class to ensure the smooth creation of cookie objects. However, -you may wish to define your own settings by changing the following settings in the ``Config\Cookie`` class in the -**app/Config/Cookie.php** file. - -==================== ===================================== ========= ===================================================== -Setting Options/Types Default Description -==================== ===================================== ========= ===================================================== -**$prefix** ``string`` ``''`` Prefix to prepend to the cookie name. -**$expires** ``DateTimeInterface|string|int`` ``0`` The expires timestamp. -**$path** ``string`` ``/`` The path property of the cookie. -**$domain** ``string`` ``''`` The domain property of the cookie. -**$secure** ``true``/``false`` ``false`` Whether to send it over secure HTTPS. -**$httponly** ``true``/``false`` ``true`` Whether it is inaccessible to JavaScript. -**$samesite** ``Lax``/``None``/``Strict`` ``Lax`` The SameSite attribute. -**$raw** ``true``/``false`` ``false`` Whether to dispatch it using ``setrawcookie()``. -==================== ===================================== ========= ===================================================== - -At runtime, you can manually supply a new default using the ``Cookie::setDefaults()`` method. - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\Cookie - -.. php:class:: Cookie - - .. php:staticmethod:: setDefaults([$config = []]) - - :param \\Config\\Cookie|array $config: The configuration array or instance - :rtype: array - :returns: The old defaults - - Set the default attributes to a Cookie instance by injecting the values from the ``Config\Cookie`` config or an - array. - - .. php:staticmethod:: fromHeaderString(string $header[, bool $raw = false]) - - :param string $header: The ``Set-Cookie`` header string - :param bool $raw: Whether this cookie is not to be URL encoded and sent via ``setrawcookie()`` - :rtype: ``Cookie`` - :returns: ``Cookie`` instance - :throws: ``CookieException`` - - Create a new Cookie instance from a ``Set-Cookie`` header. - - .. php:method:: __construct(string $name[, string $value = ''[, array $options = []]]) - - :param string $name: The cookie name - :param string $value: The cookie value - :param array $options: The cookie options - :rtype: ``Cookie`` - :returns: ``Cookie`` instance - :throws: ``CookieException`` - - Construct a new Cookie instance. - - .. php:method:: getId() - - :rtype: string - :returns: The ID used in indexing in the cookie collection. - - .. php:method:: getPrefix(): string - .. php:method:: getName(): string - .. php:method:: getPrefixedName(): string - .. php:method:: getValue(): string - .. php:method:: getExpiresTimestamp(): int - .. php:method:: getExpiresString(): string - .. php:method:: isExpired(): bool - .. php:method:: getMaxAge(): int - .. php:method:: getDomain(): string - .. php:method:: getPath(): string - .. php:method:: isSecure(): bool - .. php:method:: isHTTPOnly(): bool - .. php:method:: getSameSite(): string - .. php:method:: isRaw(): bool - .. php:method:: getOptions(): array - - .. php:method:: withRaw([bool $raw = true]) - - :param bool $raw: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with the URL encoding option updated. - - .. php:method:: withPrefix([string $prefix = '']) - - :param string $prefix: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with a new prefix. - - .. php:method:: withName(string $name) - - :param string $name: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with a new name. - - .. php:method:: withValue(string $value) - - :param string $value: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with a new value. - - .. php:method:: withExpires($expires) - - :param DateTimeInterface|string|int $expires: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with a new cookie expires time. - - .. php:method:: withExpired() - - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie that will expire from the browser. - - .. php:method:: withNeverExpiring() - - .. important:: This method was deprecated as of version 4.2.6 and was removed in 4.6.0. - - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie that will virtually never expire. - - .. php:method:: withDomain(?string $domain) - - :param string|null $domain: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with a new domain. - - .. php:method:: withPath(?string $path) - - :param string|null $path: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with a new path. - - .. php:method:: withSecure([bool $secure = true]) - - :param bool $secure: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with a new "Secure" attribute. - - .. php:method:: withHTTPOnly([bool $httponly = true]) - - :param bool $httponly: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with a new "HttpOnly" attribute. - - .. php:method:: withSameSite(string $samesite) - - :param string $samesite: - :rtype: ``Cookie`` - :returns: new ``Cookie`` instance - - Creates a new Cookie with a new "SameSite" attribute. - - .. php:method:: toHeaderString() - - :rtype: string - :returns: Returns the string representation that can be passed as a header string. - - .. php:method:: toArray() - - :rtype: array - :returns: Returns the array representation of the Cookie instance. - -.. php:class:: CookieStore - - .. php:staticmethod:: fromCookieHeaders(array $headers[, bool $raw = false]) - - :param array $headers: Array of ``Set-Cookie`` headers - :param bool $raw: Whether not to use URL encoding - :rtype: ``CookieStore`` - :returns: ``CookieStore`` instance - :throws: ``CookieException`` - - Creates a CookieStore from an array of ``Set-Cookie`` headers. - - .. php:method:: __construct(array $cookies) - - :param array $cookies: Array of ``Cookie`` objects - :rtype: ``CookieStore`` - :returns: ``CookieStore`` instance - :throws: ``CookieException`` - - .. php:method:: has(string $name[, string $prefix = ''[, ?string $value = null]]): bool - - :param string $name: Cookie name - :param string $prefix: Cookie prefix - :param string|null $value: Cookie value - :rtype: bool - :returns: Checks if a ``Cookie`` object identified by name and prefix is present in the collection. - - .. php:method:: get(string $name[, string $prefix = '']): Cookie - - :param string $name: Cookie name - :param string $prefix: Cookie prefix - :rtype: ``Cookie`` - :returns: Retrieves an instance of Cookie identified by a name and prefix. - :throws: ``CookieException`` - - .. php:method:: put(Cookie $cookie): CookieStore - - :param Cookie $cookie: A Cookie object - :rtype: ``CookieStore`` - :returns: new ``CookieStore`` instance - - Store a new cookie and return a new collection. The original collection is left unchanged. - - .. php:method:: remove(string $name[, string $prefix = '']): CookieStore - - :param string $name: Cookie name - :param string $prefix: Cookie prefix - :rtype: ``CookieStore`` - :returns: new ``CookieStore`` instance - - Removes a cookie from a collection and returns an updated collection. The original collection is left unchanged. - - .. php:method:: dispatch(): void - - .. important:: This method was deprecated as of version 4.1.6 and was removed in 4.6.0. - - :rtype: void - - Dispatches all cookies in store. - - .. php:method:: display(): array - - :rtype: array - :returns: Returns all cookie instances in store. - - .. php:method:: clear(): void - - :rtype: void - - Clears the cookie collection. diff --git a/user_guide_src/source/libraries/cookies/001.php b/user_guide_src/source/libraries/cookies/001.php deleted file mode 100644 index f415b17d827e..000000000000 --- a/user_guide_src/source/libraries/cookies/001.php +++ /dev/null @@ -1,40 +0,0 @@ - new DateTime('+2 hours'), - 'prefix' => '__Secure-', - 'path' => '/', - 'domain' => '', - 'secure' => true, - 'httponly' => true, - 'raw' => false, - 'samesite' => Cookie::SAMESITE_LAX, - ], -); - -// Supplying a Set-Cookie header string -$cookie = Cookie::fromHeaderString( - 'remember_token=f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6; Path=/; Secure; HttpOnly; SameSite=Lax', - false, // raw -); - -// Using the fluent builder interface -$cookie = (new Cookie('remember_token')) - ->withValue('f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6') - ->withPrefix('__Secure-') - ->withExpires(new DateTime('+2 hours')) - ->withPath('/') - ->withDomain('') - ->withSecure(true) - ->withHTTPOnly(true) - ->withSameSite(Cookie::SAMESITE_LAX); - -// Using the global function `cookie` which implicitly calls `new Cookie()` -$cookie = cookie('remember_token', 'f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6'); diff --git a/user_guide_src/source/libraries/cookies/002.php b/user_guide_src/source/libraries/cookies/002.php deleted file mode 100644 index ecbe37ed088b..000000000000 --- a/user_guide_src/source/libraries/cookies/002.php +++ /dev/null @@ -1,16 +0,0 @@ - 0, - 'samesite' => Cookie::SAMESITE_STRICT, -]; -Cookie::setDefaults($myDefaults); -$cookie = new Cookie('login_token'); diff --git a/user_guide_src/source/libraries/cookies/003.php b/user_guide_src/source/libraries/cookies/003.php deleted file mode 100644 index 6e9094fe7b77..000000000000 --- a/user_guide_src/source/libraries/cookies/003.php +++ /dev/null @@ -1,10 +0,0 @@ - new DateTime('2025-02-14 00:00:00', new DateTimeZone('UTC')), - 'prefix' => '__Secure-', - 'path' => '/', - 'domain' => '', - 'secure' => true, - 'httponly' => true, - 'raw' => false, - 'samesite' => Cookie::SAMESITE_LAX, - ], -); - -$cookie->getName(); // 'remember_token' -$cookie->getPrefix(); // '__Secure-' -$cookie->getPrefixedName(); // '__Secure-remember_token' -$cookie->getExpiresTimestamp(); // UNIX timestamp -$cookie->getExpiresString(); // 'Fri, 14 Feb 2025 00:00:00 GMT' -$cookie->isExpired(); // false -$cookie->getMaxAge(); // the difference from time() to expires -$cookie->isRaw(); // false -$cookie->isSecure(); // true -$cookie->getPath(); // '/' -$cookie->getDomain(); // '' -$cookie->isHTTPOnly(); // true -$cookie->getSameSite(); // 'Lax' - -// additional getter -$cookie->getId(); // '__Secure-remember_token;;/' - -// when using `setcookie()`'s alternative signature on PHP 7.3+ -// you can easily use the `getOptions()` method to supply the -// $options parameter -$cookie->getOptions(); diff --git a/user_guide_src/source/libraries/cookies/005.php b/user_guide_src/source/libraries/cookies/005.php deleted file mode 100644 index 264d06782104..000000000000 --- a/user_guide_src/source/libraries/cookies/005.php +++ /dev/null @@ -1,12 +0,0 @@ -getName(); // 'login_token' - -$cookie->withName('remember_token'); -$cookie->getName(); // 'login_token' - -$new = $cookie->withName('remember_token'); -$new->getName(); // 'remember_token' diff --git a/user_guide_src/source/libraries/cookies/006.php b/user_guide_src/source/libraries/cookies/006.php deleted file mode 100644 index 512d3e8fefe0..000000000000 --- a/user_guide_src/source/libraries/cookies/006.php +++ /dev/null @@ -1,7 +0,0 @@ -getCookieStore(); diff --git a/user_guide_src/source/libraries/cookies/008.php b/user_guide_src/source/libraries/cookies/008.php deleted file mode 100644 index d387a507abd0..000000000000 --- a/user_guide_src/source/libraries/cookies/008.php +++ /dev/null @@ -1,22 +0,0 @@ -has('login_token'); - -// check if cookie is in the current Response's cookie collection -cookies()->has('login_token'); -service('response')->hasCookie('remember_token'); - -// using the cookie helper to check the current Response -// not available to v4.1.1 and lower -helper('cookie'); -has_cookie('login_token'); diff --git a/user_guide_src/source/libraries/cookies/010.php b/user_guide_src/source/libraries/cookies/010.php deleted file mode 100644 index b2a18323cdac..000000000000 --- a/user_guide_src/source/libraries/cookies/010.php +++ /dev/null @@ -1,20 +0,0 @@ -get('login_token'); - -// getting cookie in the current Response's cookie collection -cookies()->get('login_token'); -service('response')->getCookie('remember_token'); - -// using the cookie helper to get cookie from the Response's cookie collection -helper('cookie'); -get_cookie('remember_token'); diff --git a/user_guide_src/source/libraries/cookies/011.php b/user_guide_src/source/libraries/cookies/011.php deleted file mode 100644 index 79937ad3f367..000000000000 --- a/user_guide_src/source/libraries/cookies/011.php +++ /dev/null @@ -1,4 +0,0 @@ -get('unknown_cookie'); diff --git a/user_guide_src/source/libraries/cookies/012.php b/user_guide_src/source/libraries/cookies/012.php deleted file mode 100644 index cde062c20bd0..000000000000 --- a/user_guide_src/source/libraries/cookies/012.php +++ /dev/null @@ -1,3 +0,0 @@ -get('unknown_cookie'); // null diff --git a/user_guide_src/source/libraries/cookies/013.php b/user_guide_src/source/libraries/cookies/013.php deleted file mode 100644 index d27b248662cd..000000000000 --- a/user_guide_src/source/libraries/cookies/013.php +++ /dev/null @@ -1,6 +0,0 @@ -display(); // array of Cookie objects - -// or even from the Response -service('response')->getCookies(); diff --git a/user_guide_src/source/libraries/cookies/014.php b/user_guide_src/source/libraries/cookies/014.php deleted file mode 100644 index 9be64c5cf651..000000000000 --- a/user_guide_src/source/libraries/cookies/014.php +++ /dev/null @@ -1,15 +0,0 @@ -put(new Cookie('admin_token', 'yes')); - -// removing a Cookie instance -$new = $store->remove('login_token'); diff --git a/user_guide_src/source/libraries/cookies/015.php b/user_guide_src/source/libraries/cookies/015.php deleted file mode 100644 index 696e9c7c73d3..000000000000 --- a/user_guide_src/source/libraries/cookies/015.php +++ /dev/null @@ -1,9 +0,0 @@ -setCookie('admin_token', 'yes'); -service('response')->deleteCookie('login_token'); - -// using the cookie helper -helper('cookie'); -set_cookie('admin_token', 'yes'); -delete_cookie('login_token'); diff --git a/user_guide_src/source/libraries/cookies/016.php b/user_guide_src/source/libraries/cookies/016.php deleted file mode 100644 index ec04f12f1cb7..000000000000 --- a/user_guide_src/source/libraries/cookies/016.php +++ /dev/null @@ -1,11 +0,0 @@ -dispatch(); // After dispatch, the collection is now empty. diff --git a/user_guide_src/source/libraries/cookies/017.php b/user_guide_src/source/libraries/cookies/017.php deleted file mode 100644 index e7efef05135a..000000000000 --- a/user_guide_src/source/libraries/cookies/017.php +++ /dev/null @@ -1,15 +0,0 @@ - 3600 * 2, // Expires in 2 hours - ], -); - -$response->setCookie($cookie); diff --git a/user_guide_src/source/libraries/cookies/018.php b/user_guide_src/source/libraries/cookies/018.php deleted file mode 100644 index 1e6353d45387..000000000000 --- a/user_guide_src/source/libraries/cookies/018.php +++ /dev/null @@ -1,15 +0,0 @@ - 3600 * 2, // Expires in 2 hours - ], -); - -set_cookie($cookie); diff --git a/user_guide_src/source/libraries/cors.rst b/user_guide_src/source/libraries/cors.rst deleted file mode 100644 index c27279867f65..000000000000 --- a/user_guide_src/source/libraries/cors.rst +++ /dev/null @@ -1,138 +0,0 @@ -#################################### -Cross-Origin Resource Sharing (CORS) -#################################### - -.. versionadded:: 4.5.0 - -Cross-Origin Resource Sharing (CORS) is an HTTP-header based security mechanism that allows a server to indicate any -origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. - -CORS works by adding headers to HTTP requests and responses to indicate whether the requested resource can be shared -across different origins, helping to prevent malicious attacks like cross-site request forgery (CSRF) and data theft. - -If you are not familiar with CORS and CORS headers, please read the `MDN documentation on CORS`_. - -.. _MDN documentation on CORS: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers - -CodeIgniter provides the CORS filter and helper class. - -.. contents:: - :local: - :depth: 2 - -**************** -Configuring CORS -**************** - -Setting Default Config -====================== - -CORS can be configured in **app/Config/Cors.php**. - -At a minimum, the following items in the ``$default`` property must be set: - -- ``allowedOrigins``: List explicitly the Origin(s) you want to allow. -- ``allowedHeaders``: List explicitly the HTTP headers you want to allow. -- ``allowedMethods``: List explicitly the HTTP methods you want to allow. - -.. warning:: Based on the principle of least privilege, only the minimum necessary Origin, Methods, and Headers should - be allowed. - -If you send credentials (e.g., cookies) with a cross-origin request, set ``supportsCredentials`` to ``true``. - -Enabling CORS -============= - -To enable CORS, you need to do two things: - -1. Set the ``cors`` filter on the routes that permit CORS. -2. Add **OPTIONS** routes for CORS Preflight Requests. - -Set against Routes ------------------- - -You can set the ``cors`` filter on routes in **app/Config/Routes.php**. - -E.g., - -.. literalinclude:: cors/001.php - -Don't forget to add OPTIONS routes for Preflight Requests, because Controller Filters (except for Required Filters) do -not work if the route does not exist. - -The CORS filter handles all Preflight Requests, so the closure controllers for the OPTIONS routes are not normally -called. - -Set in Config\\Filters ----------------------- - -Alternatively, you can set the ``cors`` filter on URI paths in **app/Config/Filters.php**. - -E.g., - -.. literalinclude:: cors/002.php - -Don't forget to add OPTIONS routes for Preflight Requests, because Controller Filters (except for Required Filters) do -not work if the route does not exist. - -E.g., - -.. literalinclude:: cors/003.php - -The CORS filter handles all Preflight Requests, so the closure controller for the OPTIONS routes is not normally called. - -Checking Routes and Filters -=========================== - -After configuration, you can check the routes and filters with the :ref:`routing-spark-routes` command. - -Setting Another Config -====================== - -If you want to use a different configuration than the default configuration, add a property to **app/Config/Cors.php**. - -For example, add the ``$api`` property. - -.. literalinclude:: cors/004.php - -The property name (``api`` in the above example) will become the configuration name. - -Then, specify the property name as the filter argument like ``cors:api``: - -.. literalinclude:: cors/005.php - -You can also use :ref:`filters-filters-filter-arguments`. - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\HTTP - -.. php:class:: Cors - -.. php:method:: addResponseHeaders(RequestInterface $request, ResponseInterface $response): ResponseInterface - - :param RequestInterface $request: Request instance - :param ResponseInterface $response: Response instance - :returns: Response instance - :rtype: ResponseInterface - - Adds response headers for CORS. - -.. php:method:: handlePreflightRequest(RequestInterface $request, ResponseInterface $response): ResponseInterface - - :param RequestInterface $request: Request instance - :param ResponseInterface $response: Response instance - :returns: Response instance - :rtype: ResponseInterface - - Handles Preflight Requests. - -.. php:method:: isPreflightRequest(IncomingRequest $request): bool - - :param IncomingRequest $request: Request instance - :returns: True if it is a Preflight Request. - :rtype: bool - - Checks if the request is a Preflight Request. diff --git a/user_guide_src/source/libraries/cors/001.php b/user_guide_src/source/libraries/cors/001.php deleted file mode 100644 index a64583a943e0..000000000000 --- a/user_guide_src/source/libraries/cors/001.php +++ /dev/null @@ -1,18 +0,0 @@ -group('', ['filter' => 'cors'], static function (RouteCollection $routes): void { - $routes->resource('product'); - - $routes->options('product', static function () { - // Implement processing for normal non-preflight OPTIONS requests, - // if necessary. - $response = response(); - $response->setStatusCode(204); - $response->setHeader('Allow:', 'OPTIONS, GET, POST, PUT, PATCH, DELETE'); - - return $response; - }); - $routes->options('product/(:any)', static function () {}); -}); diff --git a/user_guide_src/source/libraries/cors/002.php b/user_guide_src/source/libraries/cors/002.php deleted file mode 100644 index 1229eaace3a4..000000000000 --- a/user_guide_src/source/libraries/cors/002.php +++ /dev/null @@ -1,19 +0,0 @@ - [ - 'before' => ['api/*'], - 'after' => ['api/*'], - ], - ]; -} diff --git a/user_guide_src/source/libraries/cors/003.php b/user_guide_src/source/libraries/cors/003.php deleted file mode 100644 index 7fcefa26ebf7..000000000000 --- a/user_guide_src/source/libraries/cors/003.php +++ /dev/null @@ -1,7 +0,0 @@ -group('', ['filter' => 'cors'], static function (RouteCollection $routes): void { - $routes->options('api/(:any)', static function () {}); -}); diff --git a/user_guide_src/source/libraries/cors/004.php b/user_guide_src/source/libraries/cors/004.php deleted file mode 100644 index c06462197eae..000000000000 --- a/user_guide_src/source/libraries/cors/004.php +++ /dev/null @@ -1,25 +0,0 @@ - ['https://app.example.com'], - 'allowedOriginsPatterns' => [], - 'supportsCredentials' => true, - 'allowedHeaders' => ['Authorization', 'Content-Type'], - 'exposedHeaders' => [], - 'allowedMethods' => ['GET', 'POST', 'PUT', 'DELETE'], - 'maxAge' => 7200, - ]; -} diff --git a/user_guide_src/source/libraries/cors/005.php b/user_guide_src/source/libraries/cors/005.php deleted file mode 100644 index e9e4f86738ec..000000000000 --- a/user_guide_src/source/libraries/cors/005.php +++ /dev/null @@ -1,10 +0,0 @@ -group('api', ['filter' => 'cors:api'], static function (RouteCollection $routes): void { - $routes->resource('user'); - - $routes->options('user', static function () {}); - $routes->options('user/(:any)', static function () {}); -}); diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst deleted file mode 100644 index 58fbfb9e76fe..000000000000 --- a/user_guide_src/source/libraries/curlrequest.rst +++ /dev/null @@ -1,424 +0,0 @@ -################# -CURLRequest Class -################# - -The ``CURLRequest`` class is a lightweight HTTP client based on CURL that allows you to talk to other websites and -servers. It can be used to get the contents of a Google search, retrieve a web page or image, or communicate with an -API, among many other things. - -.. contents:: - :local: - :depth: 2 - -This class is modeled after the `Guzzle HTTP Client `_ library since it is one of -the more widely used libraries. Where possible, the syntax has been kept the same so that if your application needs -something a little more powerful than what this library provides, you will have to change very little to move over to -use Guzzle. - -.. note:: This class requires the `cURL Library `_ to be installed in your - version of PHP. This is a very common library that is typically available, but not all hosts will provide it, so - please check with your host to verify if you run into problems. - -********************** -Config for CURLRequest -********************** - -.. _curlrequest-sharing-connection: - -Sharing Connection -================== - -.. versionadded:: 4.7.0 - -By default, this option is enabled with the constants ``CURL_LOCK_DATA_CONNECT`` and ``CURL_LOCK_DATA_DNS``. - -If you want to share connections between requests, set ``$shareConnectionOptions`` to an array of -`CURL_LOCK_DATA_* `_ constants in -**app/Config/CURLRequest.php**: - -.. literalinclude:: curlrequest/039.php - -Or, when you want to disable it, just change it to an empty array: - -.. literalinclude:: curlrequest/040.php - -.. _curlrequest-sharing-options: - -Sharing Options -=============== - -.. important:: This setting exists only for backward compatibility. Do not use it in new projects. Even if you are - already using it, we recommend that you disable it. - -.. note:: Since v4.4.0, the default value has been changed to ``false``. - -If you want to share all the options between requests, set ``$shareOptions`` to ``true`` in -**app/Config/CURLRequest.php**: - -.. literalinclude:: curlrequest/001.php - -If you send more than one request with an instance of the class, this behavior may result in an erroneous request with -unnecessary headers and body. - -.. note:: Before v4.2.0, the request body was not reset even if ``$shareOptions`` was false, due to a bug. - -******************* -Loading the Library -******************* - -The library can be loaded either manually or through the :doc:`Services class `. - -To load it with the Services class, call the ``curlrequest()`` method or the global function ``service()``: - -.. literalinclude:: curlrequest/002.php - -You can pass in an array of default options as the first parameter to modify how cURL will handle the request. The -options are described later in this document: - -.. literalinclude:: curlrequest/003.php - -.. note:: When ``$shareOptions`` is false, the default options passed to the class constructor will be used for all - requests. Other options will be reset after sending a request. - -When creating the class manually, you need to pass a few dependencies in. The first parameter is an instance of the -``Config\App`` class. The second parameter is a URI instance. The third parameter is a Response object. The fourth -parameter is the optional default ``$options`` array: - -.. literalinclude:: curlrequest/004.php - -************************ -Working with the Library -************************ - -Working with CURL requests is simply a matter of creating the Request and getting a -:doc:`Response object ` back. It is meant to handle the communications. After that, you have -complete control over how the information is handled. - -Making Requests -=============== - -Most communication is done through the ``request()`` method, which fires off the request, and then returns a Response -instance to you. This takes the HTTP method, the URL, and an array of options as the parameters. - -.. literalinclude:: curlrequest/005.php - -.. important:: By default, CURLRequest will throw ``HTTPException`` if the HTTP code returned is greater than or equal - to 400. If you want to get the response, see the `http_errors`_ option. - -.. note:: When ``$shareOptions`` is false, the options passed to the method will be used for the request. After the - request succeeds or throws an exception, they will be cleared, including per-request ``baseURI`` and ``delay`` - values. The constructor defaults will be restored. To retry a failed request, pass its options again and reapply any - settings made with ``setAuth()``, ``setBody()``, ``setForm()``, or ``setJSON()``. If you want to use the options for - all requests, pass the options in the constructor. - -Since the response is an instance of ``CodeIgniter\HTTP\Response``, you have all of the normal information available to -you: - -.. literalinclude:: curlrequest/006.php - -While the ``request()`` method is the most flexible, you can also use the following shortcut methods. They each take the -URL as the first parameter and an array of options as the second: - -.. literalinclude:: curlrequest/007.php - -Base URI --------- - -A ``baseURI`` can be set as one of the options during the instantiation of the class. This allows you to set a base URI, -and then make all requests with that client using relative URLs. This is especially handy when working with APIs: - -.. literalinclude:: curlrequest/008.php - -When a relative URI is provided to the ``request()`` method or any of the shortcut methods, it will be combined with the -baseURI according to the rules described by `RFC 3986, section 5.2 `_. -To save you some time, here are some examples of how the combinations are resolved. - - ===================== ================ ======================== - baseURI URI Result - ===================== ================ ======================== - \http://foo.com /bar \http://foo.com/bar - \http://foo.com/foo /bar \http://foo.com/bar - \http://foo.com/foo bar \http://foo.com/bar - \http://foo.com/foo/ bar \http://foo.com/foo/bar - \http://foo.com \http://baz.com \http://baz.com - \http://foo.com/?bar bar \http://foo.com/bar - ===================== ================ ======================== - -Using Responses -=============== - -Each ``request()`` call returns a Response object that contains a lot of useful information and some helpful methods. -The most commonly used methods let you determine the response itself. - -You can get the status code and reason phrase of the response: - -.. literalinclude:: curlrequest/009.php - -You can retrieve headers from the response: - -.. literalinclude:: curlrequest/010.php - -The body can be retrieved using the ``getBody()`` method: - -.. literalinclude:: curlrequest/011.php - -The body is the raw body provided by the remote server. If the content type requires formatting, you will need to ensure -that your script handles that: - -.. literalinclude:: curlrequest/012.php - -*************** -Request Options -*************** - -This section describes all of the available options you may pass into the constructor, the ``request()`` method, or any -of the shortcut methods. - -allow_redirects -=============== - -By default, cURL will not follow any "Location:" headers the remote servers send back. The ``allow_redirects`` option -allows you to modify how that works. - -If you set the value to ``true``, then it will follow redirects: - -.. literalinclude:: curlrequest/014.php - -.. warning:: Please note that enabling redirects may redirect to a URL that you do not expect and may enable SSRF - attacks. - -Setting it to ``false`` will apply the default settings to the request: - -.. literalinclude:: curlrequest/013.php - -You can pass in an array as the value of the ``allow_redirects`` option to specify new settings in place of the -defaults: - -.. literalinclude:: curlrequest/015.php - -.. note:: Following redirects does not work when PHP's ``open_basedir`` restriction is enabled. - -auth -==== - -Allows you to provide Authentication details for `HTTP Basic `_ and -`Digest `_ authentication. Your script may have to do extra work to support Digest -authentication - this simply passes the username and password along for you. The value must be an array where the first -element is the username, and the second is the password. The third parameter should be the type of authentication to -use, either ``basic`` or ``digest``: - -.. literalinclude:: curlrequest/016.php - -body -==== - -There are two ways to set the body of the request for request types that support it, like PUT or POST. The first way is -to use the ``setBody()`` method: - -.. literalinclude:: curlrequest/017.php - -The second method is by passing a ``body`` option in. This is provided to maintain Guzzle API compatibility, and -functions the exact same way as the previous example. The value must be a string: - -.. literalinclude:: curlrequest/018.php - -cert -==== - -To specify the location of a PEM-formatted client-side certificate, pass a string with the full path to the file as the -``cert`` option. If a password is required, set the value to an array with the first element as the path to the -certificate, and the second as the password: - -.. literalinclude:: curlrequest/019.php - -connect_timeout -=============== - -By default, CodeIgniter does not impose a limit for cURL to attempt to connect to a website. If you need to modify this -value, you can do so by passing the amount of time in seconds with the ``connect_timeout`` option. You can pass 0 to -wait indefinitely: - -.. literalinclude:: curlrequest/020.php - -cookie -====== - -This specifies the filename that CURL should use to read cookie values from, and to save cookie values to. This is done -using the ``CURLOPT_COOKIEJAR`` and ``CURLOPT_COOKIEFILE`` options. An example: - -.. literalinclude:: curlrequest/021.php - -debug -===== - -When ``debug`` is passed and set to ``true``, this will enable additional debugging to echo to STDERR during the script -execution. - -This is done by passing ``CURLOPT_VERBOSE`` and echoing the output. So, when you're running a built-in server via -``spark serve``, you will see the output in the console. Otherwise, the output will be written to the server's error -log. - -.. literalinclude:: curlrequest/034.php - -You can pass a filename as the value for debug to have the output written to a file: - -.. literalinclude:: curlrequest/022.php - -delay -===== - -Allows you to pause for a number of milliseconds before sending the request: - -.. literalinclude:: curlrequest/023.php - -dns_cache_timeout -================= - -.. versionadded:: 4.7.0 - -By default, CodeIgniter does not change the DNS Cache Timeout value (``120`` seconds). If you need to modify this value, -you can do so by passing an amount of time in seconds with the ``dns_cache_timeout`` option. - -.. literalinclude:: curlrequest/037.php - -.. note:: Based on the `libcurl `__ documentation, you can set - it to zero (``0``) to completely disable caching, or set to ``-1`` to make the cached entries remain forever. - -form_params -=========== - -You can send form data in an application/x-www-form-urlencoded POST request by passing an associative array in the -``form_params`` option. This will set the ``Content-Type`` header to ``application/x-www-form-urlencoded`` if it's not -already set: - -.. literalinclude:: curlrequest/024.php - -.. note:: ``form_params`` cannot be used with the `multipart`_ option. You will need to use one or the other. Use - ``form_params`` for ``application/x-www-form-urlencoded`` requests, and ``multipart`` for ``multipart/form-data`` - requests. - -fresh_connect -============= - -.. versionadded:: 4.7.0 - -By default, the request is sent using a fresh connection. You can disable this behavior using the ``fresh_connect`` -option: - -.. literalinclude:: curlrequest/038.php - -.. _curlrequest-request-options-headers: - -headers -======= - -While you can set any headers this request needs by using the ``setHeader()`` method, you can also pass an associative -array of headers in as an option. Each key is the name of a header, and each value is a string or array of strings -representing the header field values: - -.. literalinclude:: curlrequest/025.php - -If headers are passed into the constructor, they are treated as default values that will be overridden later by any -further headers arrays or calls to ``setHeader()``. - -http_errors -=========== - -By default, CURLRequest will throw ``HTTPException`` if the HTTP code returned is greater than or equal to 400. - -If you want to see the response body, you can set ``http_errors`` to ``false`` to return the content instead: - -.. literalinclude:: curlrequest/026.php - -json -==== - -The ``json`` option is used to easily upload JSON-encoded data as the body of a request. A Content-Type header of -``application/json`` is added, overwriting any Content-Type that might already be set. The data provided to this option -can be any value that ``json_encode()`` accepts: - -.. literalinclude:: curlrequest/027.php - -.. note:: This option does not allow for any customization of the ``json_encode()`` function, or the Content-Type - header. If you need that ability, you will need to encode the data manually, pass it through the ``setBody()`` - method of CURLRequest, and set the Content-Type header with the ``setHeader()`` method. - -multipart -========= - -When you need to send files and other data via a POST request, you can use the ``multipart`` option, along with the -`CURLFile Class `_. - -The values should be an associative array of POST data to send. For safer usage, the legacy method of uploading files by -prefixing their name with an ``@`` has been disabled. Any files that you want to send must be passed as instances of -CURLFile: - -.. literalinclude:: curlrequest/028.php - -.. note:: ``multipart`` cannot be used with the `form_params`_ option. You can only use one or the other. Use - ``form_params`` for ``application/x-www-form-urlencoded`` requests, and ``multipart`` for ``multipart/form-data`` - requests. - -.. _curlrequest-request-options-proxy: - -proxy -===== - -.. versionadded:: 4.4.0 - -You can set a proxy by passing an associative array as the ``proxy`` option: - -.. literalinclude:: curlrequest/035.php - -query -===== - -You can pass along data to send as query string variables by passing an associative array as the ``query`` option: - -.. literalinclude:: curlrequest/029.php - -timeout -======= - -By default, cURL functions are allowed to run as long as they take, with no time limit. You can modify this with the -``timeout`` option. The value should be the number of seconds you want the functions to execute for. Use 0 to wait -indefinitely: - -.. literalinclude:: curlrequest/030.php - -user_agent -========== - -Allows specifying the User Agent for requests: - -.. literalinclude:: curlrequest/031.php - -verify -====== - -This option describes the SSL certificate verification behavior. If the ``verify`` option is ``true``, it enables the -SSL certificate verification and uses the default CA bundle provided by the operating system. If set to ``false``, it -will disable the certificate verification (this is insecure, and allows man-in-the-middle attacks!). You can set it to a -string that contains the path to a CA bundle to enable verification with a custom certificate. The default value is -true: - -.. literalinclude:: curlrequest/032.php - -force_ip_resolve -================ - -.. versionadded:: 4.6.0 - -To set the HTTP handlers to use only the IPv4 protocol (``v4``) or the IPv6 protocol (``v6``): - -.. literalinclude:: curlrequest/036.php - -.. _curlrequest-version: - -version -======= - -To set the HTTP protocol to use, you can pass a string or float with the version number (typically either ``1.0`` or -``1.1``, with ``2.0`` supported since v4.3.0): - -.. literalinclude:: curlrequest/033.php diff --git a/user_guide_src/source/libraries/curlrequest/001.php b/user_guide_src/source/libraries/curlrequest/001.php deleted file mode 100644 index 303366336dbb..000000000000 --- a/user_guide_src/source/libraries/curlrequest/001.php +++ /dev/null @@ -1,11 +0,0 @@ - 'http://example.com/api/v1/', - 'timeout' => 3, -]; -$client = service('curlrequest', $options); diff --git a/user_guide_src/source/libraries/curlrequest/004.php b/user_guide_src/source/libraries/curlrequest/004.php deleted file mode 100644 index a3bd961b68f8..000000000000 --- a/user_guide_src/source/libraries/curlrequest/004.php +++ /dev/null @@ -1,10 +0,0 @@ -request('GET', 'https://api.github.com/user', [ - 'auth' => ['user', 'pass'], -]); diff --git a/user_guide_src/source/libraries/curlrequest/006.php b/user_guide_src/source/libraries/curlrequest/006.php deleted file mode 100644 index 87cac0459a54..000000000000 --- a/user_guide_src/source/libraries/curlrequest/006.php +++ /dev/null @@ -1,6 +0,0 @@ -getStatusCode(); -echo $response->getBody(); -echo $response->header('Content-Type'); -$language = $response->negotiateLanguage(['en', 'fr']); diff --git a/user_guide_src/source/libraries/curlrequest/007.php b/user_guide_src/source/libraries/curlrequest/007.php deleted file mode 100644 index d509f3e3fa29..000000000000 --- a/user_guide_src/source/libraries/curlrequest/007.php +++ /dev/null @@ -1,9 +0,0 @@ -get('http://example.com'); -$client->delete('http://example.com'); -$client->head('http://example.com'); -$client->options('http://example.com'); -$client->patch('http://example.com'); -$client->put('http://example.com'); -$client->post('http://example.com'); diff --git a/user_guide_src/source/libraries/curlrequest/008.php b/user_guide_src/source/libraries/curlrequest/008.php deleted file mode 100644 index 2f14c6974cd0..000000000000 --- a/user_guide_src/source/libraries/curlrequest/008.php +++ /dev/null @@ -1,11 +0,0 @@ - 'https://example.com/api/v1/', -]); - -// GET http:example.com/api/v1/photos -$client->get('photos'); - -// GET http:example.com/api/v1/photos/13 -$client->delete('photos/13'); diff --git a/user_guide_src/source/libraries/curlrequest/009.php b/user_guide_src/source/libraries/curlrequest/009.php deleted file mode 100644 index 934213024009..000000000000 --- a/user_guide_src/source/libraries/curlrequest/009.php +++ /dev/null @@ -1,4 +0,0 @@ -getStatusCode(); // 200 -$reason = $response->getReasonPhrase(); // OK diff --git a/user_guide_src/source/libraries/curlrequest/010.php b/user_guide_src/source/libraries/curlrequest/010.php deleted file mode 100644 index 265146c9dada..000000000000 --- a/user_guide_src/source/libraries/curlrequest/010.php +++ /dev/null @@ -1,9 +0,0 @@ -getHeaderLine('Content-Type'); - -// Get all headers -foreach ($response->headers() as $name => $value) { - echo $name . ': ' . $response->getHeaderLine($name) . "\n"; -} diff --git a/user_guide_src/source/libraries/curlrequest/011.php b/user_guide_src/source/libraries/curlrequest/011.php deleted file mode 100644 index ee93e3dac0e9..000000000000 --- a/user_guide_src/source/libraries/curlrequest/011.php +++ /dev/null @@ -1,3 +0,0 @@ -getBody(); diff --git a/user_guide_src/source/libraries/curlrequest/012.php b/user_guide_src/source/libraries/curlrequest/012.php deleted file mode 100644 index dfb37fa57bcc..000000000000 --- a/user_guide_src/source/libraries/curlrequest/012.php +++ /dev/null @@ -1,5 +0,0 @@ -header('content-type'), 'application/json')) { - $body = json_decode($body); -} diff --git a/user_guide_src/source/libraries/curlrequest/013.php b/user_guide_src/source/libraries/curlrequest/013.php deleted file mode 100644 index 342b6af55ea7..000000000000 --- a/user_guide_src/source/libraries/curlrequest/013.php +++ /dev/null @@ -1,3 +0,0 @@ -request('GET', 'http://example.com', ['allow_redirects' => false]); diff --git a/user_guide_src/source/libraries/curlrequest/014.php b/user_guide_src/source/libraries/curlrequest/014.php deleted file mode 100644 index 25e3176b0a5a..000000000000 --- a/user_guide_src/source/libraries/curlrequest/014.php +++ /dev/null @@ -1,9 +0,0 @@ -request('GET', 'http://example.com', ['allow_redirects' => true]); -/* - * Sets the following defaults: - * 'max' => 5, // Maximum number of redirects to follow before stopping - * 'strict' => true, // Ensure POST requests stay POST requests through redirects - * 'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols - */ diff --git a/user_guide_src/source/libraries/curlrequest/015.php b/user_guide_src/source/libraries/curlrequest/015.php deleted file mode 100644 index 136a6ca13286..000000000000 --- a/user_guide_src/source/libraries/curlrequest/015.php +++ /dev/null @@ -1,6 +0,0 @@ -request('GET', 'http://example.com', ['allow_redirects' => [ - 'max' => 10, - 'protocols' => ['https'], // Force HTTPS domains only. -]]); diff --git a/user_guide_src/source/libraries/curlrequest/016.php b/user_guide_src/source/libraries/curlrequest/016.php deleted file mode 100644 index 3c3fa945f535..000000000000 --- a/user_guide_src/source/libraries/curlrequest/016.php +++ /dev/null @@ -1,3 +0,0 @@ -request('GET', 'http://example.com', ['auth' => ['username', 'password', 'digest']]); diff --git a/user_guide_src/source/libraries/curlrequest/017.php b/user_guide_src/source/libraries/curlrequest/017.php deleted file mode 100644 index c88ba46b553b..000000000000 --- a/user_guide_src/source/libraries/curlrequest/017.php +++ /dev/null @@ -1,3 +0,0 @@ -setBody($body)->request('PUT', 'http://example.com'); diff --git a/user_guide_src/source/libraries/curlrequest/018.php b/user_guide_src/source/libraries/curlrequest/018.php deleted file mode 100644 index 739784bc8152..000000000000 --- a/user_guide_src/source/libraries/curlrequest/018.php +++ /dev/null @@ -1,3 +0,0 @@ -request('PUT', 'http://example.com', ['body' => $body]); diff --git a/user_guide_src/source/libraries/curlrequest/019.php b/user_guide_src/source/libraries/curlrequest/019.php deleted file mode 100644 index 9c74dd29ca58..000000000000 --- a/user_guide_src/source/libraries/curlrequest/019.php +++ /dev/null @@ -1,3 +0,0 @@ -request('GET', '/', ['cert' => ['/path/server.pem', 'password']]); diff --git a/user_guide_src/source/libraries/curlrequest/020.php b/user_guide_src/source/libraries/curlrequest/020.php deleted file mode 100644 index 14fad31cdea4..000000000000 --- a/user_guide_src/source/libraries/curlrequest/020.php +++ /dev/null @@ -1,3 +0,0 @@ -request('GET', 'http://example.com', ['connect_timeout' => 0]); diff --git a/user_guide_src/source/libraries/curlrequest/021.php b/user_guide_src/source/libraries/curlrequest/021.php deleted file mode 100644 index 051df32e1a37..000000000000 --- a/user_guide_src/source/libraries/curlrequest/021.php +++ /dev/null @@ -1,3 +0,0 @@ -request('GET', 'http://example.com', ['cookie' => WRITEPATH . 'CookieSaver.txt']); diff --git a/user_guide_src/source/libraries/curlrequest/022.php b/user_guide_src/source/libraries/curlrequest/022.php deleted file mode 100644 index 69b0e4ed8bec..000000000000 --- a/user_guide_src/source/libraries/curlrequest/022.php +++ /dev/null @@ -1,3 +0,0 @@ -request('GET', 'http://example.com', ['debug' => '/usr/local/curl_log.txt']); diff --git a/user_guide_src/source/libraries/curlrequest/023.php b/user_guide_src/source/libraries/curlrequest/023.php deleted file mode 100644 index 61e6f6df5214..000000000000 --- a/user_guide_src/source/libraries/curlrequest/023.php +++ /dev/null @@ -1,4 +0,0 @@ -request('GET', 'http://example.com', ['delay' => 2000]); diff --git a/user_guide_src/source/libraries/curlrequest/024.php b/user_guide_src/source/libraries/curlrequest/024.php deleted file mode 100644 index bbc6285e0eec..000000000000 --- a/user_guide_src/source/libraries/curlrequest/024.php +++ /dev/null @@ -1,8 +0,0 @@ -request('POST', '/post', [ - 'form_params' => [ - 'foo' => 'bar', - 'baz' => ['hi', 'there'], - ], -]); diff --git a/user_guide_src/source/libraries/curlrequest/025.php b/user_guide_src/source/libraries/curlrequest/025.php deleted file mode 100644 index 5f1818a7fe0b..000000000000 --- a/user_guide_src/source/libraries/curlrequest/025.php +++ /dev/null @@ -1,9 +0,0 @@ -request('GET', '/', [ - 'headers' => [ - 'User-Agent' => 'testing/1.0', - 'Accept' => 'application/json', - 'X-Foo' => ['Bar', 'Baz'], - ], -]); diff --git a/user_guide_src/source/libraries/curlrequest/026.php b/user_guide_src/source/libraries/curlrequest/026.php deleted file mode 100644 index 6c42894547bd..000000000000 --- a/user_guide_src/source/libraries/curlrequest/026.php +++ /dev/null @@ -1,9 +0,0 @@ -request('GET', '/status/500'); -// If the response code is 500, an HTTPException is thrown, -// and a detailed error report is displayed if in development mode. - -$response = $client->request('GET', '/status/500', ['http_errors' => false]); -echo $response->getStatusCode(); // 500 -echo $response->getBody(); // You can see the response body. diff --git a/user_guide_src/source/libraries/curlrequest/027.php b/user_guide_src/source/libraries/curlrequest/027.php deleted file mode 100644 index bd91655f3dbe..000000000000 --- a/user_guide_src/source/libraries/curlrequest/027.php +++ /dev/null @@ -1,3 +0,0 @@ -request('PUT', '/put', ['json' => ['foo' => 'bar']]); diff --git a/user_guide_src/source/libraries/curlrequest/028.php b/user_guide_src/source/libraries/curlrequest/028.php deleted file mode 100644 index e56b96b127a5..000000000000 --- a/user_guide_src/source/libraries/curlrequest/028.php +++ /dev/null @@ -1,8 +0,0 @@ -request('POST', '/post', [ - 'multipart' => [ - 'foo' => 'bar', - 'userfile' => new \CURLFile('/path/to/file.txt'), - ], -]); diff --git a/user_guide_src/source/libraries/curlrequest/029.php b/user_guide_src/source/libraries/curlrequest/029.php deleted file mode 100644 index 7a19976bd0a2..000000000000 --- a/user_guide_src/source/libraries/curlrequest/029.php +++ /dev/null @@ -1,4 +0,0 @@ -request('GET', '/get', ['query' => ['foo' => 'bar']]); diff --git a/user_guide_src/source/libraries/curlrequest/030.php b/user_guide_src/source/libraries/curlrequest/030.php deleted file mode 100644 index 16c0c6fd6c49..000000000000 --- a/user_guide_src/source/libraries/curlrequest/030.php +++ /dev/null @@ -1,3 +0,0 @@ -request('GET', 'http://example.com', ['timeout' => 5]); diff --git a/user_guide_src/source/libraries/curlrequest/031.php b/user_guide_src/source/libraries/curlrequest/031.php deleted file mode 100644 index 8023c84faa39..000000000000 --- a/user_guide_src/source/libraries/curlrequest/031.php +++ /dev/null @@ -1,3 +0,0 @@ -request('GET', 'http://example.com', ['user_agent' => 'CodeIgniter Framework v4']); diff --git a/user_guide_src/source/libraries/curlrequest/032.php b/user_guide_src/source/libraries/curlrequest/032.php deleted file mode 100644 index 13e2fba21f04..000000000000 --- a/user_guide_src/source/libraries/curlrequest/032.php +++ /dev/null @@ -1,10 +0,0 @@ -request('GET', '/', ['verify' => true]); - -// Use a custom SSL certificate on disk. -$client->request('GET', '/', ['verify' => '/path/to/cert.pem']); - -// Disable validation entirely. (Insecure!) -$client->request('GET', '/', ['verify' => false]); diff --git a/user_guide_src/source/libraries/curlrequest/033.php b/user_guide_src/source/libraries/curlrequest/033.php deleted file mode 100644 index a7a8df45589c..000000000000 --- a/user_guide_src/source/libraries/curlrequest/033.php +++ /dev/null @@ -1,4 +0,0 @@ -request('GET', '/', ['version' => 1.0]); diff --git a/user_guide_src/source/libraries/curlrequest/034.php b/user_guide_src/source/libraries/curlrequest/034.php deleted file mode 100644 index 9e343aa9d9da..000000000000 --- a/user_guide_src/source/libraries/curlrequest/034.php +++ /dev/null @@ -1,3 +0,0 @@ -request('GET', 'http://example.com', ['debug' => true]); diff --git a/user_guide_src/source/libraries/curlrequest/035.php b/user_guide_src/source/libraries/curlrequest/035.php deleted file mode 100644 index 2b2344a1d628..000000000000 --- a/user_guide_src/source/libraries/curlrequest/035.php +++ /dev/null @@ -1,7 +0,0 @@ -request( - 'GET', - 'http://example.com', - ['proxy' => 'http://localhost:3128'], -); diff --git a/user_guide_src/source/libraries/curlrequest/036.php b/user_guide_src/source/libraries/curlrequest/036.php deleted file mode 100644 index a02787d184bb..000000000000 --- a/user_guide_src/source/libraries/curlrequest/036.php +++ /dev/null @@ -1,4 +0,0 @@ -request('GET', '/', ['force_ip_resolve' => 'v4']); // v4 or v6 diff --git a/user_guide_src/source/libraries/curlrequest/037.php b/user_guide_src/source/libraries/curlrequest/037.php deleted file mode 100644 index 7d71d90bec70..000000000000 --- a/user_guide_src/source/libraries/curlrequest/037.php +++ /dev/null @@ -1,4 +0,0 @@ -request('GET', '/', ['dns_cache_timeout' => 360]); // seconds diff --git a/user_guide_src/source/libraries/curlrequest/038.php b/user_guide_src/source/libraries/curlrequest/038.php deleted file mode 100644 index 83e971d2782a..000000000000 --- a/user_guide_src/source/libraries/curlrequest/038.php +++ /dev/null @@ -1,4 +0,0 @@ -request('GET', 'http://example.com', ['fresh_connect' => true]); -$client->request('GET', 'http://example.com', ['fresh_connect' => false]); diff --git a/user_guide_src/source/libraries/curlrequest/039.php b/user_guide_src/source/libraries/curlrequest/039.php deleted file mode 100644 index 9dda44d9312c..000000000000 --- a/user_guide_src/source/libraries/curlrequest/039.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * @see https://www.php.net/manual/en/curl.constants.php#constant.curl-lock-data-connect - */ - public array $shareConnection = [ - CURL_LOCK_DATA_CONNECT, - CURL_LOCK_DATA_DNS, - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/curlrequest/040.php b/user_guide_src/source/libraries/curlrequest/040.php deleted file mode 100644 index bd68f56a04b8..000000000000 --- a/user_guide_src/source/libraries/curlrequest/040.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * @see https://www.php.net/manual/en/curl.constants.php#constant.curl-lock-data-connect - */ - public array $shareConnection = []; - - // ... -} diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst deleted file mode 100644 index 335adf1ab7db..000000000000 --- a/user_guide_src/source/libraries/email.rst +++ /dev/null @@ -1,375 +0,0 @@ -########### -Email Class -########### - -CodeIgniter's robust Email Class supports the following features: - -- Multiple Protocols: Mail, Sendmail, and SMTP -- TLS and SSL Encryption for SMTP -- Multiple recipients -- CC and BCCs -- HTML or Plaintext email -- Attachments -- Word wrapping -- Priorities -- BCC Batch Mode, enabling large email lists to be broken into small BCC batches. -- Email Debugging tools - -.. contents:: - :local: - :depth: 3 - -*********************** -Using the Email Library -*********************** - -Sending Email -============= - -Sending email is not only simple, but you can configure it on the fly or set your preferences in the -**app/Config/Email.php** file. - -Here is a basic example demonstrating how you might send email: - -.. literalinclude:: email/001.php - -.. _setting-email-preferences: - -Setting Email Preferences -========================= - -There are several preferences available to tailor how your email messages are sent. You can either set them manually as -described here, or automatically via preferences stored in your config file, described in `Email Preferences`_. - -Setting Email Preferences by Passing an Array ---------------------------------------------- - -Preferences are set by passing an array of preference values to the email initialize method. Here is an example of how -you might set some preferences: - -.. literalinclude:: email/002.php - -.. note:: Most of the preferences have default values that will be used if you do not set them. - -Setting Email Preferences in a Config File ------------------------------------------- - -If you prefer not to set preferences using the above method, you can instead put them into the config file. Simply open -the **app/Config/Email.php** file, and set your configs in the Email properties. Then save the file and it will be used -automatically. You will NOT need to use the ``$email->initialize()`` method if you set your preferences in the config -file. - -.. _email-ssl-tls-for-smtp: - -SSL versus TLS for SMTP Protocol --------------------------------- - -To protect the username, password and email content while communicating with the SMTP server, encryption on the channel -should be used. Two different standards are widely deployed and it is important to understand the differences when -trying to troubleshoot email sending issues. - -Most SMTP servers allow connections on ports 465 or 587 when submitting emails. (The original port 25 is seldom used -because many ISPs have blocking rules in place and because the communication is entirely in clear text.) - -The key difference is that port 465 expects the communication channel to be secured using TLS from the start as per -`RFC 8314 `_. A connection to port 587 allows a clear-text connection and later -will upgrade the channel to use encryption using the ``STARTTLS`` SMTP command. - -Upgrading a connection on port 465 may or may not be supported by the server, so the ``STARTTLS`` SMTP command may fail -if the server does not allow it. If you set the port to 465, you should try to set ``SMTPCrypto`` to an empty string -(``''``) since the communication is secured using TLS from the start and ``STARTTLS`` is not needed. - -If your configuration requires you to connect to port 587, you should most likely set ``SMTPCrypto`` to ``tls`` as this -will implement the ``STARTTLS`` command while communicating with the SMTP server to switch from clear text to an -encrypted channel. The initial communication will be made in clear text and the channel will be upgraded to TLS with the -``STARTTLS`` command. - -Reviewing Preferences ---------------------- - -The settings used for the last successful send are available from the instance property ``$archive``. This is helpful -for testing and debugging to determine the actual values at the time of the ``send()`` call. - -.. _email-preferences: - -Email Preferences -================= - -The following is a list of all the preferences that can be set when sending email. - -=================== =================== ============================ ======================================================================= -Preference Default Value Options Description -=================== =================== ============================ ======================================================================= -**fromEmail** The email address to be set in the "from" header. -**fromName** The name to be set in the "from" header. -**userAgent** CodeIgniter The "user agent". -**protocol** mail ``mail``, ``sendmail``, The mail sending protocol. - or ``smtp`` -**mailPath** /usr/sbin/sendmail The server path to Sendmail. -**SMTPHost** SMTP Server Hostname. -**SMTPAuthMethod** login ``login``, ``plain`` SMTP Authentication Method. (Available since 4.7.0) -**SMTPUser** SMTP Username. -**SMTPPass** SMTP Password. -**SMTPPort** 25 SMTP Port. (If set to ``465``, TLS will be used for the connection - regardless of the ``SMTPCrypto`` setting.) -**SMTPTimeout** 5 SMTP Timeout (in seconds). -**SMTPKeepAlive** false ``true``/``false`` Enable persistent SMTP connections. -**SMTPCrypto** tls ``tls``, ``ssl``, or SMTP Encryption. Setting this to ``ssl`` will create a secure - empty string (``''``) channel to the server using SSL, and ``tls`` will issue a - ``STARTTLS`` command to the server. Connections on port ``465`` should - set this to an empty string (``''``). See also - :ref:`email-ssl-tls-for-smtp`. -**wordWrap** true ``true``/``false`` Enable word-wrap. -**wrapChars** 76 Character count to wrap at. -**mailType** text ``text`` or ``html`` Type of mail. If you send HTML email you must send it as a complete web - page. Make sure you don't have any relative links or relative image - paths, otherwise they will not work. -**charset** UTF-8 Character set (``utf-8``, ``iso-8859-1``, etc.). -**validate** false ``true``/``false`` Whether to validate the email address. -**priority** 3 1, 2, 3, 4, 5 Email Priority. ``1`` = highest. ``5`` = lowest. ``3`` = normal. -**CRLF** \\r\\n ``\r\n``, ``\n`` or ``\r`` Newline character. (Use ``\r\n`` to comply with RFC 822). -**newline** \\r\\n ``\r\n``, ``\n`` or ``\r`` Newline character. (Use ``\r\n`` to comply with RFC 822). -**BCCBatchMode** false ``true``/``false`` Enable BCC Batch Mode. -**BCCBatchSize** 200 Number of emails in each BCC batch. -**DSN** false ``true``/``false`` Enable notification messages from the server. -=================== =================== ============================ ======================================================================= - -The defaults above reflect **app/Config/Email.php**, which is used by the Email service. If you instantiate -``CodeIgniter\Email\Email`` directly without a configuration object, its ``$validate`` property defaults to ``true``. - -Overriding Word Wrapping -======================== - -If you have word wrapping enabled (recommended to comply with RFC 822) and you have a very long link in your email, it -can get wrapped too, causing it to become unclickable by the person receiving it. CodeIgniter lets you manually override -word wrapping within part of your message like this:: - - The text of your email that - gets wrapped normally. - - {unwrap}http://example.com/a_long_link_that_should_not_be_wrapped.html{/unwrap} - - More text that will be - wrapped normally. - -Place the item you do not want word-wrapped between: {unwrap} {/unwrap} - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\Email - -.. php:class:: Email - - .. php:method:: setFrom($from[, $name = ''[, $returnPath = null]]) - - :param string $from: "From" email address - :param string $name: "From" display name - :param string $returnPath: Optional email address to redirect undelivered email to - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Sets the email address and name of the person sending the email: - - .. literalinclude:: email/003.php - - You can also set a Return-Path, to help redirect undelivered mail: - - .. literalinclude:: email/004.php - - .. note:: Return-Path can't be used if you've configured 'smtp' as your protocol. - - .. php:method:: setReplyTo($replyto[, $name = '']) - - :param string $replyto: Email address for replies - :param string $name: Display name for the reply-to email address - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Sets the reply-to address. If the information is not provided, the information in the :php:meth:`setFrom()` - method is used. Example: - - .. literalinclude:: email/005.php - - .. php:method:: setTo($to) - - :param mixed $to: Comma-separated string or an array of email addresses - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Sets the email address(es) of the recipient(s). Can be a single email, a comma-separated list, or an array: - - .. literalinclude:: email/006.php - - .. literalinclude:: email/007.php - - .. literalinclude:: email/008.php - - .. php:method:: setCC($cc) - - :param mixed $cc: Comma-separated string or an array of email addresses - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Sets the CC email address(es). Just like the "to" address, it can be a single email, a comma-separated list, or - an array. - - .. php:method:: setBCC($bcc[, $limit = '']) - - :param mixed $bcc: Comma-separated string or an array of email addresses - :param int $limit: Maximum number of emails to send per batch - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Sets the BCC email address(es). Just like the ``setTo()`` method, it can be a single email, a comma-separated - list, or an array. - - If ``$limit`` is set, "batch mode" will be enabled, which will send the emails in batches, with each batch not - exceeding the specified ``$limit``. - - .. php:method:: setSubject($subject) - - :param string $subject: Email subject line - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Sets the email subject: - - .. literalinclude:: email/009.php - - .. php:method:: setMessage($body) - - :param string $body: Email message body - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Sets the email message body: - - .. literalinclude:: email/010.php - - .. php:method:: setAltMessage($str) - - :param string $str: Alternative email message body - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Sets the alternative email message body: - - .. literalinclude:: email/011.php - - This is an optional message string which can be used if you send HTML-formatted email. It lets you specify an - alternative message with no HTML formatting which is added to the header string for people who do not accept - HTML email. If you do not set your own message, CodeIgniter will extract the message from your HTML email and - strip the tags. - - .. php:method:: setHeader($header, $value) - - :param string $header: Header name - :param string $value: Header value - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Appends additional headers to the email: - - .. literalinclude:: email/012.php - - .. php:method:: clear($clearAttachments = false) - - :param bool $clearAttachments: Whether or not to clear attachments - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Initializes all the email variables to an empty state. This method is intended for use if you run the email - sending method in a loop, permitting the data to be reset between cycles. - - .. literalinclude:: email/013.php - - If you set the parameter to true, any attachments will be cleared as well: - - .. literalinclude:: email/014.php - - .. php:method:: send($autoClear = true) - - :param bool $autoClear: Whether to clear message data automatically - :returns: true on success, false on failure - :rtype: bool - - The email sending method. Returns boolean true or false based on success or failure, enabling it to be used - conditionally: - - .. literalinclude:: email/015.php - - This method will automatically clear all parameters if the request was successful. To stop this behaviour, pass - false: - - .. literalinclude:: email/016.php - - .. note:: In order to use the ``printDebugger()`` method, you need to avoid clearing the email parameters. - - .. note:: If ``BCCBatchMode`` is enabled, and there are more than ``BCCBatchSize`` recipients, this method will - always return boolean ``true``. - - .. php:method:: attach($filename[, $disposition = ''[, $newname = null[, $mime = '']]]) - - :param string $filename: File name - :param string $disposition: 'disposition' of the attachment. Most - email clients make their own decision regardless of the MIME - specification used here. https://www.iana.org/assignments/cont-disp/cont-disp.xhtml - :param string $newname: Custom file name to use in the email - :param string $mime: MIME type to use (useful for buffered data) - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email - - Enables you to send an attachment. Put the file path/name in the first parameter. For multiple attachments, use - the method multiple times. For example: - - .. literalinclude:: email/017.php - - To use the default disposition (attachment), leave the second parameter blank. Otherwise, use a custom - disposition: - - .. literalinclude:: email/018.php - - You can also use a URL: - - .. literalinclude:: email/019.php - - If you'd like to use a custom file name, you can use the third parameter: - - .. literalinclude:: email/020.php - - If you need to use a buffer string instead of a real (physical) file, you can use the first parameter as the - buffer, the third parameter as the file name, and the fourth parameter as the MIME type: - - .. literalinclude:: email/021.php - - .. php:method:: setAttachmentCID($filename) - - :param string $filename: Existing attachment filename - :returns: Attachment Content-ID or false if not found - :rtype: string - - Sets and returns an attachment's Content-ID, which enables you to embed an inline (picture) attachment into - HTML. The first parameter must be the already attached file name. - - .. literalinclude:: email/022.php - - .. note:: Content-ID for each email must be re-created for it to be unique. - - .. php:method:: printDebugger($include = ['headers', 'subject', 'body']) - - :param array $include: Which parts of the message to print out - :returns: Formatted debug data - :rtype: string - - Returns a string containing any server messages, the email headers, and the email message. Useful for debugging. - - You can optionally specify which parts of the message should be printed. Valid options are: **headers**, - **subject**, **body**. - - Example: - - .. literalinclude:: email/023.php - - .. note:: By default, all of the raw data will be printed. diff --git a/user_guide_src/source/libraries/email/001.php b/user_guide_src/source/libraries/email/001.php deleted file mode 100644 index f7873714bab5..000000000000 --- a/user_guide_src/source/libraries/email/001.php +++ /dev/null @@ -1,13 +0,0 @@ -setFrom('your@example.com', 'Your Name'); -$email->setTo('someone@example.com'); -$email->setCC('another@another-example.com'); -$email->setBCC('them@their-example.com'); - -$email->setSubject('Email Test'); -$email->setMessage('Testing the email class.'); - -$email->send(); diff --git a/user_guide_src/source/libraries/email/002.php b/user_guide_src/source/libraries/email/002.php deleted file mode 100644 index 02268ee6079d..000000000000 --- a/user_guide_src/source/libraries/email/002.php +++ /dev/null @@ -1,8 +0,0 @@ -initialize($config); diff --git a/user_guide_src/source/libraries/email/003.php b/user_guide_src/source/libraries/email/003.php deleted file mode 100644 index b2ade5bab56b..000000000000 --- a/user_guide_src/source/libraries/email/003.php +++ /dev/null @@ -1,3 +0,0 @@ -setFrom('you@example.com', 'Your Name'); diff --git a/user_guide_src/source/libraries/email/004.php b/user_guide_src/source/libraries/email/004.php deleted file mode 100644 index 9d8195de4ea5..000000000000 --- a/user_guide_src/source/libraries/email/004.php +++ /dev/null @@ -1,3 +0,0 @@ -setFrom('you@example.com', 'Your Name', 'returned_emails@example.com'); diff --git a/user_guide_src/source/libraries/email/005.php b/user_guide_src/source/libraries/email/005.php deleted file mode 100644 index ba6033c281c0..000000000000 --- a/user_guide_src/source/libraries/email/005.php +++ /dev/null @@ -1,3 +0,0 @@ -setReplyTo('you@example.com', 'Your Name'); diff --git a/user_guide_src/source/libraries/email/006.php b/user_guide_src/source/libraries/email/006.php deleted file mode 100644 index 1998618a5b5f..000000000000 --- a/user_guide_src/source/libraries/email/006.php +++ /dev/null @@ -1,3 +0,0 @@ -setTo('someone@example.com'); diff --git a/user_guide_src/source/libraries/email/007.php b/user_guide_src/source/libraries/email/007.php deleted file mode 100644 index b0622d0ac56f..000000000000 --- a/user_guide_src/source/libraries/email/007.php +++ /dev/null @@ -1,3 +0,0 @@ -setTo('one@example.com, two@example.com, three@example.com'); diff --git a/user_guide_src/source/libraries/email/008.php b/user_guide_src/source/libraries/email/008.php deleted file mode 100644 index d3ac20661d04..000000000000 --- a/user_guide_src/source/libraries/email/008.php +++ /dev/null @@ -1,3 +0,0 @@ -setTo(['one@example.com', 'two@example.com', 'three@example.com']); diff --git a/user_guide_src/source/libraries/email/009.php b/user_guide_src/source/libraries/email/009.php deleted file mode 100644 index 566736474df4..000000000000 --- a/user_guide_src/source/libraries/email/009.php +++ /dev/null @@ -1,3 +0,0 @@ -setSubject('This is my subject'); diff --git a/user_guide_src/source/libraries/email/010.php b/user_guide_src/source/libraries/email/010.php deleted file mode 100644 index 6383ac2e112d..000000000000 --- a/user_guide_src/source/libraries/email/010.php +++ /dev/null @@ -1,3 +0,0 @@ -setMessage('This is my message'); diff --git a/user_guide_src/source/libraries/email/011.php b/user_guide_src/source/libraries/email/011.php deleted file mode 100644 index 75f8fe87587d..000000000000 --- a/user_guide_src/source/libraries/email/011.php +++ /dev/null @@ -1,3 +0,0 @@ -setAltMessage('This is the alternative message'); diff --git a/user_guide_src/source/libraries/email/012.php b/user_guide_src/source/libraries/email/012.php deleted file mode 100644 index b5fdc3f86ddd..000000000000 --- a/user_guide_src/source/libraries/email/012.php +++ /dev/null @@ -1,4 +0,0 @@ -setHeader('Header1', 'Value1'); -$email->setHeader('Header2', 'Value2'); diff --git a/user_guide_src/source/libraries/email/013.php b/user_guide_src/source/libraries/email/013.php deleted file mode 100644 index 60147e305d34..000000000000 --- a/user_guide_src/source/libraries/email/013.php +++ /dev/null @@ -1,11 +0,0 @@ - $address) { - $email->clear(); - - $email->setTo($address); - $email->setFrom('your@example.com'); - $email->setSubject('Here is your info ' . $name); - $email->setMessage('Hi ' . $name . ' Here is the info you requested.'); - $email->send(); -} diff --git a/user_guide_src/source/libraries/email/014.php b/user_guide_src/source/libraries/email/014.php deleted file mode 100644 index 01bf56c01116..000000000000 --- a/user_guide_src/source/libraries/email/014.php +++ /dev/null @@ -1,3 +0,0 @@ -clear(true); diff --git a/user_guide_src/source/libraries/email/015.php b/user_guide_src/source/libraries/email/015.php deleted file mode 100644 index 60512f6b6416..000000000000 --- a/user_guide_src/source/libraries/email/015.php +++ /dev/null @@ -1,5 +0,0 @@ -send()) { - // Generate error -} diff --git a/user_guide_src/source/libraries/email/016.php b/user_guide_src/source/libraries/email/016.php deleted file mode 100644 index 2eb092b49787..000000000000 --- a/user_guide_src/source/libraries/email/016.php +++ /dev/null @@ -1,5 +0,0 @@ -send(false)) { - // Parameters won't be cleared -} diff --git a/user_guide_src/source/libraries/email/017.php b/user_guide_src/source/libraries/email/017.php deleted file mode 100644 index 391cd43214c8..000000000000 --- a/user_guide_src/source/libraries/email/017.php +++ /dev/null @@ -1,5 +0,0 @@ -attach('/path/to/photo1.jpg'); -$email->attach('/path/to/photo2.jpg'); -$email->attach('/path/to/photo3.jpg'); diff --git a/user_guide_src/source/libraries/email/018.php b/user_guide_src/source/libraries/email/018.php deleted file mode 100644 index 5f17f0aae311..000000000000 --- a/user_guide_src/source/libraries/email/018.php +++ /dev/null @@ -1,3 +0,0 @@ -attach('image.jpg', 'inline'); diff --git a/user_guide_src/source/libraries/email/019.php b/user_guide_src/source/libraries/email/019.php deleted file mode 100644 index d5fc39267e3c..000000000000 --- a/user_guide_src/source/libraries/email/019.php +++ /dev/null @@ -1,3 +0,0 @@ -attach('http://example.com/filename.pdf'); diff --git a/user_guide_src/source/libraries/email/020.php b/user_guide_src/source/libraries/email/020.php deleted file mode 100644 index e14badb97d6b..000000000000 --- a/user_guide_src/source/libraries/email/020.php +++ /dev/null @@ -1,3 +0,0 @@ -attach('filename.pdf', 'attachment', 'report.pdf'); diff --git a/user_guide_src/source/libraries/email/021.php b/user_guide_src/source/libraries/email/021.php deleted file mode 100644 index 103d8bc02c45..000000000000 --- a/user_guide_src/source/libraries/email/021.php +++ /dev/null @@ -1,3 +0,0 @@ -attach($buffer, 'attachment', 'report.pdf', 'application/pdf'); diff --git a/user_guide_src/source/libraries/email/022.php b/user_guide_src/source/libraries/email/022.php deleted file mode 100644 index 3d5dcc23e649..000000000000 --- a/user_guide_src/source/libraries/email/022.php +++ /dev/null @@ -1,11 +0,0 @@ -attach($filename); - -foreach ($list as $address) { - $email->setTo($address); - $cid = $email->setAttachmentCID($filename); - $email->setMessage('photo1'); - $email->send(); -} diff --git a/user_guide_src/source/libraries/email/023.php b/user_guide_src/source/libraries/email/023.php deleted file mode 100644 index 82813787c1c9..000000000000 --- a/user_guide_src/source/libraries/email/023.php +++ /dev/null @@ -1,9 +0,0 @@ -send(false); - -// Will only print the email headers, excluding the message subject and body -$email->printDebugger(['headers']); diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst deleted file mode 100644 index c685e06b16ec..000000000000 --- a/user_guide_src/source/libraries/encryption.rst +++ /dev/null @@ -1,345 +0,0 @@ -################## -Encryption Service -################## - -.. important:: DO NOT use this or any other *encryption* library for password storage! Passwords must be *hashed* - instead, and you should do that through PHP's `Password Hashing extension `_. - -The Encryption Service provides two-way symmetric (secret key) data encryption. The service will instantiate and/or -initialize an encryption **handler** to suit your parameters as explained below. - -Encryption Service handlers must implement CodeIgniter's simple ``EncrypterInterface``. Using an appropriate PHP -cryptographic extension or third-party library may require additional software to be installed on your server and/or -might need to be explicitly enabled in your instance of PHP. - -The following PHP extensions are currently supported: - -- `OpenSSL `_ -- `Sodium `_ - -This is not a full cryptographic solution. If you need more capabilities, for example, public-key encryption, we suggest -you consider direct use of OpenSSL or one of the other -`Cryptography Extensions `_. A more comprehensive package like -`Halite `_ (an O-O package built on libsodium) is another possibility. - -.. note:: Support for the ``MCrypt`` extension has been dropped. PHP deprecated it in 7.1 and removed it from the core - in 7.2. - -.. contents:: - :local: - :depth: 3 - -.. _usage: - -**************************** -Using the Encryption Library -**************************** - -Like all services in CodeIgniter, it can be loaded via ``Config\Services``: - -.. literalinclude:: encryption/001.php - -Assuming you have set your starting key (see :ref:`configuration`), encrypting and decrypting data is simple - pass the -appropriate string to the ``encrypt()`` and/or ``decrypt()`` methods: - -.. literalinclude:: encryption/002.php - -And that's it! The Encryption library will do everything necessary for the whole process to be cryptographically secure -out of the box. You don't need to worry about it. - -.. _configuration: - -Configuring the Library -======================= - -The example above uses the configuration settings found in **app/Config/Encryption.php**. - -============== ========================================================================== -Option Possible values (default in parentheses) -============== ========================================================================== -key Encryption key starter -driver Preferred handler, e.g., OpenSSL or Sodium (``OpenSSL``) -digest Message digest algorithm (``SHA512``) -blockSize [**SodiumHandler** only] Padding length in bytes (``16``) -cipher [**OpenSSLHandler** only] Cipher to use (``AES-256-CTR``) -encryptKeyInfo [**OpenSSLHandler** only] Encryption key info (``''``) -authKeyInfo [**OpenSSLHandler** only] Authentication key info (``''``) -rawData [**OpenSSLHandler** only] Whether the cipher-text should be raw (``true``) -============== ========================================================================== - -You can replace the config file's settings by passing a configuration object of your own to the ``Services`` call. The -``$config`` variable must be an instance of the ``Config\Encryption`` class. - -.. literalinclude:: encryption/003.php - -.. _encryption-compatible-with-ci3: - -Configuration to Maintain Compatibility with CI3 ------------------------------------------------- - -.. versionadded:: 4.3.0 - -Since v4.3.0, you can decrypt data encrypted with CI3's Encryption. If you need to decrypt such data, use the following -settings to maintain compatibility. - -.. literalinclude:: encryption/013.php - -Supported HMAC Authentication Algorithms ----------------------------------------- - -For HMAC message authentication, the Encryption library supports usage of the SHA-2 family of algorithms: - -=========== ==================== ============================ -Algorithm Raw length (bytes) Hex-encoded length (bytes) -=========== ==================== ============================ -SHA512 64 128 -SHA384 48 96 -SHA256 32 64 -SHA224 28 56 -=========== ==================== ============================ - -The reason for not including other popular algorithms, such as MD5 or SHA1, is that they are no longer considered secure -enough and as such, we don't want to encourage their usage. If you absolutely need to use them, it is easy to do so via -PHP's native `hash_hmac() `_ function. - -Stronger algorithms will, of course, be added in the future as they appear and become widely available. - -Default Behavior -================ - -By default, the Encryption Library uses the OpenSSL handler. That handler encrypts using the AES-256-CTR algorithm, your -configured *key*, and SHA512 HMAC authentication. - -Setting Your Encryption Key -=========================== - -Your encryption key **must** be as long as the encryption algorithm in use allows. For AES-256, that's 256 bits or 32 -bytes (characters) long. - -The key should be as random as possible, and it **must not** be a regular text string, nor the output of a hashing -function, etc. To create a proper key, you can use the Encryption library's ``createKey()`` method. - -.. literalinclude:: encryption/004.php - -The key can be stored in **app/Config/Encryption.php**, or you can design a storage mechanism of your own and pass the -key dynamically when encrypting/decrypting. - -To save your key to your **app/Config/Encryption.php**, open the file and set: - -.. literalinclude:: encryption/005.php - -Encoding Keys or Results ------------------------- - -You'll notice that the ``createKey()`` method outputs binary data, which is hard to deal with (i.e., a copy-paste may -damage it), so you may use ``bin2hex()`` or ``base64_encode`` to work with the key in a more friendly manner. For -example: - -.. literalinclude:: encryption/006.php - -You might find the same technique useful for the results of encryption: - -.. literalinclude:: encryption/007.php - -Using Prefixes in Storing Keys ------------------------------- - -You may take advantage of two special prefixes when storing your encryption keys: ``hex2bin:`` and ``base64:``. When -these prefixes immediately precede the value of your key, ``Encryption`` will intelligently parse the key and still pass -a binary string to the library. - -.. literalinclude:: encryption/008.php - -Similarly, you can use these prefixes in your **.env** file, too! :: - - // For hex2bin - encryption.key = hex2bin: - - // or - encryption.key = base64: - -Encryption Key Rotation -======================= - -.. versionadded:: 4.7.0 - -When you need to rotate your encryption key (for security best practices or compliance requirements), you can use the -``previousKeys`` configuration option to maintain the ability to decrypt data encrypted with old keys while using a new -key for all new encryption operations. - -How It Works ------------- - -- **Encryption** always uses the current ``key`` value -- **Decryption** tries the current ``key`` first -- If decryption fails, it automatically falls back to trying each key in ``previousKeys`` -- This allows seamless key rotation without data loss - -Configuration -------------- - -Add your old keys to the ``$previousKeys`` property in **app/Config/Encryption.php**: - -.. literalinclude:: encryption/014.php - -Using .env File ---------------- - -You can also configure previous keys in your **.env** file (recommended) using a comma-separated list: - -:: - - encryption.key = hex2bin:your_new_key - encryption.previousKeys = hex2bin:old_key_1,hex2bin:old_key_2 - -The framework automatically parses the comma-separated string into an array and processes each key. - -Key Rotation Workflow ---------------------- - -1. **Before rotation**: Data is encrypted and decrypted with ``key`` -2. **Start rotation**: Move current ``key`` value to ``previousKeys`` array, set new value for ``key`` -3. **During rotation**: New data encrypted with new ``key``, old data still decryptable via ``previousKeys`` -4. **Re-encrypt data** (optional): Decrypt and re-encrypt existing data with the new key -5. **Complete rotation**: Once all data is re-encrypted, remove old keys from ``previousKeys`` - -.. important:: The ``previousKeys`` feature is for **decryption fallback only**. All new encryption operations always - use the current ``key``. If you pass an explicit key via the ``$params`` argument to ``encrypt()`` or ``decrypt()``, - the previousKeys fallback will not be used. - -Padding -======= - -Sometimes, the length of a message may provide a lot of information about its nature. If a message is one of "yes", "no" -and "maybe", encrypting the message doesn't help: knowing the length is enough to know what the message is. - -Padding is a technique to mitigate this, by making the length a multiple of a given block size. - -Padding is implemented in ``SodiumHandler`` using libsodium's native ``sodium_pad`` and ``sodium_unpad`` functions. This -requires the use of a padding length (in bytes) that is added to the plaintext message prior to encryption, and removed -after decryption. Padding is configurable via the ``$blockSize`` property of ``Config\Encryption``. This value should be -greater than zero. - -.. important:: You are advised not to devise your own padding implementation. You must always use the more secure - implementation of a library. Also, passwords should not be padded. Usage of padding in order to hide the length of a - password is not recommended. A client willing to send a password to a server should hash it instead (even with a - single iteration of the hash function). This ensures that the length of the transmitted data is constant, and that - the server doesn't effortlessly get a copy of the password. - -Encryption Handler Notes -======================== - -OpenSSL Notes -------------- - -The `OpenSSL `_ extension has been a standard part of PHP for a long time. - -CodeIgniter's OpenSSL handler uses the AES-256-CTR cipher. - -The *key* your configuration provides is used to derive two other keys, one for encryption and one for authentication. -This is achieved by way of a technique known as an -`HMAC-based Key Derivation Function `_ (HKDF). - -Sodium Notes ------------- - -The `Sodium `_ extension is bundled by default in PHP as of PHP 7.2.0. - -CodeIgniter's Sodium handler uses ``sodium_crypto_secretbox()`` for shared-key authenticated encryption. It uses -XSalsa20 for encryption and Poly1305 for authentication. This handler does not perform public-key key exchange. - -Message Length -============== - -An encrypted string is usually longer than the original, plain-text string (depending on the cipher). - -This is influenced by the cipher algorithm itself, the initialization vector (IV) prepended to the cipher-text, and the -HMAC authentication message that is also prepended. Furthermore, the encrypted message is also Base64-encoded so that it -is safe for storage and transmission regardless of the character set in use. - -Keep this information in mind when selecting your data storage mechanism. Cookies, for example, can only hold 4K of -information. - -Using the Encryption Service Directly -===================================== - -Instead of (or in addition to) using ``Services`` as described in :ref:`usage`, you can create an "Encrypter" directly, -or change the settings of an existing instance. - -.. literalinclude:: encryption/009.php - -Remember that ``$config`` must be an instance of the ``Config\Encryption`` class. - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\Encryption - -.. php:class:: Encryption - - .. php:staticmethod:: createKey([$length = 32]) - - :param int $length: Output length - :returns: A pseudo-random cryptographic key with the specified length, or ``false`` on failure - :rtype: string - - Creates a cryptographic key by fetching random data from the operating system's sources (*i.e.* - ``/dev/urandom``). - - .. php:method:: initialize([Encryption $config = null]) - - :param Config\\Encryption $config: Configuration parameters - :returns: ``CodeIgniter\Encryption\EncrypterInterface`` instance - :rtype: ``CodeIgniter\Encryption\EncrypterInterface`` - :throws: ``CodeIgniter\Encryption\Exceptions\EncryptionException`` - - Initializes (configures) the library to use different settings. - - Example: - - .. literalinclude:: encryption/010.php - - Please refer to the :ref:`configuration` section for detailed info. - -.. php:interface:: CodeIgniter\Encryption\EncrypterInterface - - .. php:method:: encrypt($data[, $params = null]) - - :param string $data: Data to encrypt - :param array|string|null $params: Configuration parameters (key) - :returns: Encrypted data - :rtype: string - :throws: ``CodeIgniter\Encryption\Exceptions\EncryptionException`` - - Encrypts the input data and returns its ciphertext. - - If you pass parameters as the second argument, the ``key`` element will be used as the starting key for this - operation if ``$params`` is an array. Alternatively, the starting key may be passed as a string. - - If you are using the SodiumHandler and want to pass a different ``blockSize`` at runtime, pass the ``blockSize`` - key in the ``$params`` array. - - Examples: - - .. literalinclude:: encryption/011.php - - .. php:method:: decrypt($data[, $params = null]) - - :param string $data: Data to decrypt - :param array|string|null $params: Configuration parameters (key) - :returns: Decrypted data - :rtype: string - :throws: ``CodeIgniter\Encryption\Exceptions\EncryptionException`` - - Decrypts the input data and returns it in plain text. - - If you pass parameters as the second argument, the ``key`` element will be used as the starting key for this - operation if ``$params`` is an array. Alternatively, the starting key may be passed as a string. - - If you are using the SodiumHandler and want to pass a different ``blockSize`` at runtime, pass the ``blockSize`` - key in the ``$params`` array. - - Examples: - - .. literalinclude:: encryption/012.php diff --git a/user_guide_src/source/libraries/encryption/001.php b/user_guide_src/source/libraries/encryption/001.php deleted file mode 100644 index 1481d20c2758..000000000000 --- a/user_guide_src/source/libraries/encryption/001.php +++ /dev/null @@ -1,3 +0,0 @@ -encrypt($plainText); - -// Outputs: This is a plain-text message! -echo $encrypter->decrypt($ciphertext); diff --git a/user_guide_src/source/libraries/encryption/003.php b/user_guide_src/source/libraries/encryption/003.php deleted file mode 100644 index a84d6b3852f4..000000000000 --- a/user_guide_src/source/libraries/encryption/003.php +++ /dev/null @@ -1,9 +0,0 @@ -key = 'aBigsecret_ofAtleast32Characters'; -$config->driver = 'OpenSSL'; - -$encrypter = service('encrypter', $config); diff --git a/user_guide_src/source/libraries/encryption/004.php b/user_guide_src/source/libraries/encryption/004.php deleted file mode 100644 index 30d861e74a40..000000000000 --- a/user_guide_src/source/libraries/encryption/004.php +++ /dev/null @@ -1,8 +0,0 @@ -encrypt($plaintext)); diff --git a/user_guide_src/source/libraries/encryption/008.php b/user_guide_src/source/libraries/encryption/008.php deleted file mode 100644 index 0fe44575e8db..000000000000 --- a/user_guide_src/source/libraries/encryption/008.php +++ /dev/null @@ -1,14 +0,0 @@ -'; - // or - public $key = 'base64:'; - // ... -} diff --git a/user_guide_src/source/libraries/encryption/009.php b/user_guide_src/source/libraries/encryption/009.php deleted file mode 100644 index ec40cae6127c..000000000000 --- a/user_guide_src/source/libraries/encryption/009.php +++ /dev/null @@ -1,7 +0,0 @@ -initialize($config); diff --git a/user_guide_src/source/libraries/encryption/010.php b/user_guide_src/source/libraries/encryption/010.php deleted file mode 100644 index 53bcceac5fe5..000000000000 --- a/user_guide_src/source/libraries/encryption/010.php +++ /dev/null @@ -1,3 +0,0 @@ -initialize(['cipher' => 'AES-256-CTR']); diff --git a/user_guide_src/source/libraries/encryption/011.php b/user_guide_src/source/libraries/encryption/011.php deleted file mode 100644 index 8b675de0f16f..000000000000 --- a/user_guide_src/source/libraries/encryption/011.php +++ /dev/null @@ -1,7 +0,0 @@ -encrypt('My secret message'); -$ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key']); -$ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key', 'blockSize' => 32]); -$ciphertext = $encrypter->encrypt('My secret message', 'New secret key'); -$ciphertext = $encrypter->encrypt('My secret message', ['blockSize' => 32]); diff --git a/user_guide_src/source/libraries/encryption/012.php b/user_guide_src/source/libraries/encryption/012.php deleted file mode 100644 index 491e16f876e4..000000000000 --- a/user_guide_src/source/libraries/encryption/012.php +++ /dev/null @@ -1,7 +0,0 @@ -decrypt($ciphertext); -echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key']); -echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key', 'blockSize' => 32]); -echo $encrypter->decrypt($ciphertext, 'New secret key'); -echo $encrypter->decrypt($ciphertext, ['blockSize' => 32]); diff --git a/user_guide_src/source/libraries/encryption/013.php b/user_guide_src/source/libraries/encryption/013.php deleted file mode 100644 index f7ef52060b6b..000000000000 --- a/user_guide_src/source/libraries/encryption/013.php +++ /dev/null @@ -1,17 +0,0 @@ -driver = 'OpenSSL'; - -// Your CI3's 'encryption_key' -$config->key = hex2bin('64c70b0b8d45b80b9eba60b8b3c8a34d0193223d20fea46f8644b848bf7ce67f'); -// Your CI3's 'cipher' and 'mode' -$config->cipher = 'AES-128-CBC'; - -$config->rawData = false; -$config->encryptKeyInfo = 'encryption'; -$config->authKeyInfo = 'authentication'; - -$encrypter = service('encrypter', $config); diff --git a/user_guide_src/source/libraries/encryption/014.php b/user_guide_src/source/libraries/encryption/014.php deleted file mode 100644 index 77a2255419ab..000000000000 --- a/user_guide_src/source/libraries/encryption/014.php +++ /dev/null @@ -1,17 +0,0 @@ -set([])`` is essentially a hard reset. - -*************** -Inputting Files -*************** - -add(string[]|string $paths, bool $recursive = true) -=================================================== - -Adds all files indicated by the path or array of paths. If the path resolves to a directory then ``$recursive`` will -include sub-directories. - -addFile(string $file) / addFiles(array $files) -============================================== - -Adds the file or files to the current list of input files. Files are absolute paths to actual files. - -removeFile(string $file) / removeFiles(array $files) -==================================================== - -Removes the file or files from the current list of input files. - -addDirectory(string $directory, bool $recursive = false) -======================================================== -addDirectories(array $directories, bool $recursive = false) -=========================================================== - -Adds all files from the directory or directories, optionally recursing into sub-directories. Directories are absolute -paths to actual directories. - -*************** -Filtering Files -*************** - -removePattern(string $pattern, ?string $scope = null) -===================================================== -retainPattern(string $pattern, ?string $scope = null) -===================================================== - -Filters the current file list through the pattern (and optional scope), removing or retaining matched files. - -``$pattern`` may be a complete regex (like ``'#\A[A-Za-z]+\.php\z#'``) or a pseudo-regex similar to ``glob()`` (like -``'*.css'``). - -If a ``$scope`` is provided then only files in or under that directory will be considered (i.e. files outside of -``$scope`` are always retained). When no scope is provided, all files are subject. - -Examples: - -.. literalinclude:: files/015.php - - -.. _file-collections-retain-multiple-patterns: - -retainMultiplePatterns(array $patterns, ?string $scope = null) -============================================================== - -Provides the same functionality as ``retainPattern()`` but accepts an array of patterns to retain files from all -patterns. - -Example: - -.. literalinclude:: files/016.php - -**************** -Retrieving Files -**************** - -get(): string[] -=============== - -Returns an array of all the loaded input files. - -.. note:: ``FileCollection`` is an ``IteratorAggregate`` so you can work with it directly (e.g. - ``foreach ($collection as $file)``). diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst deleted file mode 100644 index f2dfa85c8936..000000000000 --- a/user_guide_src/source/libraries/files.rst +++ /dev/null @@ -1,141 +0,0 @@ -################## -Working with Files -################## - -CodeIgniter provides a File class that wraps the `SplFileInfo `_ -class and provides some additional convenience methods. This class is the base class for -:doc:`uploaded files ` and :doc:`images `. - -.. contents:: - :local: - :depth: 2 - -Getting a File instance -*********************** - -You create a new File instance by passing in the path to the file in the constructor. - -.. literalinclude:: files/001.php - :lines: 2- - -By default, the file does not need to exist. However, you can pass an additional argument of ``true`` to check that the -file exists and throw ``FileNotFoundException()`` if it does not. - -Taking Advantage of Spl -*********************** - -Once you have an instance, you have the full power of the SplFileInfo class at the ready, including: - -.. literalinclude:: files/002.php - :lines: 2- - -New Features -************ - -In addition to all of the methods in the SplFileInfo class, you get some new tools. - -getRandomName() -=============== - -You can generate a cryptographically secure random filename, with the current timestamp prepended, using the -``getRandomName()`` method. This is especially useful to rename files when moving them so that the filename is -unguessable: - -.. literalinclude:: files/003.php - :lines: 2- - -getSize() -========= - -Returns the size of the file in bytes: - -.. literalinclude:: files/004.php - :lines: 2- - -A ``RuntimeException`` will be thrown if the file does not exist or an error occurs. - -getSizeByUnit() -=============== - -.. deprecated:: 4.6.0 - -Returns the size of the file, in bytes by default. You can pass in either ``'kb'`` or ``'mb'`` as the first parameter to -get the results in kibibytes or mebibytes, respectively: - -.. literalinclude:: files/005.php - :lines: 2- - -A ``RuntimeException`` will be thrown if the file does not exist or an error occurs. - - -.. _file-get-size-by-binary-unit: - -getSizeByBinaryUnit() -===================== - -.. versionadded:: 4.6.0 - -Returns the size of the file, in bytes by default. You can pass in different FileSizeUnit values as the first parameter -to get the results in kibibytes, mebibytes, etc., respectively. You can pass in a precision value as the second -parameter to define the number of decimal places. - -.. literalinclude:: files/017.php - :lines: 4- - -A ``RuntimeException`` will be thrown if the file does not exist or an error occurs. - - -.. _file-get-size-by-metric-unit: - -getSizeByMetricUnit() -===================== - -.. versionadded:: 4.6.0 - -Returns the size of the file, in bytes by default. You can pass in different FileSizeUnit values as the first parameter -to get the results in kilobytes, megabytes, etc., respectively. You can pass in a precision value as the second -parameter to define the number of decimal places. - -.. literalinclude:: files/018.php - :lines: 4- - -A ``RuntimeException`` will be thrown if the file does not exist or an error occurs. - -getMimeType() -============= - -Retrieves the media type (mime type) of the file. Uses methods that are considered as secure as possible when -determining the type of file: - -.. literalinclude:: files/006.php - :lines: 2- - -guessExtension() -================ - -Attempts to determine the file extension based on the trusted ``getMimeType()`` method. If the mime type is unknown, it -will return null. This is often a more trusted source than simply using the extension provided by the filename. Uses the -values in **app/Config/Mimes.php** to determine the extension: - -.. literalinclude:: files/007.php - :lines: 2- - -Moving Files -============ - -Each file can be moved to its new location with the aptly named ``move()`` method. This takes the directory to move the -file to as the first parameter: - -.. literalinclude:: files/008.php - :lines: 2- - -By default, the original filename is used. You can specify a new filename by passing it as the second parameter: - -.. literalinclude:: files/009.php - :lines: 2- - -The ``move()`` method returns a new File instance for the relocated file, so you must capture the result if the -resulting location is needed: - -.. literalinclude:: files/010.php - :lines: 2- diff --git a/user_guide_src/source/libraries/files/001.php b/user_guide_src/source/libraries/files/001.php deleted file mode 100644 index 643758d14ca8..000000000000 --- a/user_guide_src/source/libraries/files/001.php +++ /dev/null @@ -1,3 +0,0 @@ -getBasename(); -// Get last modified time -echo $file->getMTime(); -// Get the true real path -echo $file->getRealPath(); -// Get the file permissions -echo $file->getPerms(); - -// Write CSV rows to it. -if ($file->isWritable()) { - $csv = $file->openFile('w'); - - foreach ($rows as $row) { - $csv->fputcsv($row); - } -} diff --git a/user_guide_src/source/libraries/files/003.php b/user_guide_src/source/libraries/files/003.php deleted file mode 100644 index 53327d59bd0f..000000000000 --- a/user_guide_src/source/libraries/files/003.php +++ /dev/null @@ -1,4 +0,0 @@ -getRandomName(); diff --git a/user_guide_src/source/libraries/files/004.php b/user_guide_src/source/libraries/files/004.php deleted file mode 100644 index e3998d56af19..000000000000 --- a/user_guide_src/source/libraries/files/004.php +++ /dev/null @@ -1,3 +0,0 @@ -getSize(); // 256901 diff --git a/user_guide_src/source/libraries/files/005.php b/user_guide_src/source/libraries/files/005.php deleted file mode 100644 index ee9043ff92a6..000000000000 --- a/user_guide_src/source/libraries/files/005.php +++ /dev/null @@ -1,5 +0,0 @@ -getSizeByUnit(); // 256901 -$kilobytes = $file->getSizeByUnit('kb'); // 250.880 -$megabytes = $file->getSizeByUnit('mb'); // 0.245 diff --git a/user_guide_src/source/libraries/files/006.php b/user_guide_src/source/libraries/files/006.php deleted file mode 100644 index 5c8ae9a08945..000000000000 --- a/user_guide_src/source/libraries/files/006.php +++ /dev/null @@ -1,5 +0,0 @@ -getMimeType(); - -echo $type; // image/png diff --git a/user_guide_src/source/libraries/files/007.php b/user_guide_src/source/libraries/files/007.php deleted file mode 100644 index 26be30a2c7bc..000000000000 --- a/user_guide_src/source/libraries/files/007.php +++ /dev/null @@ -1,4 +0,0 @@ -guessExtension(); diff --git a/user_guide_src/source/libraries/files/008.php b/user_guide_src/source/libraries/files/008.php deleted file mode 100644 index 12499a3ca1ba..000000000000 --- a/user_guide_src/source/libraries/files/008.php +++ /dev/null @@ -1,3 +0,0 @@ -move(WRITEPATH . 'uploads'); diff --git a/user_guide_src/source/libraries/files/009.php b/user_guide_src/source/libraries/files/009.php deleted file mode 100644 index 2e6b39645a4b..000000000000 --- a/user_guide_src/source/libraries/files/009.php +++ /dev/null @@ -1,4 +0,0 @@ -getRandomName(); -$file->move(WRITEPATH . 'uploads', $newName); diff --git a/user_guide_src/source/libraries/files/010.php b/user_guide_src/source/libraries/files/010.php deleted file mode 100644 index 2a3fcab40957..000000000000 --- a/user_guide_src/source/libraries/files/010.php +++ /dev/null @@ -1,3 +0,0 @@ -move(WRITEPATH . 'uploads'); diff --git a/user_guide_src/source/libraries/files/011.php b/user_guide_src/source/libraries/files/011.php deleted file mode 100644 index db63f20a0f79..000000000000 --- a/user_guide_src/source/libraries/files/011.php +++ /dev/null @@ -1,9 +0,0 @@ -addDirectory(APPPATH . 'Filters'); diff --git a/user_guide_src/source/libraries/files/012.php b/user_guide_src/source/libraries/files/012.php deleted file mode 100644 index b87efe4a692a..000000000000 --- a/user_guide_src/source/libraries/files/012.php +++ /dev/null @@ -1,6 +0,0 @@ -removeFile(APPPATH . 'Filters/DevelopToolbar.php'); - -$files->removePattern('#\.gitkeep#'); -$files->retainPattern('*.php'); diff --git a/user_guide_src/source/libraries/files/013.php b/user_guide_src/source/libraries/files/013.php deleted file mode 100644 index a529fd0bcd6c..000000000000 --- a/user_guide_src/source/libraries/files/013.php +++ /dev/null @@ -1,9 +0,0 @@ -get()); -echo 'I have ' . count($files) . ' files!'; - -foreach ($files as $file) { - echo 'Moving ' . $file->getBasename() . ', ' . $file->getSizeByUnit('mb'); - $file->move(WRITABLE . $file->getRandomName()); -} diff --git a/user_guide_src/source/libraries/files/014.php b/user_guide_src/source/libraries/files/014.php deleted file mode 100644 index fb11f62d31e6..000000000000 --- a/user_guide_src/source/libraries/files/014.php +++ /dev/null @@ -1,13 +0,0 @@ -add(APPPATH . 'Config', true)->retainPattern('*.php'); - } -} diff --git a/user_guide_src/source/libraries/files/015.php b/user_guide_src/source/libraries/files/015.php deleted file mode 100644 index f03f2a205c32..000000000000 --- a/user_guide_src/source/libraries/files/015.php +++ /dev/null @@ -1,12 +0,0 @@ -add(APPPATH . 'Config', true); // Adds all Config files and directories - -$files->removePattern('*tion.php'); // Would remove Encryption.php, Validation.php, and boot/production.php -$files->removePattern('*tion.php', APPPATH . 'Config/boot'); // Would only remove boot/production.php - -$files->retainPattern('#A.+php$#'); // Would keep only Autoload.php -$files->retainPattern('#d.+php$#', APPPATH . 'Config/boot'); // Would keep everything but boot/production.php and boot/testing.php diff --git a/user_guide_src/source/libraries/files/016.php b/user_guide_src/source/libraries/files/016.php deleted file mode 100644 index b40498cf5786..000000000000 --- a/user_guide_src/source/libraries/files/016.php +++ /dev/null @@ -1,3 +0,0 @@ -retainMultiplePatterns(['*.css', '*.js']); // Would keep only *.css and *.js files diff --git a/user_guide_src/source/libraries/files/017.php b/user_guide_src/source/libraries/files/017.php deleted file mode 100644 index ad4d89476180..000000000000 --- a/user_guide_src/source/libraries/files/017.php +++ /dev/null @@ -1,7 +0,0 @@ -getSizeByBinaryUnit(); // 256901 -$kibibytes = $file->getSizeByBinaryUnit(FileSizeUnit::KB); // 250.880 -$mebibytes = $file->getSizeByBinaryUnit(FileSizeUnit::MB); // 0.245 diff --git a/user_guide_src/source/libraries/files/018.php b/user_guide_src/source/libraries/files/018.php deleted file mode 100644 index 07521b4bbe1c..000000000000 --- a/user_guide_src/source/libraries/files/018.php +++ /dev/null @@ -1,7 +0,0 @@ -getSizeByMetricUnit(); // 256901 -$kilobytes = $file->getSizeByMetricUnit(FileSizeUnit::KB); // 256.901 -$megabytes = $file->getSizeByMetricUnit(FileSizeUnit::MB); // 0.256 diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst deleted file mode 100644 index 301d10ef693e..000000000000 --- a/user_guide_src/source/libraries/honeypot.rst +++ /dev/null @@ -1,40 +0,0 @@ -############## -Honeypot Class -############## - -The Honeypot Class makes it possible to determine when a Bot makes a request to a CodeIgniter4 application, if it's -enabled in the **app/Config/Filters.php** file. This is done by attaching a form field to any form, and this field is -hidden from a human but accessible to a Bot. When data is entered into the field, it's assumed the request is coming -from a Bot. The bundled Honeypot filter throws a ``HoneypotException`` with an HTTP status code of 403 (Forbidden). - -.. contents:: - :local: - :depth: 2 - -***************** -Enabling Honeypot -***************** - -To enable a Honeypot, changes have to be made to the **app/Config/Filters.php** file. Just uncomment honeypot from the -``$globals`` array, like: - -.. literalinclude:: honeypot/001.php - -A sample Honeypot filter is bundled, as **system/Filters/Honeypot.php**. If it is not suitable, make your own at -**app/Filters/Honeypot.php**, and modify the ``$aliases`` in **app/Config/Filters.php** appropriately. - -******************** -Customizing Honeypot -******************** - -Honeypot can be customized. The fields below can be set either in **app/Config/Honeypot.php** or in **.env**. - -* ``$hidden`` - ``true`` or ``false`` to control visibility of the honeypot field; default is ``true`` -* ``$label`` - HTML label for the honeypot field; default is ``'Fill This Field'`` -* ``$name`` - name of the HTML form field used for the template; default is ``'honeypot'`` -* ``$template`` - form field template used for the honeypot; default is - ``''`` -* ``$container`` - container tag for the template; default is ``'
{template}
'``. If you - enable CSP, you can remove ``style="display:none"``. -* ``$containerId`` - [Since v4.3.0] this setting is used only when you enable CSP. You can change the id attribute for - the container tag; default is ``'hpc'`` diff --git a/user_guide_src/source/libraries/honeypot/001.php b/user_guide_src/source/libraries/honeypot/001.php deleted file mode 100644 index 573010145976..000000000000 --- a/user_guide_src/source/libraries/honeypot/001.php +++ /dev/null @@ -1,25 +0,0 @@ - [ - 'honeypot', - // 'csrf', - // 'invalidchars', - ], - 'after' => [ - 'toolbar', - 'honeypot', - // 'secureheaders', - ], - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/images.rst b/user_guide_src/source/libraries/images.rst deleted file mode 100644 index 4dd0fad912b9..000000000000 --- a/user_guide_src/source/libraries/images.rst +++ /dev/null @@ -1,288 +0,0 @@ -######################## -Image Manipulation Class -######################## - -CodeIgniter's Image Manipulation class lets you perform the following actions: - -- Image Resizing -- Thumbnail Creation -- Image Cropping -- Image Rotating -- Image Watermarking - -The following image libraries are supported: GD/GD2 and ImageMagick. - -.. contents:: - :local: - :depth: 2 - -********************** -Initializing the Class -********************** - -Like most other classes in CodeIgniter, the image class is initialized in your controller by calling the global function -``service()``: - -.. literalinclude:: images/001.php - -You can pass the alias for the image library you wish to use into the global function ``service()``: - -.. literalinclude:: images/002.php - -The available Handlers are as follows: - -- ``gd``: The GD/GD2 image library. -- ``imagick``: The ImageMagick library. - -.. note:: The ImageMagick handler requires the imagick extension. - -.. note:: - On Windows, the ImageMagick handler requires **absolute file paths** when loading images (for example, using - ``WRITEPATH`` or ``FCPATH``). - -.. warning:: - Do not let user input directly decide the image source path, storage directory, or filename. This includes values - passed to methods like ``save()``, ``copy()`` and others, and any path or filename used to store processed images. - Use directories controlled by your application, and generate filenames yourself or sanitize them with - :php:func:`sanitize_filename`. - -******************* -Processing an Image -******************* - -Regardless of the type of processing you would like to perform (resizing, cropping, rotation, or watermarking), the -general process is identical. You will set some preferences corresponding to the action you intend to perform, then call -one of the available processing functions. - -For example, to create an image thumbnail, you'll do this: - -.. literalinclude:: images/003.php - -The above code tells the library to look for an image called **mypic.jpg** located in the **/path/to/image** folder, -then create a new image from it that is 100 x 100 pixels, and save it to a new file **mypic_thumb.jpg**. Since it is -using the ``fit()`` method, it will attempt to find the best portion of the image to crop based on the desired aspect -ratio, and then crop and resize the result. - -An image can be processed through as many of the available methods as needed before saving. The original image is left -untouched, and a new image is used and passed through each method, applying the results on top of the previous results: - -.. literalinclude:: images/004.php - -This example would take the same image and first fix any mobile phone orientation issues, rotate the image by 90 -degrees, and then crop the result into a 100 x 100 pixel image, starting at the top left corner. The result would be -saved as the thumbnail. - -.. note:: In order for the image class to be allowed to do any processing, the folder containing the image files must - have write permissions. - -.. note:: Image processing can require a considerable amount of server memory for some operations. If you are - experiencing out-of-memory errors while processing images, you may need to limit their maximum size, and/or adjust - PHP memory limits. - -Image Quality -============= - -``save()`` can take an additional parameter ``$quality`` to alter the resulting image quality. Values range from 0 to -100, with 90 being the framework default. This parameter only applies to JPEG and WebP images, and will be ignored -otherwise: - -.. note:: The parameter ``$quality`` for WebP can be used since v4.4.0. - -.. note:: When using ImageMagick, the target path passed to ``save()`` determines the output format by its extension. - ImageMagick may also interpret explicit format prefixes like ``jpg:filename.png``. If the target path is based on - user input, validate it against the formats your application allows, including any format prefix or extension. - -.. literalinclude:: images/005.php - -.. note:: Higher quality will result in larger file sizes. See also https://www.php.net/manual/en/function.imagejpeg.php - -If you are only interested in changing the image quality without doing any processing, you will need to include the -image resource, or you will end up with an exact copy: - -.. literalinclude:: images/006.php - -****************** -Processing Methods -****************** - -There are eight available processing methods: - -- ``$image->crop()`` -- ``$image->convert()`` -- ``$image->fit()`` -- ``$image->flatten()`` -- ``$image->flip()`` -- ``$image->resize()`` -- ``$image->rotate()`` -- ``$image->text()`` - -These methods return the class instance so they can be chained together, as shown above. If they fail, they will throw a -``CodeIgniter\Images\ImageException`` that contains the error message. A good practice is to catch the exceptions, -showing an error upon failure, like this: - -.. literalinclude:: images/007.php - -Cropping Images -=============== - -Images can be cropped so that only a portion of the original image remains. This is often used when creating thumbnail -images that should match a certain size/aspect ratio. This is handled with the ``crop()`` method:: - - crop(int $width = null, int $height = null, int $x = null, int $y = null, bool $maintainRatio = false, string $masterDim = 'auto') - -- ``$width`` is the desired width of the resulting image, in pixels. -- ``$height`` is the desired height of the resulting image, in pixels. -- ``$x`` is the number of pixels from the left side of the image to start cropping. -- ``$y`` is the number of pixels from the top of the image to start cropping. -- ``$maintainRatio`` will, if true, adjust the final dimensions as needed to maintain the image's original aspect ratio. -- ``$masterDim`` specifies which dimension should be left untouched when ``$maintainRatio`` is true. Values can be: - ``'width'``, ``'height'``, or ``'auto'``. - -To take a 50 x 50 pixel square out of the center of an image, you would need to first calculate the appropriate x and y -offset values: - -.. literalinclude:: images/008.php - -Converting Images -================= - -The ``convert()`` method changes the library's internal indicator for the desired file format. This doesn't touch the -actual image resource, but indicates to ``save()`` what format to use:: - - convert(int $imageType) - -- ``$imageType`` is one of PHP's image type constants (see for example - https://www.php.net/manual/en/function.image-type-to-mime-type.php): - - .. literalinclude:: images/009.php - -.. note:: ImageMagick already saves files in the type indicated by their extension, ignoring ``$imageType``. - -Fitting Images -============== - -The ``fit()`` method aims to help simplify cropping a portion of an image in a "smart" way, by doing the following -steps: - -- Determine the correct portion of the original image to crop in order to maintain the desired aspect ratio. -- Crop the original image. -- Resize to the final dimensions. - -:: - - fit(int $width, int $height = null, string $position = 'center') - -- ``$width`` is the desired final width of the image. -- ``$height`` is the desired final height of the image. -- ``$position`` determines the portion of the image to crop out. Allowed positions: ``'top-left'``, ``'top'``, - ``'top-right'``, ``'left'``, ``'center'``, ``'right'``, ``'bottom-left'``, ``'bottom'``, ``'bottom-right'``. - -This provides a much simpler way to crop that will always maintain the aspect ratio: - -.. literalinclude:: images/010.php - -Flattening Images -================= - -The ``flatten()`` method aims to add a background color behind transparent images (PNG) and convert RGBA pixels to RGB -pixels. - -- Specify a background color when converting from transparent images to JPGs. - -:: - - flatten(int $red = 255, int $green = 255, int $blue = 255) - -- ``$red`` is the red value of the background. -- ``$green`` is the green value of the background. -- ``$blue`` is the blue value of the background. - -.. literalinclude:: images/011.php - -Flipping Images -=============== - -Images can be flipped along either their horizontal or vertical axis:: - - flip(string $dir) - -- ``$dir`` specifies the axis to flip along. Can be either ``'vertical'`` or ``'horizontal'``. - -.. literalinclude:: images/012.php - -Resizing Images -=============== - -Images can be resized to fit any dimension you require with the ``resize()`` method:: - - resize(int $width, int $height, bool $maintainRatio = false, string $masterDim = 'auto') - -- ``$width`` is the desired width of the new image in pixels. -- ``$height`` is the desired height of the new image in pixels. -- ``$maintainRatio`` determines whether the image is stretched to fit the new dimensions, or the original aspect ratio - is maintained. -- ``$masterDim`` specifies which axis should have its dimension honored when maintaining ratio. Use ``'width'``, - ``'height'``, or ``'auto'`` to choose automatically. - -When resizing images, you can choose whether to maintain the ratio of the original image, or stretch/squash the new -image to fit the desired dimensions. If ``$maintainRatio`` is true, the dimension specified by ``$masterDim`` will stay -the same, while the other dimension will be altered to match the original image's aspect ratio. - -.. literalinclude:: images/013.php - -Rotating Images -=============== - -The ``rotate()`` method allows you to rotate an image in 90-degree increments:: - - rotate(float $angle) - -- ``$angle`` is the number of degrees to rotate. One of ``90``, ``180``, ``270``. - -.. note:: While the ``$angle`` parameter accepts a float, it will convert it to an integer during the process. If the - value is anything other than the three values listed above, it will throw a ``CodeIgniter\Images\ImageException``. - -Adding a Text Watermark -======================= - -You can overlay a text watermark onto the image very simply with the ``text()`` method. This is useful for placing -copyright notices, photographer names, or simply marking the images as a preview so they won't be used in other people's -final products. - -:: - - text(string $text, array $options = []) - -The first parameter is the string of text that you wish to display. The second parameter is an array of options that -allow you to specify how the text should be displayed: - -.. literalinclude:: images/014.php - -The possible options that are recognized are as follows: - -- ``color``: Text color (hex number), i.e., ``'#ff0000'`` -- ``opacity``: A number between ``0`` and ``1`` that represents the opacity of the text. -- ``withShadow``: Boolean value indicating whether to display a shadow. -- ``shadowColor``: Color of the shadow (hex number) -- ``shadowOffset``: How many pixels to offset the shadow. Applies to both the vertical and horizontal values. -- ``hAlign``: Horizontal alignment: ``'left'``, ``'center'``, ``'right'`` -- ``vAlign``: Vertical alignment: ``'top'``, ``'middle'``, ``'bottom'`` -- ``hOffset``: Additional offset on the x axis, in pixels -- ``vOffset``: Additional offset on the y axis, in pixels -- ``fontPath``: The full server path to the TTF font you wish to use. System font will be used if none is given. -- ``fontSize``: The font size to use. When using the GD handler with the system font, valid values are between ``1`` and - ``5``. - -Clearing Image Metadata -======================= - -The ``clearMetadata()`` method removes metadata (EXIF, XMP, ICC, IPTC, comments, etc.) from an image. - -.. important:: The GD image library automatically strips all metadata during processing, so this method has no - additional effect when using the GD handler. This behavior is built into GD itself and cannot be modified. - -Some essential technical metadata (dimensions, color depth) will be regenerated during save operations as they're -required for image display. However, all privacy-sensitive information such as GPS location, camera details, and -timestamps will be completely removed. - -.. literalinclude:: images/015.php diff --git a/user_guide_src/source/libraries/images/001.php b/user_guide_src/source/libraries/images/001.php deleted file mode 100644 index 3001f4561029..000000000000 --- a/user_guide_src/source/libraries/images/001.php +++ /dev/null @@ -1,3 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->fit(100, 100, 'center') - ->save('/path/to/image/mypic_thumb.jpg'); diff --git a/user_guide_src/source/libraries/images/004.php b/user_guide_src/source/libraries/images/004.php deleted file mode 100644 index ff01d0187568..000000000000 --- a/user_guide_src/source/libraries/images/004.php +++ /dev/null @@ -1,7 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->reorient() - ->rotate(90) - ->crop(100, 100, 0, 0) - ->save('/path/to/image/mypic_thumb.jpg'); diff --git a/user_guide_src/source/libraries/images/005.php b/user_guide_src/source/libraries/images/005.php deleted file mode 100644 index faafbddd158b..000000000000 --- a/user_guide_src/source/libraries/images/005.php +++ /dev/null @@ -1,5 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - // processing methods - ->save('/path/to/image/my_low_quality_pic.jpg', 10); diff --git a/user_guide_src/source/libraries/images/006.php b/user_guide_src/source/libraries/images/006.php deleted file mode 100644 index e49d368fc0da..000000000000 --- a/user_guide_src/source/libraries/images/006.php +++ /dev/null @@ -1,5 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->withResource() - ->save('/path/to/image/my_low_quality_pic.jpg', 10); diff --git a/user_guide_src/source/libraries/images/007.php b/user_guide_src/source/libraries/images/007.php deleted file mode 100644 index aa5c2a8d4313..000000000000 --- a/user_guide_src/source/libraries/images/007.php +++ /dev/null @@ -1,11 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->fit(100, 100, 'center') - ->save('/path/to/image/mypic_thumb.jpg'); -} catch (\CodeIgniter\Images\Exceptions\ImageException $e) { - echo $e->getMessage(); -} diff --git a/user_guide_src/source/libraries/images/008.php b/user_guide_src/source/libraries/images/008.php deleted file mode 100644 index a7963d420573..000000000000 --- a/user_guide_src/source/libraries/images/008.php +++ /dev/null @@ -1,14 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->getFile() - ->getProperties(true); - -$xOffset = ($info['width'] / 2) - 25; -$yOffset = ($info['height'] / 2) - 25; - -service('image', 'imagick') - ->withFile('/path/to/image/mypic.jpg') - ->crop(50, 50, $xOffset, $yOffset) - ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/009.php b/user_guide_src/source/libraries/images/009.php deleted file mode 100644 index e24cfcc40a4a..000000000000 --- a/user_guide_src/source/libraries/images/009.php +++ /dev/null @@ -1,6 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->convert(IMAGETYPE_PNG) - ->save('/path/to/new/image.png'); diff --git a/user_guide_src/source/libraries/images/010.php b/user_guide_src/source/libraries/images/010.php deleted file mode 100644 index 696eab880516..000000000000 --- a/user_guide_src/source/libraries/images/010.php +++ /dev/null @@ -1,6 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->fit(100, 150, 'left') - ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/011.php b/user_guide_src/source/libraries/images/011.php deleted file mode 100644 index e816af48c647..000000000000 --- a/user_guide_src/source/libraries/images/011.php +++ /dev/null @@ -1,11 +0,0 @@ -withFile('/path/to/image/mypic.png') - ->flatten() - ->save('/path/to/new/image.jpg'); - -service('image', 'imagick') - ->withFile('/path/to/image/mypic.png') - ->flatten(25, 25, 112) - ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/012.php b/user_guide_src/source/libraries/images/012.php deleted file mode 100644 index eb99b11ae3b1..000000000000 --- a/user_guide_src/source/libraries/images/012.php +++ /dev/null @@ -1,6 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->flip('horizontal') - ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/013.php b/user_guide_src/source/libraries/images/013.php deleted file mode 100644 index 7c1780565a5d..000000000000 --- a/user_guide_src/source/libraries/images/013.php +++ /dev/null @@ -1,6 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->resize(200, 100, true, 'height') - ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/014.php b/user_guide_src/source/libraries/images/014.php deleted file mode 100644 index cfe551a4c411..000000000000 --- a/user_guide_src/source/libraries/images/014.php +++ /dev/null @@ -1,13 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->text('Copyright 2017 My Photo Co', [ - 'color' => '#fff', - 'opacity' => 0.5, - 'withShadow' => true, - 'hAlign' => 'center', - 'vAlign' => 'bottom', - 'fontSize' => 20, - ]) - ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/015.php b/user_guide_src/source/libraries/images/015.php deleted file mode 100644 index 446deab2d35f..000000000000 --- a/user_guide_src/source/libraries/images/015.php +++ /dev/null @@ -1,6 +0,0 @@ -withFile('/path/to/image/mypic.jpg') - ->clearMetadata() - ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/index.rst b/user_guide_src/source/libraries/index.rst deleted file mode 100644 index a67b4d97e545..000000000000 --- a/user_guide_src/source/libraries/index.rst +++ /dev/null @@ -1,28 +0,0 @@ -################# -Library Reference -################# - -.. toctree:: - :titlesonly: - - caching - cookies - cors - curlrequest - email - encryption - files - file_collections - honeypot - images - pagination - publisher - security - sessions - throttler - time - typography - uploaded_files - uri - user_agent - validation diff --git a/user_guide_src/source/libraries/official_packages.rst b/user_guide_src/source/libraries/official_packages.rst deleted file mode 100644 index 971d0526e11b..000000000000 --- a/user_guide_src/source/libraries/official_packages.rst +++ /dev/null @@ -1,81 +0,0 @@ -################# -Official Packages -################# - -The CodeIgniter framework cannot solve all of the problems that developers will encounter. Many users have said they -love how small and fast the framework is, so we don't want to bloat the core framework. To bridge the gap, we are -releasing official packages to provide additional functionality that not every site will need or want. - -.. contents:: - :local: - :depth: 2 - -.. _shield: - -****** -Shield -****** - -`CodeIgniter Shield `_ is an authentication and authorization framework for CodeIgniter 4. -It is designed to be secure, flexible, and easily extendable to meet the needs of many different types of websites. -Among its many features are: - -* Session-based authentication -* Personal access token authentication -* Framework for after login/register "actions" (like Two Factor Authentication, etc.) -* Role-Based Access Control with simple, flexible permissions -* Per-user permission overrides -* And more... - -.. _settings: - -******** -Settings -******** - -`CodeIgniter Settings `_ is a wrapper around the configuration files that allows any -configuration setting to be saved to the database, while defaulting to the config files when no custom value has been -stored. This allows an application to ship with the default config values, but adapt as the project grows or moves -servers, without having to touch the code. - -***** -Tasks -***** - -`CodeIgniter Tasks `_ is a simple task scheduler for CodeIgniter 4. It allows you to -schedule tasks to run at specific times, or on a recurring basis. It is designed to be simple to use, but flexible -enough to handle most use cases. - -***** -Queue -***** - -`CodeIgniter Queue `_ is a simple queue system for CodeIgniter 4. It allows you to queue -up tasks to be run later. - -***** -Cache -***** - -We provide a library with `PSR-6 and PSR-16 Cache Adapters `_ for CodeIgniter 4. -This is not required for use, since CodeIgniter 4 comes with a fully functional cache component. This module is only for -integrating third-party packages that rely on the PSR interface provisions. - - -****** -DevKit -****** - -`CodeIgniter DevKit `_ provides all of the development tools that CodeIgniter -uses to help ensure quality code, including our coding standard, static analysis tools and rules, unit testing, data -generation, file-system mocking, security advisories, and more. This can be used in any of your personal projects or -libraries to get you rapidly set up with 17 different tools. - - -*************** -Coding Standard -*************** - -The `CodeIgniter Coding Standard `_ holds the official coding standards -of CodeIgniter based on PHP CS Fixer and powered by Nexus CS Config. This can be used in your own projects to form the -basis of a consistent set of style rules that can be automatically applied to your code. diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst deleted file mode 100644 index 3c5e43d210b9..000000000000 --- a/user_guide_src/source/libraries/pagination.rst +++ /dev/null @@ -1,376 +0,0 @@ -########## -Pagination -########## - -CodeIgniter provides a very simple but flexible pagination library that is simple to theme, works with the model, and is -capable of supporting multiple paginators on a single page. - -.. contents:: - :local: - :depth: 2 - -******************* -Loading the Library -******************* - -Like all services in CodeIgniter, it can be loaded via ``Config\Services``, though you usually will not need to load it -manually: - -.. literalinclude:: pagination/001.php - -.. _paginating-with-models: - -********************** -Paginating with Models -********************** - -In most cases, you will be using the Pager library in order to paginate results that you retrieve from the database. -When using the :doc:`Model ` class, you can use its built-in ``paginate()`` method to automatically -retrieve the current batch of results, as well as set up the Pager library so it's ready to use in your controllers. It -even reads the current page it should display from the current URL via a ``page=X`` query variable. - -To provide a paginated list of users in your application, your controller's method would look something like: - -.. literalinclude:: pagination/002.php - -In this example, we first create a new instance of our ``UserModel``. Then we populate the data to send to the view. The -first element is the results from the database, **users**, which are retrieved for the correct page, returning 10 users -per page. The second item that must be sent to the view is the Pager instance itself. As a convenience, the Model will -hold on to the instance it used and store it in the public property, ``$pager``. So, we grab that and assign it to the -``$pager`` variable in the view. - -Customizing Query for Pagination -================================ - -To customize a query for pagination in a model, you can add :doc:`Query Builder <../database/query_builder>` methods -before the ``paginate()`` method. - -Adding WHERE ------------- - -If you want to add WHERE conditions, you can specify conditions directly: - -.. literalinclude:: pagination/003.php - :lines: 2- - -You can move the conditions to a separate method: - -.. literalinclude:: pagination/017.php - -.. literalinclude:: pagination/018.php - :lines: 2- - -Adding JOIN ------------ - -You can join another table: - -.. literalinclude:: pagination/016.php - -.. important:: It is important to understand that the ``Model::paginate()`` method uses the **Model** and the - **Query Builder** instance in the Model. Therefore, trying to use ``Model::paginate()`` with :ref:`db-query` - **will not work** because ``$db->query()`` executes the query immediately and is not associated with the Query - Builder. - -If you need a complicated SQL query that you cannot write with Query Builder, try using :ref:`db-query` and -`Manual Pagination`_. - -Displaying Pager Links -====================== - -Within the view, we then need to tell it where to display the resulting links:: - - links() ?> - -And that's all it takes. The Pager class will render First and Last page links, as well as Next and Previous links for -any pages more than two pages on either side of the current page. - -It is important to be aware that the library pattern for Next and Previous is different from what is used in the -traditional way of paging results. - -Next and Previous here are linked to the group of links to be displayed in the pagination structure, and not to the next -or previous page of records. - -If you prefer a simpler output, you can use the ``simpleLinks()`` method, which only uses "Older" and "Newer" links, -instead of the detailed pagination links:: - - simpleLinks() ?> - -Behind the scenes, the library loads a view file that determines how the links are formatted, making it simple to modify -to your needs. See below for details on how to completely customize the output. - -Paginating Multiple Results -=========================== - -If you need to provide links from two different result sets, you can pass group names to most of the pagination methods -to keep the data separate: - -.. literalinclude:: pagination/004.php - -Setting Page Manually -===================== - -If you need to specify which page of results to return, you can specify the page as the 3rd argument. This can be handy -when you use a different way than the default ``$_GET`` variable to control which page to show. - -.. literalinclude:: pagination/005.php - -Specifying the URI Segment for Page -=================================== - -It is also possible to use a URI segment for the page number, instead of the page query parameter. Simply specify the -segment number to use as the fourth argument. URIs generated by the pager would then look like -**https://domain.tld/foo/bar/[pageNumber]** instead of **https://domain.tld/foo/bar?page=[pageNumber]**. - -.. literalinclude:: pagination/006.php - -Please note: the ``$segment`` value cannot be greater than the number of URI segments plus 1. - -***************** -Manual Pagination -***************** - -There may be times when you just need to create pagination based on known data. You can create links manually with the -``makeLinks()`` method, which takes the current page, the number of results per page, and the total number of items as -the first, second, and third parameters, respectively: - -.. literalinclude:: pagination/015.php - -This will, by default, display the links in the normal manner, as a series of links, but you can change the display -template used by passing in the name of the template as the fourth parameter. More details can be found in the following -sections:: - - $pager->makeLinks($page, $perPage, $total, 'template_name'); - -It is also possible to use a URI segment for the page number, instead of the page query parameter, as described in the -previous section. Specify the segment number to use as the fifth parameter to ``makeLinks()``:: - - $pager->makeLinks($page, $perPage, $total, 'template_name', $segment); - -Please note: the ``$segment`` value cannot be greater than the number of URI segments plus 1. - -If you need to show many pagers on one page, then an additional parameter that defines a group can be helpful: - -.. literalinclude:: pagination/007.php - -The Pagination library uses the **page** query parameter for HTTP queries by default (if no group or the ``default`` -group name is given) or ``page_[groupName]`` for custom group names. - -************************************* -Paginating with Only Expected Queries -************************************* - -By default, all GET queries are shown in the pagination links. - -For example, when accessing the URL **https://domain.tld?search=foo&order=asc&hello=i+am+here&page=2**, the page 3 link -can be generated, along with the other links, as follows: - -.. literalinclude:: pagination/008.php - -The ``only()`` method allows you to limit this just to queries already expected: - -.. literalinclude:: pagination/009.php - -The *page* query is enabled by default. The ``only()`` method applies to all pagination links. - -********************* -Customizing the Links -********************* - -View Configuration -================== - -When the links are rendered out to the page, they use a view file to describe the HTML. You can easily change the view -that is used by editing **app/Config/Pager.php**: - -.. literalinclude:: pagination/010.php - -This setting stores the alias and :doc:`namespaced view paths ` for the view that should be used. The -``default_full`` and ``default_simple`` views are used for the ``links()`` and ``simpleLinks()`` methods, respectively. -To change the way those are displayed application-wide, you could assign a new view here. - -For example, say you create a new view file that works with the Foundation CSS framework, and you place that file at -**app/Views/Pagers/foundation_full.php**. Since the **app** directory is namespaced as ``App``, and all directories -underneath it map directly to segments of the namespace, you can locate the view file through its namespace:: - - 'default_full' => 'App\Views\Pagers\foundation_full' - -Since it is under the standard **app/Views** directory, though, you do not need to namespace it since the ``view()`` -method can locate it by filename. In that case, you can simply give the sub-directory and file name:: - - 'default_full' => 'Pagers/foundation_full' - -Once you have created the view and set it in the configuration, it will automatically be used. You don't have to replace -the existing templates. You can create as many additional templates as you need in the configuration file. A common -situation would be needing different styles for the frontend and the backend of your application. - -.. literalinclude:: pagination/011.php - -Once configured, you can specify it as the last parameter in the ``links()``, ``simpleLinks()``, and ``makeLinks()`` -methods:: - - links('group1', 'front_full') ?> - simpleLinks('group2', 'front_full') ?> - makeLinks($page, $perPage, $total, 'front_full') ?> - -Creating the View -================= - -When you create a new view, you only need to create the code that is needed for creating the pagination links -themselves. You should not create unnecessary wrapping divs, since the view might be used in multiple places and they -would only limit its usefulness. It is easiest to demonstrate creating a new view by showing you the existing -``default_full`` template: - -.. literalinclude:: pagination/012.php - -setSurroundCount() ------------------- - -In the first line, the ``setSurroundCount()`` method specifies that we want to show two links to either side of the -current page link. The only parameter that it accepts is the number of links to show. - -.. note:: You must call this method first to generate correct pagination links. - -hasPrevious() & hasNext() -------------------------- - -These methods return a boolean ``true`` if there are more links that can be displayed on either side of the current -page, based on the value passed to `setSurroundCount()`_. - -For example, let's say we have 20 pages of data. The current page is page 3. If the surrounding count is 2, then the -following links would show up like this:: - - 1 | 2 | 3 | 4 | 5 - -Since the first link displayed is page one, ``hasPrevious()`` would return ``false`` since there is no page zero. -However, ``hasNext()`` would return ``true`` since there are 15 additional pages of results after page five. - -getPrevious() & getNext() -------------------------- - -These methods return the **URL** for the previous or next pages of results on either side of the numbered links. - -For example, if you have the current page set at 5 and you want the links before and after (the surroundCount) to be 2 -each, that will give you something like this:: - - 3 | 4 | 5 | 6 | 7 - -``getPrevious()`` returns the URL for page 2. ``getNext()`` returns the URL for page 8. - -If you want to get page 4 and page 6, use `getPreviousPage() & getNextPage()`_ instead. - -getFirst() & getLast() ----------------------- - -Much like `getPrevious() & getNext()`_, these methods return the **URL** to the first and last pages in the result set. - -links() -------- - -Returns an array of data about all of the numbered links. Each link's array contains the URI for the link, the title, -which is just the number, and a boolean that tells whether the link is the current/active link or not: - -.. literalinclude:: pagination/013.php - -In the code presented for the standard pagination structure, the methods `getPrevious() & getNext()`_ are used to obtain -the links to the previous and next pagination groups, respectively. - -If you want to use the pagination structure where prev and next will be links to the previous and next pages based on -the current page, just replace the `getPrevious() & getNext()`_ methods with `getPreviousPage() & getNextPage()`_, and -the methods `hasPrevious() & hasNext()`_ with `hasPreviousPage() & hasNextPage()`_, respectively. - -See the following example with these changes: - -.. literalinclude:: pagination/014.php - -hasPreviousPage() & hasNextPage() ---------------------------------- - -These methods return a boolean ``true`` if there are links to a page before and after, respectively, the current page -being displayed. - -For example, let's say we have 20 pages of data. The current page is page 3. If the surrounding count is 2, then the -following links would show up like this:: - - 1 | 2 | 3 | 4 | 5 - -``hasPreviousPage()`` would return ``true`` since page 2 exists, and ``hasNextPage()`` would return ``true`` since page -4 exists. - -.. note:: The difference from `hasPrevious() & hasNext()`_ is that these methods are based on the current page, while - `hasPrevious() & hasNext()`_ are based on the set of links to be displayed before and after the current page based - on the value passed in `setSurroundCount()`_. - -getPreviousPage() & getNextPage() ---------------------------------- - -These methods return a **URL** for the previous and next pages in relation to the current page being displayed. - -For example, if you have the current page set at 5 and you want the links before and after (the surroundCount) to be 2 -each, that will give you something like this:: - - 3 | 4 | 5 | 6 | 7 - -``getPreviousPage()`` returns the URL for page 4. ``getNextPage()`` returns the URL for page 6. - -.. note:: `getPrevious() & getNext()`_ return the URL for the previous or next pages of results on either side of the - numbered links. - -If you want page numbers instead of URLs, you can use the following methods: - -getPreviousPageNumber() & getNextPageNumber() ---------------------------------------------- - -These methods return the page number for the previous or next pages in relation to the current page being displayed. - -getFirstPageNumber() & getLastPageNumber() ------------------------------------------- - -These methods return the page numbers of the first and last pages in the set of links to be displayed. For example, if -the set of links to be displayed is something like this:: - - 3 | 4 | 5 | 6 | 7 - -``getFirstPageNumber()`` will return 3 while ``getLastPageNumber()`` will return 7. - -.. note:: To obtain the page numbers of the first and last pages in the entire result set, you can use the following - approach: The first page number is always 1, and `getPageCount()`_ can be used to retrieve the last page number. - -getCurrentPageNumber() ----------------------- - -This method returns the page number of the current page. - -getPageCount() --------------- - -This method returns the total number of pages. - -.. _displaying-the-number-of-items-on-the-page: - -Displaying the Number of Items on the Page -========================================== - -.. versionadded:: 4.6.0 - -When paginating items, it’s often helpful to display the total number of items and the range of items shown on the -current page. To simplify this task, new methods have been added. These methods make it easier to manage and display -pagination details. Here's an example: - -.. literalinclude:: pagination/019.php - -getTotal() ----------- -Returns the total number of items. - -getPerPage() ------------- -Returns the number of items to be displayed on the page. - -getPerPageStart() ------------------ -Returns the number of the item the page starts with. - -getPerPageEnd() ---------------- -Returns the number of the item the page ends with. diff --git a/user_guide_src/source/libraries/pagination/001.php b/user_guide_src/source/libraries/pagination/001.php deleted file mode 100644 index 4b67fd5511de..000000000000 --- a/user_guide_src/source/libraries/pagination/001.php +++ /dev/null @@ -1,3 +0,0 @@ - $model->paginate(10), - 'pager' => $model->pager, - ]; - - return view('users/index', $data); - } -} diff --git a/user_guide_src/source/libraries/pagination/003.php b/user_guide_src/source/libraries/pagination/003.php deleted file mode 100644 index 262385ea0eb8..000000000000 --- a/user_guide_src/source/libraries/pagination/003.php +++ /dev/null @@ -1,11 +0,0 @@ - $model->where('ban', 1)->paginate(10), - 'pager' => $model->pager, -]; diff --git a/user_guide_src/source/libraries/pagination/004.php b/user_guide_src/source/libraries/pagination/004.php deleted file mode 100644 index b7af3ec83d2a..000000000000 --- a/user_guide_src/source/libraries/pagination/004.php +++ /dev/null @@ -1,28 +0,0 @@ - $userModel->paginate(10, 'group1'), - 'pages' => $pageModel->paginate(15, 'group2'), - 'pager' => $userModel->pager, - ]; - - echo view('users/index', $data); - } -} -?> - - -links('group1') ?> -simpleLinks('group2') ?> diff --git a/user_guide_src/source/libraries/pagination/005.php b/user_guide_src/source/libraries/pagination/005.php deleted file mode 100644 index 2dc3405b8a62..000000000000 --- a/user_guide_src/source/libraries/pagination/005.php +++ /dev/null @@ -1,8 +0,0 @@ -paginate(10, 'group1', $page); diff --git a/user_guide_src/source/libraries/pagination/006.php b/user_guide_src/source/libraries/pagination/006.php deleted file mode 100644 index 9d754431ce58..000000000000 --- a/user_guide_src/source/libraries/pagination/006.php +++ /dev/null @@ -1,3 +0,0 @@ -paginate(10, 'group1', null, $segment); diff --git a/user_guide_src/source/libraries/pagination/007.php b/user_guide_src/source/libraries/pagination/007.php deleted file mode 100644 index be726a996116..000000000000 --- a/user_guide_src/source/libraries/pagination/007.php +++ /dev/null @@ -1,5 +0,0 @@ -setPath('path/for/my-group', 'my-group'); // Additionally you could define path for every group. -$pager->makeLinks($page, $perPage, $total, 'template_name', $segment, 'my-group'); diff --git a/user_guide_src/source/libraries/pagination/008.php b/user_guide_src/source/libraries/pagination/008.php deleted file mode 100644 index 0b8219ff43e3..000000000000 --- a/user_guide_src/source/libraries/pagination/008.php +++ /dev/null @@ -1,4 +0,0 @@ -links(); -// Page 3 link: https://domain.tld?search=foo&order=asc&hello=i+am+here&page=3 diff --git a/user_guide_src/source/libraries/pagination/009.php b/user_guide_src/source/libraries/pagination/009.php deleted file mode 100644 index 6f309ca10552..000000000000 --- a/user_guide_src/source/libraries/pagination/009.php +++ /dev/null @@ -1,4 +0,0 @@ -only(['search', 'order'])->links(); -// Page 3 link: https://domain.tld?search=foo&order=asc&page=3 diff --git a/user_guide_src/source/libraries/pagination/010.php b/user_guide_src/source/libraries/pagination/010.php deleted file mode 100644 index 86947793c132..000000000000 --- a/user_guide_src/source/libraries/pagination/010.php +++ /dev/null @@ -1,15 +0,0 @@ - 'CodeIgniter\Pager\Views\default_full', - 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/pagination/011.php b/user_guide_src/source/libraries/pagination/011.php deleted file mode 100644 index 6c15797754e0..000000000000 --- a/user_guide_src/source/libraries/pagination/011.php +++ /dev/null @@ -1,16 +0,0 @@ - 'CodeIgniter\Pager\Views\default_full', - 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', - 'front_full' => 'App\Views\Pagers\foundation_full', - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/pagination/012.php b/user_guide_src/source/libraries/pagination/012.php deleted file mode 100644 index 00bdee764c7f..000000000000 --- a/user_guide_src/source/libraries/pagination/012.php +++ /dev/null @@ -1,39 +0,0 @@ -setSurroundCount(2) ?> - - diff --git a/user_guide_src/source/libraries/pagination/013.php b/user_guide_src/source/libraries/pagination/013.php deleted file mode 100644 index 43a8f2624d64..000000000000 --- a/user_guide_src/source/libraries/pagination/013.php +++ /dev/null @@ -1,7 +0,0 @@ - false, - 'uri' => 'https://example.com/foo?page=2', - 'title' => 1, -]; diff --git a/user_guide_src/source/libraries/pagination/014.php b/user_guide_src/source/libraries/pagination/014.php deleted file mode 100644 index e827bd15a457..000000000000 --- a/user_guide_src/source/libraries/pagination/014.php +++ /dev/null @@ -1,37 +0,0 @@ - diff --git a/user_guide_src/source/libraries/pagination/015.php b/user_guide_src/source/libraries/pagination/015.php deleted file mode 100644 index ac9f4fc430f0..000000000000 --- a/user_guide_src/source/libraries/pagination/015.php +++ /dev/null @@ -1,31 +0,0 @@ -request->getGet('page') ?? 1); - $perPage = 20; - $total = 200; - - // Call makeLinks() to make pagination links. - $pager_links = $pager->makeLinks($page, $perPage, $total); - - $data = [ - // ... - 'pager_links' => $pager_links, - ]; - - return view('users/index', $data); - } -} -?> - - - diff --git a/user_guide_src/source/libraries/pagination/016.php b/user_guide_src/source/libraries/pagination/016.php deleted file mode 100644 index 64be257b4152..000000000000 --- a/user_guide_src/source/libraries/pagination/016.php +++ /dev/null @@ -1,24 +0,0 @@ -builder() - ->select('news.*, category.name') - ->join('category', 'news.category_id = category.id'); - - return [ - 'news' => $this->paginate($perPage), - 'pager' => $this->pager, - ]; - } -} diff --git a/user_guide_src/source/libraries/pagination/017.php b/user_guide_src/source/libraries/pagination/017.php deleted file mode 100644 index 86e656be5fac..000000000000 --- a/user_guide_src/source/libraries/pagination/017.php +++ /dev/null @@ -1,17 +0,0 @@ -builder()->where('ban', 1); - - return $this; // This will allow the call chain to be used. - } -} diff --git a/user_guide_src/source/libraries/pagination/018.php b/user_guide_src/source/libraries/pagination/018.php deleted file mode 100644 index afabd1c8c998..000000000000 --- a/user_guide_src/source/libraries/pagination/018.php +++ /dev/null @@ -1,11 +0,0 @@ - $model->banned()->paginate(10), - 'pager' => $model->pager, -]; diff --git a/user_guide_src/source/libraries/pagination/019.php b/user_guide_src/source/libraries/pagination/019.php deleted file mode 100644 index 91c514948111..000000000000 --- a/user_guide_src/source/libraries/pagination/019.php +++ /dev/null @@ -1,7 +0,0 @@ -setSurroundCount(1) ?> - -

- Showing getPerPageStart() ?> - to getPerPageEnd() ?> - of getTotal() ?> results -

diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst deleted file mode 100644 index cec5579f037c..000000000000 --- a/user_guide_src/source/libraries/publisher.rst +++ /dev/null @@ -1,331 +0,0 @@ -######### -Publisher -######### - -The Publisher library provides a means to copy files within a project using robust detection and error checking. - -.. contents:: - :local: - :depth: 2 - -******************* -Loading the Library -******************* - -Because Publisher instances are specific to their source and destination, this library is not available through -``Services`` but should be instantiated or extended directly. E.g.: - -.. literalinclude:: publisher/001.php - -***************** -Concept and Usage -***************** - -``Publisher`` solves a handful of common problems when working within a backend framework: - -* How do I maintain project assets with version dependencies? -* How do I manage uploads and other "dynamic" files that need to be web-accessible? -* How can I update my project when the framework or modules change? -* How can components inject new content into existing projects? - -At its most basic, publishing amounts to copying a file or files into a project. ``Publisher`` extends -``FileCollection`` to enact fluent-style command chaining to read, filter, and process input files, then copies or -merges them into the target destination. You may use ``Publisher`` on demand in your Controllers or other components, or -you may stage publications by extending the class and leveraging its discovery with ``spark publish``. - -On Demand -========= - -Access ``Publisher`` directly by instantiating a new instance of the class: - -.. literalinclude:: publisher/002.php - -By default, the source and destination will be set to ``ROOTPATH`` and ``FCPATH``, respectively, giving ``Publisher`` -easy access to take any file from your project and make it web-accessible. Alternatively, you may pass a new source or -source and destination into the constructor: - -.. literalinclude:: publisher/003.php - -Once all the files are staged, use one of the output commands (**copy()** or **merge()**) to process the staged files to -their destination(s): - -.. literalinclude:: publisher/004.php - -See the :ref:`reference` for a full description of available methods. - -Automation and Discovery -======================== - -You may have regular publication tasks embedded as part of your application deployment or upkeep. ``Publisher`` -leverages the powerful ``Autoloader`` to locate any child classes primed for publication: - -.. literalinclude:: publisher/005.php - -By default, ``discover()`` will search for the "Publishers" directory across all namespaces, but you may specify a -different directory and it will return any child classes found: - -.. literalinclude:: publisher/006.php - -Most of the time you will not need to handle your own discovery. Just use the provided "publish" command: - -.. code-block:: console - - php spark publish - -By default, on your class extension, ``publish()`` will add all files from your ``$source`` and merge them out to your -destination, overwriting on collision. - -.. _discovery-in-a-specific-namespace: - -Discovery in a specific namespace ---------------------------------- - -.. versionadded:: 4.6.0 - -Since v4.6.0, you can also scan a specific namespace. This not only reduces the number of files to be scanned, but also -avoids the need to rerun a Publisher. All you need to do is specify the desired root namespace in the second parameter -of the ``discover()`` method. - -.. literalinclude:: publisher/016.php - -The specified namespace must be known to CodeIgniter. You can check the list of all namespaces using the "spark -namespaces" command: - -.. code-block:: console - - php spark namespaces - -The "publish" command also offers the ``--namespace`` option to define the namespace when searching for Publishers that -might come from a library. - -.. code-block:: console - - php spark publish --namespace Namespace\Vendor\Package - -Security -======== - -In order to prevent modules from injecting malicious code into your projects, ``Publisher`` contains a config file that -defines which directories and file patterns are allowed as destinations. By default, files may only be published to your -project (to prevent access to the rest of the filesystem), and the **public/** folder (``FCPATH``) will only receive -files with the following extensions: - -* Web assets: css, scss, js, map -* Non-executable web files: htm, html, xml, json, webmanifest -* Fonts: ttf, eot, woff, woff2 -* Images: gif, jpg, jpeg, tif, tiff, png, webp, bmp, ico, svg - -If you need to add or adjust the security for your project, then alter the ``$restrictions`` property of -``Config\Publisher`` in **app/Config/Publisher.php**. - -******** -Examples -******** - -Here are a handful of example use cases and their implementations to help you get started publishing. - -File Sync Example -================= - -You want to display a "photo of the day" image on your homepage. You have a feed for daily photos, but you need to get -the actual file into a browsable location in your project at **public/images/daily_photo.jpg**. You can set up a -:doc:`Custom Command ` that runs daily to handle this for you: - -.. literalinclude:: publisher/007.php - -Now running ``spark publish:daily`` will keep your homepage's image up to date. What if the photo is coming from an -external API? You can use ``addUri()`` in place of ``addPath()`` to download the remote resource and publish it out -instead: - -.. literalinclude:: publisher/008.php - -Asset Dependencies Example -========================== - -You want to integrate the frontend library "Bootstrap" into your project, but the frequent updates make it a hassle to -keep up with. You can create a publication definition in your project to sync frontend assets by extending ``Publisher`` -in your project. So **app/Publishers/BootstrapPublisher.php** might look like this: - -.. literalinclude:: publisher/009.php - -.. note:: The ``$destination`` directory must be created before executing the command. - -Now add the dependency via Composer and call ``spark publish`` to run the publication: - -.. code-block:: console - - composer require twbs/bootstrap - php spark publish - -... and you'll end up with something like this:: - - public/.htaccess - public/favicon.ico - public/index.php - public/robots.txt - public/ - bootstrap/ - css/ - bootstrap.min.css - bootstrap-utilities.min.css.map - bootstrap-grid.min.css - bootstrap.rtl.min.css - bootstrap.min.css.map - bootstrap-reboot.min.css - bootstrap-utilities.min.css - bootstrap-reboot.rtl.min.css - bootstrap-grid.min.css.map - js/ - bootstrap.esm.min.js - bootstrap.bundle.min.js.map - bootstrap.bundle.min.js - bootstrap.min.js - bootstrap.esm.min.js.map - bootstrap.min.js.map - -Module Deployment Example -========================= - -You want to give developers using your popular authentication module the ability to expand on the default behavior of -your Migration, Controller, and Model. You can create your own module "publish" command to inject these components into -an application for use: - -.. literalinclude:: publisher/010.php - -Now when your module users run ``php spark auth:publish`` they will have the following added to their project:: - - app/Controllers/AuthController.php - app/Database/Migrations/2017-11-20-223112_create_auth_tables.php - app/Models/LoginModel.php - app/Models/UserModel.php - -.. _reference: - -***************** -Library Reference -***************** - -.. note:: ``Publisher`` is an extension of :doc:`FileCollection `, so it has access to all - those methods for reading and filtering files. - -Support Methods -=============== - -[static] discover(string $directory = 'Publishers', string $namespace = ''): Publisher[] ----------------------------------------------------------------------------------------- - -Discovers and returns all Publishers in the specified namespace directory. For example, if both -**app/Publishers/FrameworkPublisher.php** and **myModule/src/Publishers/AssetPublisher.php** exist and are extensions of -``Publisher``, then ``Publisher::discover()`` would return an instance of each. - -publish(): bool ---------------- - -Processes the full input-process-output chain. By default, this is the equivalent of calling ``addPath($source)`` and -``merge(true)``, but child classes will typically provide their own implementation. ``publish()`` is called on all -discovered Publishers when running ``spark publish``. Returns success or failure. - -getScratch(): string --------------------- - -Returns the temporary workspace, creating it if necessary. Some operations use intermediate storage to stage files and -changes, and this provides the path to a transient, writable directory that you may use as well. - -getErrors(): array -------------------------------------- - -Returns any errors from the last write operation. The array keys are the files that caused the error, and the values are -the Throwable that was caught. Use ``getMessage()`` on the Throwable to get the error message. - -addPath(string $path, bool $recursive = true) ---------------------------------------------- - -Adds all files indicated by the relative path. The path is a reference to actual files or directories relative to -``$source``. If the relative path resolves to a directory then ``$recursive`` will include sub-directories. - -addPaths(array $paths, bool $recursive = true) ----------------------------------------------- - -Adds all files indicated by the relative paths. The paths are references to actual files or directories relative to -``$source``. If a relative path resolves to a directory then ``$recursive`` will include sub-directories. - -addUri(string $uri) -------------------- - -Downloads the contents of a URI using ``CURLRequest`` into the scratch workspace, then adds the resulting file to the -list. - -addUris(array $uris) --------------------- - -Downloads the contents of URIs using ``CURLRequest`` into the scratch workspace, then adds the resulting files to the -list. - -.. note:: The CURL request made is a simple ``GET`` and uses the response body for the file contents. Some remote files - may need a custom request to be handled properly. - -Outputting Files -================ - -wipe() ------- - -Removes all files, directories, and sub-directories from ``$destination``. - -.. important:: Use wisely. - -copy(bool $replace = true): bool --------------------------------- - -Copies all files into the ``$destination``. This does not recreate the directory structure, so every file from the -current list will end up in the same destination directory. Using ``$replace`` will cause files to overwrite when there -is already an existing file. Returns success or failure. Use ``getPublished()`` and ``getErrors()`` to troubleshoot -failures. Be mindful of duplicate basename collisions, for example: - -.. literalinclude:: publisher/011.php - -merge(bool $replace = true): bool ---------------------------------- - -Copies all files into the ``$destination`` in appropriate relative sub-directories. Any files that match ``$source`` -will be placed into their equivalent directories in ``$destination``, effectively creating a "mirror" or "rsync" -operation. Using ``$replace`` will cause files to overwrite when there is already an existing file. Since directories -are merged, this will not affect other files in the destination. Returns success or failure. Use ``getPublished()`` and -``getErrors()`` to troubleshoot failures. - -Example: - -.. literalinclude:: publisher/012.php - -.. _publisher-modifying-files: - -Modifying Files -=============== - -replace(string $file, array $replaces): bool --------------------------------------------- - -.. versionadded:: 4.3.0 - -Replaces the ``$file`` contents. The second parameter ``$replaces`` array specifies the search strings as keys and the -replacements as values. - -.. literalinclude:: publisher/013.php - -addLineAfter(string $file, string $line, string $after): bool -------------------------------------------------------------- - -.. versionadded:: 4.3.0 - -Adds ``$line`` after a line with the specific string ``$after``. - -.. literalinclude:: publisher/014.php - -addLineBefore(string $file, string $line, string $before): bool ---------------------------------------------------------------- - -.. versionadded:: 4.3.0 - -Adds ``$line`` before a line with the specific string ``$before``. - -.. literalinclude:: publisher/015.php diff --git a/user_guide_src/source/libraries/publisher/001.php b/user_guide_src/source/libraries/publisher/001.php deleted file mode 100644 index 6312e0d034f4..000000000000 --- a/user_guide_src/source/libraries/publisher/001.php +++ /dev/null @@ -1,3 +0,0 @@ -addPath('app/Config/Cookie.php'); - -// You may also add from outside the source, but the files will not be merged into subdirectories -$frameworkPublisher->addFiles([ - '/opt/mail/susan', - '/opt/mail/ubuntu', -]); -$frameworkPublisher->addDirectory(SUPPORTPATH . 'Images'); diff --git a/user_guide_src/source/libraries/publisher/004.php b/user_guide_src/source/libraries/publisher/004.php deleted file mode 100644 index f516a8cab4aa..000000000000 --- a/user_guide_src/source/libraries/publisher/004.php +++ /dev/null @@ -1,10 +0,0 @@ -copy(); - -// Place all files into $destination, overwriting existing files -$frameworkPublisher->copy(true); - -// Place files into their relative $destination directories, overwriting and saving the boolean result -$result = $frameworkPublisher->merge(true); diff --git a/user_guide_src/source/libraries/publisher/005.php b/user_guide_src/source/libraries/publisher/005.php deleted file mode 100644 index 8984c56f0011..000000000000 --- a/user_guide_src/source/libraries/publisher/005.php +++ /dev/null @@ -1,12 +0,0 @@ -publish(); - - if ($result === false) { - CLI::error($publisher::class . ' failed to publish!', 'red'); - } -} diff --git a/user_guide_src/source/libraries/publisher/006.php b/user_guide_src/source/libraries/publisher/006.php deleted file mode 100644 index 5a1eb24c87b2..000000000000 --- a/user_guide_src/source/libraries/publisher/006.php +++ /dev/null @@ -1,5 +0,0 @@ -addPath('daily_photo.jpg')->copy(true); // `true` to enable overwrites - } catch (Throwable $e) { - $this->showError($e); - } - } -} diff --git a/user_guide_src/source/libraries/publisher/008.php b/user_guide_src/source/libraries/publisher/008.php deleted file mode 100644 index 23467e5b28bf..000000000000 --- a/user_guide_src/source/libraries/publisher/008.php +++ /dev/null @@ -1,3 +0,0 @@ -addUri('https://example.com/feeds/daily_photo.jpg')->copy(true); diff --git a/user_guide_src/source/libraries/publisher/009.php b/user_guide_src/source/libraries/publisher/009.php deleted file mode 100644 index f3c2fb21d5f2..000000000000 --- a/user_guide_src/source/libraries/publisher/009.php +++ /dev/null @@ -1,43 +0,0 @@ -addPath('dist') - - // Indicate we only want the minimized versions - ->retainPattern('*.min.*') - - // Merge-and-replace to retain the original directory structure - ->merge(true); - } -} diff --git a/user_guide_src/source/libraries/publisher/010.php b/user_guide_src/source/libraries/publisher/010.php deleted file mode 100644 index 61b75287e51f..000000000000 --- a/user_guide_src/source/libraries/publisher/010.php +++ /dev/null @@ -1,43 +0,0 @@ -getNamespace('Math\\Auth')[0]; - - $publisher = new Publisher($source, APPPATH); - - try { - // Add only the desired components - $publisher->addPaths([ - 'Controllers', - 'Database/Migrations', - 'Models', - ])->merge(false); // Be careful not to overwrite anything - } catch (Throwable $e) { - $this->showError($e); - - return; - } - - // If publication succeeded then update namespaces - foreach ($publisher->getPublished() as $file) { - // Replace the namespace - $contents = file_get_contents($file); - $contents = str_replace('namespace Math\\Auth', 'namespace ' . APP_NAMESPACE, $contents); - file_put_contents($file, $contents); - } - } -} diff --git a/user_guide_src/source/libraries/publisher/011.php b/user_guide_src/source/libraries/publisher/011.php deleted file mode 100644 index 6e7ce630232e..000000000000 --- a/user_guide_src/source/libraries/publisher/011.php +++ /dev/null @@ -1,12 +0,0 @@ -addPaths([ - 'pencil/lead.png', - 'metal/lead.png', -]); - -// This is bad! Only one file will remain at /home/destination/lead.png -$publisher->copy(true); diff --git a/user_guide_src/source/libraries/publisher/012.php b/user_guide_src/source/libraries/publisher/012.php deleted file mode 100644 index 7d978744758a..000000000000 --- a/user_guide_src/source/libraries/publisher/012.php +++ /dev/null @@ -1,12 +0,0 @@ -addPaths([ - 'pencil/lead.png', - 'metal/lead.png', -]); - -// Results in "/home/destination/pencil/lead.png" and "/home/destination/metal/lead.png" -$publisher->merge(); diff --git a/user_guide_src/source/libraries/publisher/013.php b/user_guide_src/source/libraries/publisher/013.php deleted file mode 100644 index a4838c99bfee..000000000000 --- a/user_guide_src/source/libraries/publisher/013.php +++ /dev/null @@ -1,16 +0,0 @@ -getNamespace('CodeIgniter\\Shield')[0]; -$publisher = new Publisher($source, APPPATH); - -$file = APPPATH . 'Config/Auth.php'; - -$publisher->replace( - $file, - [ - 'use CodeIgniter\Config\BaseConfig;' . "\n" => '', - 'class App extends BaseConfig' => 'class App extends \Some\Package\SomeConfig', - ], -); diff --git a/user_guide_src/source/libraries/publisher/014.php b/user_guide_src/source/libraries/publisher/014.php deleted file mode 100644 index eadecf59944b..000000000000 --- a/user_guide_src/source/libraries/publisher/014.php +++ /dev/null @@ -1,14 +0,0 @@ -getNamespace('CodeIgniter\\Shield')[0]; -$publisher = new Publisher($source, APPPATH); - -$file = APPPATH . 'Config/App.php'; - -$publisher->addLineAfter( - $file, - ' public int $myOwnConfig = 1000;', // Adds this line - 'public bool $CSPEnabled = false;', // After this line -); diff --git a/user_guide_src/source/libraries/publisher/015.php b/user_guide_src/source/libraries/publisher/015.php deleted file mode 100644 index af00d5c65451..000000000000 --- a/user_guide_src/source/libraries/publisher/015.php +++ /dev/null @@ -1,14 +0,0 @@ -getNamespace('CodeIgniter\\Shield')[0]; -$publisher = new Publisher($source, APPPATH); - -$file = APPPATH . 'Config/App.php'; - -$publisher->addLineBefore( - $file, - ' public int $myOwnConfig = 1000;', // Add this line - 'public bool $CSPEnabled = false;', // Before this line -); diff --git a/user_guide_src/source/libraries/publisher/016.php b/user_guide_src/source/libraries/publisher/016.php deleted file mode 100644 index 54f2beca5701..000000000000 --- a/user_guide_src/source/libraries/publisher/016.php +++ /dev/null @@ -1,5 +0,0 @@ -add()``, and use HTTP verbs in routes. -2. Check the request method in the controller method before processing. - -E.g.:: - - if (! $this->request->is('post')) { - return $this->response->setStatusCode(405)->setBody('Method Not Allowed'); - } - -.. note:: The :ref:`$this->request->is() ` method can be used since v4.3.0. In previous versions, - you need to use ``if (strtolower($this->request->getMethod()) !== 'post')``. - -When Auto-Routing is Enabled ----------------------------- - -1. Check the request method in the controller method before processing. - -E.g.:: - - if (! $this->request->is('post')) { - return $this->response->setStatusCode(405)->setBody('Method Not Allowed'); - } - -Config for CSRF -=============== - -.. _csrf-protection-methods: - -CSRF Protection Methods ------------------------ - -.. warning:: If you use :doc:`Session <./sessions>`, be sure to use Session-based CSRF protection. Cookie-based CSRF - protection will not prevent Same-site attacks. See - `GHSA-5hm8-vh6r-2cjq `_ for details. - -By default, the Cookie-based CSRF Protection is used. It is the -`Double Submit Cookie `_ -pattern on the OWASP Cross-Site Request Forgery Prevention Cheat Sheet. - -You can also use Session-based CSRF Protection. It is the -`Synchronizer Token Pattern `_. - -You can use the Session-based CSRF protection by editing the following config parameter value in -**app/Config/Security.php**: - -.. literalinclude:: security/002.php - -Token Randomization -------------------- - -To mitigate compression side-channel attacks like `BREACH`_, and prevent an attacker from guessing the CSRF tokens, you -can configure token randomization (off by default). - -If you enable it, a random mask is added to the token and used to scramble it. - -.. _`BREACH`: https://en.wikipedia.org/wiki/BREACH - -You can enable it by editing the following config parameter value in **app/Config/Security.php**: - -.. literalinclude:: security/003.php - -Token Regeneration ------------------- - -Tokens may be either regenerated on every submission (default) or kept the same throughout the life of the Session or -CSRF cookie. - -The default regeneration of tokens provides stricter security, but may result in usability concerns as other tokens -become invalid (back/forward navigation, multiple tabs/windows, asynchronous actions, etc.). You may alter this behavior -by editing the following config parameter value in **app/Config/Security.php**: - -.. literalinclude:: security/004.php - -.. warning:: If you use Cookie-based CSRF protection, and :php:func:`redirect()` after the submission, you must call - ``withCookie()`` to send the regenerated CSRF cookie. See :ref:`response-redirect` for details. - -.. note:: Since v4.2.3, you can regenerate the CSRF token manually with the ``Security::generateHash()`` method. - -.. _csrf-redirection-on-failure: - -Redirection on Failure ----------------------- - -Starting with v4.5.0, when a request fails the CSRF validation check, by default, the user is redirected to the previous -page in the production environment, or a SecurityException is thrown in other environments. - -.. note:: In the production environment, when you use HTML forms, it is recommended to enable this redirection for a - better user experience. - - Upgrade users should check their configuration files. - -If you want to make it redirect to the previous page, set the following config parameter value to ``true`` in -**app/Config/Security.php**: - -.. literalinclude:: security/005.php - -When redirected, an ``error`` flash message is set and can be displayed to the end user with the following code in your -view:: - - getFlashdata('error') ?> - -This provides a nicer experience than simply crashing. - -Even when the redirect value is ``true``, AJAX calls will not redirect, but will throw a SecurityException. - -.. _enable-csrf-protection: - -Enable CSRF Protection -====================== - -You can enable CSRF protection by altering your **app/Config/Filters.php** and enabling the ``csrf`` filter globally: - -.. literalinclude:: security/006.php - -Select URIs can be whitelisted from CSRF protection (for example, API endpoints expecting externally POSTed content). -You can do this by adding them as exceptions in the filter: - -.. literalinclude:: security/007.php - -Regular expressions are also supported (case-insensitive): - -.. literalinclude:: security/008.php - -It is also possible to enable the CSRF filter only for specific methods: - -.. literalinclude:: security/009.php - -.. Warning:: If you use ``$methods`` filters, you should :ref:`disable Auto Routing (Legacy) ` - because :ref:`auto-routing-legacy` permits any HTTP method to access a controller. Accessing the controller with a - method you don't expect could bypass the filter. - -HTML Forms -========== - -If you use the :doc:`form helper <../helpers/form_helper>`, then :func:`form_open()` will automatically insert a hidden -CSRF field in your forms. - -.. note:: To use auto-generation of the CSRF field, you need to turn the CSRF filter on for the form page. In most - cases, it is requested using the ``GET`` method. - -If not, then you can use the always available ``csrf_token()`` and ``csrf_hash()`` functions:: - - - -Additionally, you can use the ``csrf_field()`` method to generate this hidden input field for you:: - - // Generates: - - -When sending a JSON request, the CSRF token can also be passed as one of the parameters. The next way to pass the CSRF -token is a special HTTP header whose name is available from the ``csrf_header()`` function. - -Additionally, you can use the ``csrf_meta()`` method to generate this handy meta tag for you:: - - // Generates: - - -The Order of Token Sent by Users -================================ - -The order of checking the availability of the CSRF token is as follows: - -1. ``$_POST`` array -2. HTTP header -3. ``php://input`` (JSON request) - bear in mind that this approach is the slowest one since we have to decode JSON and - then re-encode it -4. ``php://input`` (raw body) - for PUT, PATCH, and DELETE type of requests - -.. note:: ``php://input`` (raw body) is checked since v4.4.2. - -.. note:: - - If you include the CSRF token in a JSON object, removing it decodes and re-encodes the body. This changes its - formatting and may affect number precision. To keep the JSON body unchanged, send the token in the ``X-CSRF-TOKEN`` - header and leave the CSRF field out of the body. - -********************* -Other Helpful Methods -********************* - -You will never need to use most of the methods in the Security class directly. The following are methods that you might -find helpful that are not related to the CSRF protection. - -sanitizeFilename() -================== - -Tries to sanitize filenames in order to prevent directory traversal attempts and other security threats, which is -particularly useful for files that were supplied via user input. The first parameter is the path to sanitize. - -If it is acceptable for the user input to include relative paths, e.g., **file/in/some/approved/folder.txt**, you can -set the second optional parameter, ``$relativePath``, to ``true``. - -.. literalinclude:: security/010.php - -This method is an alias for the ``sanitize_filename()`` function from the Security helper. diff --git a/user_guide_src/source/libraries/security/001.php b/user_guide_src/source/libraries/security/001.php deleted file mode 100644 index f81de1a9432c..000000000000 --- a/user_guide_src/source/libraries/security/001.php +++ /dev/null @@ -1,3 +0,0 @@ - [ - // 'honeypot', - 'csrf', - ], - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/security/007.php b/user_guide_src/source/libraries/security/007.php deleted file mode 100644 index 437bc7bfbead..000000000000 --- a/user_guide_src/source/libraries/security/007.php +++ /dev/null @@ -1,16 +0,0 @@ - [ - 'csrf' => ['except' => ['api/record/save']], - ], - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/security/008.php b/user_guide_src/source/libraries/security/008.php deleted file mode 100644 index 8a4a6ef4d430..000000000000 --- a/user_guide_src/source/libraries/security/008.php +++ /dev/null @@ -1,16 +0,0 @@ - [ - 'csrf' => ['except' => ['api/record/[0-9]+']], - ], - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/security/009.php b/user_guide_src/source/libraries/security/009.php deleted file mode 100644 index fb9d114b026e..000000000000 --- a/user_guide_src/source/libraries/security/009.php +++ /dev/null @@ -1,15 +0,0 @@ - ['csrf'], - 'POST' => ['csrf'], - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/security/010.php b/user_guide_src/source/libraries/security/010.php deleted file mode 100644 index 228df8107fda..000000000000 --- a/user_guide_src/source/libraries/security/010.php +++ /dev/null @@ -1,3 +0,0 @@ -sanitizeFilename($request->getVar('filepath')); diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst deleted file mode 100644 index 55a757d7ecad..000000000000 --- a/user_guide_src/source/libraries/sessions.rst +++ /dev/null @@ -1,673 +0,0 @@ -############### -Session Library -############### - -The Session class permits you to maintain a user's "state" and track their activity while they browse your site. - -CodeIgniter comes with a few session storage drivers, which you can see in the last section of the table of contents: - -.. contents:: - :local: - :depth: 2 - -Using the Session Class -*********************** - -Initializing a Session -====================== - -Sessions will typically run globally with each page load, so the Session class should be magically initialized. - -To access and initialize the session: - -.. literalinclude:: sessions/001.php - -The ``$config`` parameter is your application configuration, and is optional. If not provided, the services register -will instantiate your default one. - -Once loaded, the Sessions library object will be available using ``$session``. - -Alternatively, you can use the helper function that will use the default configuration options. This version is a little -friendlier to read, but does not take any configuration options. - -.. literalinclude:: sessions/002.php - -How Do Sessions Work? -===================== - -When a page is loaded, the session class will check to see if a valid session cookie is sent by the user's browser. If a -session cookie does **not** exist (or if it doesn't match one stored on the server or has expired), a new session will -be created and saved. - -If a valid session does exist, its information will be updated. With each update, the session ID may be regenerated if -configured to do so. - -It's important for you to understand that once initialized, the Session class runs automatically. There is nothing you -need to do to cause the above behavior to happen. You can, as you'll see below, work with session data, but the process -of reading, writing, and updating a session is automatic. - -.. note:: Under CLI, the Session library will automatically halt itself, as this is a concept based entirely on the HTTP - protocol. - -A Note about Concurrency ------------------------- - -Unless you're developing a website with heavy AJAX usage, you can skip this section. If you are, however, and if you're -experiencing performance issues, then this note is exactly what you're looking for. - -Sessions in CodeIgniter v2.x didn't implement locking, which meant that two HTTP requests using the same session could -run exactly at the same time. To use a more appropriate technical term: requests were non-blocking. - -However, non-blocking requests in the context of sessions are also unsafe, because modifications to session data (or -session ID regeneration) in one request can interfere with the execution of a second, concurrent request. This detail -was at the root of many issues and the main reason why CodeIgniter 3 has a completely rewritten Session library. - -Why are we telling you this? Because it is likely that after trying to find the reason for your performance issues, you -may conclude that locking is the issue and therefore look into how to remove the locks ... - -DO NOT DO THAT! Removing locks would be **wrong** and it will cause you more problems! - -Locking is not the issue. It is a solution. Your issue is that you still have the session open, while you've already -processed it and therefore no longer need it. So, what you need is to close the session for the current request after -you no longer need it. - -.. literalinclude:: sessions/003.php - -What is Session Data? -===================== - -Session data is simply an array associated with a particular session ID (cookie). - -If you've used sessions in PHP before, you should be familiar with PHP's -`$_SESSION superglobal `_ (if not, please read the content -on that link). - -CodeIgniter gives access to its session data through the same means, as it uses the session handlers' mechanism provided -by PHP. Using session data is as simple as manipulating (read, set and unset values) the ``$_SESSION`` array. - -.. note:: In general, it is bad practice to use global variables. So using the superglobal ``$_SESSION`` directly is not - recommended. - -In addition, CodeIgniter provides 2 special types of session data that are further explained below: `Flashdata`_ and -`Tempdata`_. - -.. note:: For historical reasons, we refer to session data excluding Flashdata and Tempdata as "userdata". - -Retrieving Session Data -======================= - -Any piece of information from the session array is available through the ``$_SESSION`` superglobal. For example, to -assign a previously stored ``name`` item to the ``$name`` variable, you will do this: - -.. literalinclude:: sessions/004.php - -Or through the conventional accessor method: - -.. literalinclude:: sessions/005.php - -Or through the magic getter: - -.. literalinclude:: sessions/006.php - -Or even through the session helper method: - -.. literalinclude:: sessions/007.php - -.. note:: The ``get()`` method returns null if the item you are trying to access does not exist. - -If you want to retrieve all of the existing session data, you can simply omit the item key (the magic getter only works -for single property values): - -.. literalinclude:: sessions/009.php - -.. important:: The ``get()`` method WILL return flashdata or tempdata items when retrieving a single item by key. It - will not return flashdata or tempdata when grabbing all data from the session, however. - -Adding Session Data -=================== - -Let's say a particular user logs into your site. Once authenticated, you could add their username and e-mail address to -the session, making that data globally available to you without having to run a database query when you need it. - -You can simply assign data to the ``$_SESSION`` array, as with any other variable, or as a property of ``$session``. - -You can pass an array containing your new session data to the ``set()`` method: - -.. literalinclude:: sessions/010.php - -Here, ``$array`` is an associative array containing your new data. Here's an example: - -.. literalinclude:: sessions/011.php - -If you want to add session data one value at a time, ``set()`` also supports this syntax: - -.. literalinclude:: sessions/012.php - -If you want to verify that a session value exists, simply check with ``isset()``: - -.. literalinclude:: sessions/013.php - -Or you can call ``has()``: - -.. literalinclude:: sessions/014.php - -Pushing New Value to Session Data -================================= - -The ``push()`` method is used to push a new value onto a session value that is an array. For instance, if the -``hobbies`` key contains an array of hobbies, you can add a new value or replace the previous value in the array like -so: - -.. literalinclude:: sessions/015.php - -Removing Session Data -===================== - -Just as with any other variable, unsetting a value in ``$_SESSION`` can be done through ``unset()``: - -.. literalinclude:: sessions/016.php - -Also, just as ``set()`` can be used to add information to a session, ``remove()`` can be used to remove it, by passing -the session key. For example, if you wanted to remove ``some_name`` from your session data array: - -.. literalinclude:: sessions/017.php - -This method also accepts an array of item keys to unset: - -.. literalinclude:: sessions/018.php - -.. _sessions-flashdata: - -Flashdata -========= - -CodeIgniter supports "flashdata", or session data that will only be available for the next request, and is then -automatically cleared. - -This can be very useful, especially for one-time informational, error or status messages (for example: "Record 2 -deleted"). - -It should be noted that flashdata variables are regular session variables, managed inside the CodeIgniter session -handler. - -To mark an existing item as "flashdata": - -.. literalinclude:: sessions/019.php - -If you want to mark multiple items as flashdata, simply pass the keys as an array: - -.. literalinclude:: sessions/020.php - -To add flashdata: - -.. literalinclude:: sessions/021.php - -Or alternatively, using the ``setFlashdata()`` method: - -.. literalinclude:: sessions/022.php - -You can also pass an array to ``setFlashdata()``, in the same manner as ``set()``. - -Reading flashdata variables is the same as reading regular session data through ``$_SESSION``: - -.. literalinclude:: sessions/023.php - -.. important:: The ``get()`` method WILL return flashdata items when retrieving a single item by key. It will not return - flashdata when grabbing all data from the session, however. - -However, if you want to be sure that you're reading "flashdata" (and not any other kind), you can also use the -``getFlashdata()`` method: - -.. literalinclude:: sessions/024.php - -.. note:: The ``getFlashdata()`` method returns null if the item cannot be found. - -Or to get an array with all flashdata, simply omit the key parameter: - -.. literalinclude:: sessions/025.php - - -If you find that you need to preserve a flashdata variable through an additional request, you can do so using the -``keepFlashdata()`` method. You can either pass a single item or an array of flashdata items to keep. - -.. literalinclude:: sessions/026.php - -Tempdata -======== - -CodeIgniter also supports "tempdata", or session data with a specific expiration time. After the value expires, or the -session expires or is deleted, the value is automatically removed. - -Similarly to flashdata, tempdata variables are managed internally by the CodeIgniter session handler. - -To mark an existing item as "tempdata", simply pass its key and expiry time (in seconds!) to the ``markAsTempdata()`` -method: - -.. literalinclude:: sessions/027.php - -You can mark multiple items as tempdata in two ways, depending on whether you want them all to have the same expiry time -or not: - -.. literalinclude:: sessions/028.php - -To add tempdata: - -.. literalinclude:: sessions/029.php - -Or alternatively, using the ``setTempdata()`` method: - -.. literalinclude:: sessions/030.php - -You can also pass an array to ``setTempdata()``: - -.. literalinclude:: sessions/031.php - -.. note:: If the expiration is omitted or set to 0, the default time-to-live value of 300 seconds (or 5 minutes) will be - used. - -To read a tempdata variable, again you can just access it through the ``$_SESSION`` superglobal array: - -.. literalinclude:: sessions/032.php - -.. important:: The ``get()`` method WILL return tempdata items when retrieving a single item by key. It will not return - tempdata when grabbing all data from the session, however. - -Or if you want to be sure that you're reading "tempdata" (and not any other kind), you can also use the -``getTempdata()`` method: - -.. literalinclude:: sessions/033.php - -.. note:: The ``getTempdata()`` method returns null if the item cannot be found. - -And of course, if you want to retrieve all existing tempdata: - -.. literalinclude:: sessions/034.php - -If you need to remove a tempdata value before it expires, you can directly unset it from the ``$_SESSION`` array: - -.. literalinclude:: sessions/035.php - -However, this won't remove the marker that makes this specific item tempdata (it will be invalidated on the next HTTP -request), so if you intend to reuse that same key in the same request, you'd want to use ``removeTempdata()``: - -.. literalinclude:: sessions/036.php - -Changing the Session Key Type -============================= - -Since session data values like Flashdata and Tempdata are differentiated only by internal flags, you can change a -value's type without rewriting its data. - -.. literalinclude:: sessions/045.php - -Closing a Session -================= - -.. _session-close: - -close() -------- - -.. versionadded:: 4.4.0 - -To close the current session manually after you no longer need it, use the ``close()`` method: - -.. literalinclude:: sessions/044.php - -You do not have to close the session manually. PHP will close it automatically after your script terminates. But as -session data is locked to prevent concurrent writes, only one request may operate on a session at any time. You may -improve your site performance by closing the session as soon as all changes to session data are done. - -This method will work in exactly the same way as PHP's -`session_write_close() `_ function. - -Destroying a Session -==================== - -.. _session-destroy: - -destroy() ---------- - -To clear the current session (for example, during a logout), you may simply use the library's ``destroy()`` method: - -.. literalinclude:: sessions/037.php - -This method will work in exactly the same way as PHP's `session_destroy() `_ -function. - -This must be the last session-related operation that you do during the same request. All session data (including -flashdata and tempdata) will be destroyed permanently. - -.. note:: You do not have to call this method from usual code. Clean up session data rather than destroying the session. - -Accessing Session Metadata -========================== - -In CodeIgniter 2, the session data array included 4 items by default: 'session_id', 'ip_address', 'user_agent', -'last_activity'. - -This was due to the specifics of how sessions worked, but is now no longer necessary with our new implementation. -However, it may happen that your application relied on these values, so here are alternative methods of accessing them: - - - session_id: ``$session->session_id`` or ``session_id()`` (PHP's built-in function) - - ip_address: ``$_SERVER['REMOTE_ADDR']`` - - user_agent: ``$_SERVER['HTTP_USER_AGENT']`` (unused by sessions) - - last_activity: Depends on the storage, no straightforward way. Sorry! - -Session Preferences -******************* - -CodeIgniter will usually make everything work out of the box. However, Sessions are a very sensitive component of any -application, so some careful configuration must be done. Please take your time to consider all of the options and their -effects. - -.. note:: Since v4.3.0, the new **app/Config/Session.php** has been added. Previously, the Session Preferences were in - your **app/Config/App.php** file. - -You'll find the following Session-related preferences in your **app/Config/Session.php** file: - -======================= ============================================ ================================================= ============================================================================================ -Preference Default Options Description -======================= ============================================ ================================================= ============================================================================================ -**driver** CodeIgniter\\Session\\Handlers\\FileHandler CodeIgniter\\Session\\Handlers\\FileHandler The session storage driver to use. - CodeIgniter\\Session\\Handlers\\DatabaseHandler - CodeIgniter\\Session\\Handlers\\MemcachedHandler - CodeIgniter\\Session\\Handlers\\RedisHandler - CodeIgniter\\Session\\Handlers\\ArrayHandler -**cookieName** ci_session [A-Za-z\_-] characters only The name used for the session cookie. -**expiration** 7200 (2 hours) Time in seconds (integer) The number of seconds you would like the session to last. - If you would like a non-expiring session (until browser is closed), set the value to zero: 0 -**savePath** WRITEPATH . 'session' None Specifies the storage location, which depends on the driver being used. -**matchIP** false true/false (boolean) Whether to validate the user's IP address when reading the session cookie. - Note that some ISPs dynamically change the IP, so if you want a non-expiring session you - will likely set this to false. -**timeToUpdate** 300 Time in seconds (integer) This option controls how often the session class will regenerate itself and create a new - session ID. Setting it to 0 will disable session ID regeneration. -**regenerateDestroy** false true/false (boolean) Whether to destroy session data associated with the old session ID when auto-regenerating - the session ID. When set to false, the data will be later deleted by the garbage collector. -======================= ============================================ ================================================= ============================================================================================ - -.. note:: As a last resort, the Session library will try to fetch PHP's session-related INI settings, as well as - CodeIgniter 3 settings such as 'sess_expire_on_close' when any of the above is not configured. However, you should - never rely on this behavior as it can cause unexpected results or be changed in the future. Please configure - everything properly. - -.. note:: If ``expiration`` is set to ``0``, the ``session.gc_maxlifetime`` setting set by PHP in session management - will be used as-is (often the default value of ``1440``). This needs to be changed in ``php.ini`` or via - ``ini_set()`` as needed. - -In addition to the values above, the Session cookie uses the following configuration values in your -**app/Config/Cookie.php** file: - -============== =============== =========================================================================== -Preference Default Description -============== =============== =========================================================================== -**domain** '' The domain for which the session is applicable -**path** / The path to which the session is applicable -**secure** false Whether to create the session cookie only on encrypted (HTTPS) connections -**sameSite** Lax The SameSite setting for the session cookie -============== =============== =========================================================================== - -.. note:: The ``httponly`` setting (in **app/Config/Cookie.php**) doesn't have an effect on sessions. Instead, the - HttpOnly parameter is always enabled, for security reasons. Additionally, the ``Config\Cookie::$prefix`` setting is - completely ignored. - -Session Drivers -*************** - -As already mentioned, the Session library comes with five handlers, or storage engines, that you can use: - - - CodeIgniter\\Session\\Handlers\\FileHandler - - CodeIgniter\\Session\\Handlers\\DatabaseHandler - - CodeIgniter\\Session\\Handlers\\MemcachedHandler - - CodeIgniter\\Session\\Handlers\\RedisHandler - - CodeIgniter\\Session\\Handlers\\ArrayHandler - -By default, the ``FileHandler`` will be used when a session is initialized, because it is the safest choice and is -expected to work everywhere (virtually every environment has a file system). - -However, any other driver may be selected via the ``$driver`` setting in your **app/Config/Session.php** file, if you -choose to do so. Keep in mind, though, that every driver has different caveats, so be sure to familiarize yourself with -them (below) before you make that choice. - -.. note:: The ArrayHandler is used during testing and stores all data within a PHP array, while preventing the data from - being persisted. See :doc:`Testing Sessions `. - -FileHandler Driver (the default) -================================ - -The 'FileHandler' driver uses your file system for storing session data. - -It can safely be said that it works exactly like PHP's own default session implementation, but in case this is an -important detail for you, in fact it is not the same code and it has some limitations (and advantages). - -To be more specific, it doesn't support PHP's -`directory level and mode formats used in session.save_path `_, -and it has most of the options hard-coded for safety. Instead, only absolute paths are supported with the ``$savePath`` -setting. - -Another important thing is to make sure that you don't use a publicly readable or shared directory for storing your -session files. *Only you* should have access to the contents of your chosen *savePath* directory. Otherwise, anybody can -see and steal session data, potentially enabling session hijacking. - -On UNIX-like operating systems, this is usually achieved by setting the 0700 mode permissions on that directory via the -``chmod`` command, which allows only the directory's owner to perform read and write operations on it. But be careful, -because the system user *running* the script is usually not your own, but something like 'www-data' instead, so only -setting those permissions will probably break your application. - -Instead, you should do something like this, depending on your environment: - -.. code-block:: console - - mkdir //writable/sessions/ - chmod 0700 //writable/sessions/ - chown www-data //writable/sessions/ - -The `built-in mechanism `_ for -automatically clearing expired sessions may not run often, and you will notice that the *savePath* directory may be -overflowing with files. To solve this problem, you will need to configure **cron** or **Task Scheduler** to delete -outdated files. - -Bonus Tip ---------- - -Some of you will probably choose another session driver because file storage is usually slower. This is only half true. - -A very basic test will probably trick you into believing that an SQL database is faster, but in 99% of the cases, this -is true only if you have a few current sessions. As the session count and server load increase - which is when it -matters - the file system will consistently outperform almost all relational database setups. - -In addition, if performance is your only concern, you may want to look into using -`tmpfs `_, which can make your -sessions blazing fast. - -.. _sessions-databasehandler-driver: - -DatabaseHandler Driver -====================== - -.. important:: Only MySQL and PostgreSQL databases are officially supported, due to lack of advisory locking mechanisms - on other platforms. Using sessions without locks can cause all sorts of problems, especially with heavy usage of - AJAX. Use the :ref:`session-close` method after you've finished processing session data if you're having performance - issues. - -The 'DatabaseHandler' driver uses a relational database such as MySQL or PostgreSQL to store sessions. This is a popular -choice among many users, because it allows the developer easy access to the session data within an application - it is -just another table in your database. - -However, there is a restriction: You can NOT use a persistent connection. - -Configure DatabaseHandler -------------------------- - -Setting Table Name -^^^^^^^^^^^^^^^^^^ - -In order to use the 'DatabaseHandler' session driver, you must also create this table that we already mentioned and then -set it as your ``$savePath`` value. For example, if you would like to use 'ci_sessions' as your table name, you would do -this: - -.. literalinclude:: sessions/039.php - -Creating Database Table -^^^^^^^^^^^^^^^^^^^^^^^ - -And then of course, create the database table. - -For MySQL:: - - CREATE TABLE IF NOT EXISTS `ci_sessions` ( - `id` varchar(128) NOT NULL, - `ip_address` varchar(45) NOT NULL, - `timestamp` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, - `data` blob NOT NULL, - KEY `ci_sessions_timestamp` (`timestamp`) - ); - -For PostgreSQL:: - - CREATE TABLE "ci_sessions" ( - "id" varchar(128) NOT NULL, - "ip_address" inet NOT NULL, - "timestamp" timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL, - "data" bytea DEFAULT '' NOT NULL - ); - - CREATE INDEX "ci_sessions_timestamp" ON "ci_sessions" ("timestamp"); - -.. note:: The ``id`` value contains the session cookie name (``Config\Session::$cookieName``), the session ID, and a - delimiter. Its size should be increased as needed, for example, when using long session IDs. - -Adding Primary Key -^^^^^^^^^^^^^^^^^^ - -You will also need to add a PRIMARY KEY **depending on your $matchIP setting**. The following statements work on both -MySQL and PostgreSQL:: - - -- When $matchIP = true - ALTER TABLE ci_sessions ADD PRIMARY KEY (id, ip_address); - - -- When $matchIP = false - ALTER TABLE ci_sessions ADD PRIMARY KEY (id); - -To drop a previously created primary key when changing the setting, use the appropriate statement for your database. - -For MySQL:: - - ALTER TABLE ci_sessions DROP PRIMARY KEY; - -For PostgreSQL, use the constraint name assigned when the primary key was created:: - - ALTER TABLE ci_sessions DROP CONSTRAINT ci_sessions_pkey; - -.. important:: If you don't add the correct primary key, the following error - may occur:: - - Uncaught mysqli_sql_exception: Duplicate entry 'ci_session:***' for key 'ci_sessions.PRIMARY' - -Changing Database Group -^^^^^^^^^^^^^^^^^^^^^^^ - -The default database group is used by default. You can change the database group to use by changing the ``$DBGroup`` -property in the **app/Config/Session.php** file to the name of the group to use: - -.. literalinclude:: sessions/040.php - -Setting Up Database Table with Command -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If you'd rather not do all of this by hand, you can use the ``make:migration --session`` command from the CLI to -generate a migration file for you: - -.. code-block:: console - - php spark make:migration --session - php spark migrate - -This command reads the ``$matchIP`` setting to decide the primary key. The table name and database group are not read -from **app/Config/Session.php**, so pass ``--table`` and ``--dbgroup`` when they differ from ``ci_sessions`` and -``default``: - -.. code-block:: console - - php spark make:migration --session --table my_sessions --dbgroup sessions - -The ``--table`` value should match ``$savePath``, and the ``--dbgroup`` value should match ``$DBGroup``. - -.. _sessions-redishandler-driver: - -RedisHandler Driver -=================== - -.. note:: Since Redis doesn't have a locking mechanism exposed, locks for this driver are emulated by a separate value - that is kept for up to 300 seconds. - -.. note:: Starting with v4.3.2, you can connect to Redis with the **TLS** protocol. - -Redis is a storage engine typically used for caching and popular because of its high performance, which is also probably -your reason to use the 'RedisHandler' session driver. - -The downside is that it is not as ubiquitous as relational databases and requires the -`phpredis `_ PHP extension to be installed on your system, and that one doesn't -come bundled with PHP. Chances are, you're using the RedisHandler driver only if you're already both familiar with Redis -and using it for other purposes. - -Configure RedisHandler ----------------------- - -Just as with the 'FileHandler' and 'DatabaseHandler' drivers, you must also configure the storage location for your -sessions via the ``$savePath`` setting. The format here is a bit different and complicated. It is best explained by the -*phpredis* extension's README file, so we'll simply give a link to it: - - https://github.com/phpredis/phpredis - -.. important:: CodeIgniter's Session library does NOT use the actual 'redis' ``session.save_handler``. Take note - **only** of the path format in the link above. - -For the most common case, however, a simple ``host:port`` pair should be sufficient: - -.. literalinclude:: sessions/041.php - -Starting with v4.5.0, you can use Redis ACL (username and password):: - - public string $savePath = 'tcp://localhost:6379?auth[user]=username&auth[pass]=password'; - -.. note:: Starting with v4.5.0, the interval time for acquiring locks (``$lockRetryInterval``) and the number of retries - (``$lockMaxRetries``) are configurable. - -.. _sessions-memcachedhandler-driver: - -MemcachedHandler Driver -======================= - -.. note:: Since Memcached doesn't have a locking mechanism exposed, locks for this driver are emulated by a separate - value that is kept for up to 300 seconds. - -The 'MemcachedHandler' driver is very similar to the 'RedisHandler' one in all of its properties, except perhaps for -availability, because PHP's `Memcached `_ extension is distributed via PECL and some -Linux distributions make it available as an easy-to-install package. - -Other than that, and without any intentional bias towards Redis, there's not much different to be said about Memcached - -it is also a popular product that is usually used for caching and famed for its speed. - -However, it is worth noting that the only guarantee given by Memcached is that setting value X to expire after Y seconds -will result in it being deleted after Y seconds have passed (but not necessarily that it won't expire earlier than that -time). This happens very rarely, but should be considered as it may result in loss of sessions. - -Configure MemcachedHandler --------------------------- - -The ``$savePath`` format is fairly straightforward here, being just a ``host:port`` pair: - -.. literalinclude:: sessions/042.php - -Bonus Tip ---------- - -Multi-server configuration with an optional *weight* parameter as the third colon-separated (``:weight``) value is also -supported, but we have to note that we haven't tested if that is reliable. - -If you want to experiment with this feature (at your own risk), simply separate the multiple server paths with commas: - -.. literalinclude:: sessions/043.php diff --git a/user_guide_src/source/libraries/sessions/001.php b/user_guide_src/source/libraries/sessions/001.php deleted file mode 100644 index f1f2159e16e0..000000000000 --- a/user_guide_src/source/libraries/sessions/001.php +++ /dev/null @@ -1,3 +0,0 @@ -close(); diff --git a/user_guide_src/source/libraries/sessions/004.php b/user_guide_src/source/libraries/sessions/004.php deleted file mode 100644 index 791a57f21ecf..000000000000 --- a/user_guide_src/source/libraries/sessions/004.php +++ /dev/null @@ -1,3 +0,0 @@ -get('name'); diff --git a/user_guide_src/source/libraries/sessions/006.php b/user_guide_src/source/libraries/sessions/006.php deleted file mode 100644 index 2e6c05c8e217..000000000000 --- a/user_guide_src/source/libraries/sessions/006.php +++ /dev/null @@ -1,3 +0,0 @@ -name; diff --git a/user_guide_src/source/libraries/sessions/007.php b/user_guide_src/source/libraries/sessions/007.php deleted file mode 100644 index 852220f692a0..000000000000 --- a/user_guide_src/source/libraries/sessions/007.php +++ /dev/null @@ -1,3 +0,0 @@ -get(); diff --git a/user_guide_src/source/libraries/sessions/010.php b/user_guide_src/source/libraries/sessions/010.php deleted file mode 100644 index b8b949797d22..000000000000 --- a/user_guide_src/source/libraries/sessions/010.php +++ /dev/null @@ -1,3 +0,0 @@ -set($array); diff --git a/user_guide_src/source/libraries/sessions/011.php b/user_guide_src/source/libraries/sessions/011.php deleted file mode 100644 index 01bbbe1670b0..000000000000 --- a/user_guide_src/source/libraries/sessions/011.php +++ /dev/null @@ -1,9 +0,0 @@ - 'johndoe', - 'email' => 'johndoe@some-site.com', - 'logged_in' => true, -]; - -$session->set($newdata); diff --git a/user_guide_src/source/libraries/sessions/012.php b/user_guide_src/source/libraries/sessions/012.php deleted file mode 100644 index 0d9c4699281a..000000000000 --- a/user_guide_src/source/libraries/sessions/012.php +++ /dev/null @@ -1,3 +0,0 @@ -set('some_name', 'some_value'); diff --git a/user_guide_src/source/libraries/sessions/013.php b/user_guide_src/source/libraries/sessions/013.php deleted file mode 100644 index 45bce58b5e06..000000000000 --- a/user_guide_src/source/libraries/sessions/013.php +++ /dev/null @@ -1,7 +0,0 @@ -has('some_name'); diff --git a/user_guide_src/source/libraries/sessions/015.php b/user_guide_src/source/libraries/sessions/015.php deleted file mode 100644 index c2ac72da85f8..000000000000 --- a/user_guide_src/source/libraries/sessions/015.php +++ /dev/null @@ -1,26 +0,0 @@ - Array - * ( - * [music] => rock - * [sport] => running - * ) - */ -$session->set('hobbies', [ - 'music' => 'rock', - 'sport' => 'running', -]); - -/** - * [hobbies] => Array - * ( - * [food] => cooking - * [music] => rock - * [sport] => tennis - * ) - */ -$session->push('hobbies', [ - 'food' => 'cooking', - 'sport' => 'tennis', -]); diff --git a/user_guide_src/source/libraries/sessions/016.php b/user_guide_src/source/libraries/sessions/016.php deleted file mode 100644 index 2b00df65a034..000000000000 --- a/user_guide_src/source/libraries/sessions/016.php +++ /dev/null @@ -1,8 +0,0 @@ -remove('some_name'); diff --git a/user_guide_src/source/libraries/sessions/018.php b/user_guide_src/source/libraries/sessions/018.php deleted file mode 100644 index 2ebd4f8a4e5f..000000000000 --- a/user_guide_src/source/libraries/sessions/018.php +++ /dev/null @@ -1,4 +0,0 @@ -remove($array_items); diff --git a/user_guide_src/source/libraries/sessions/019.php b/user_guide_src/source/libraries/sessions/019.php deleted file mode 100644 index 471c5c5fef96..000000000000 --- a/user_guide_src/source/libraries/sessions/019.php +++ /dev/null @@ -1,3 +0,0 @@ -markAsFlashdata('item'); diff --git a/user_guide_src/source/libraries/sessions/020.php b/user_guide_src/source/libraries/sessions/020.php deleted file mode 100644 index 4be42e7f3a62..000000000000 --- a/user_guide_src/source/libraries/sessions/020.php +++ /dev/null @@ -1,3 +0,0 @@ -markAsFlashdata(['item', 'item2']); diff --git a/user_guide_src/source/libraries/sessions/021.php b/user_guide_src/source/libraries/sessions/021.php deleted file mode 100644 index d87dd8763d34..000000000000 --- a/user_guide_src/source/libraries/sessions/021.php +++ /dev/null @@ -1,4 +0,0 @@ -markAsFlashdata('item'); diff --git a/user_guide_src/source/libraries/sessions/022.php b/user_guide_src/source/libraries/sessions/022.php deleted file mode 100644 index f22af522ab61..000000000000 --- a/user_guide_src/source/libraries/sessions/022.php +++ /dev/null @@ -1,3 +0,0 @@ -setFlashdata('item', 'value'); diff --git a/user_guide_src/source/libraries/sessions/023.php b/user_guide_src/source/libraries/sessions/023.php deleted file mode 100644 index ec1e40879798..000000000000 --- a/user_guide_src/source/libraries/sessions/023.php +++ /dev/null @@ -1,3 +0,0 @@ -getFlashdata('item'); diff --git a/user_guide_src/source/libraries/sessions/025.php b/user_guide_src/source/libraries/sessions/025.php deleted file mode 100644 index 7c387b5a4fa2..000000000000 --- a/user_guide_src/source/libraries/sessions/025.php +++ /dev/null @@ -1,3 +0,0 @@ -getFlashdata(); diff --git a/user_guide_src/source/libraries/sessions/026.php b/user_guide_src/source/libraries/sessions/026.php deleted file mode 100644 index 94a299006a5d..000000000000 --- a/user_guide_src/source/libraries/sessions/026.php +++ /dev/null @@ -1,4 +0,0 @@ -keepFlashdata('item'); -$session->keepFlashdata(['item1', 'item2', 'item3']); diff --git a/user_guide_src/source/libraries/sessions/027.php b/user_guide_src/source/libraries/sessions/027.php deleted file mode 100644 index d2ed461826c0..000000000000 --- a/user_guide_src/source/libraries/sessions/027.php +++ /dev/null @@ -1,4 +0,0 @@ -markAsTempdata('item', 300); diff --git a/user_guide_src/source/libraries/sessions/028.php b/user_guide_src/source/libraries/sessions/028.php deleted file mode 100644 index fd8d241ad069..000000000000 --- a/user_guide_src/source/libraries/sessions/028.php +++ /dev/null @@ -1,11 +0,0 @@ -markAsTempdata(['item', 'item2'], 300); - -// 'item' will be erased after 300 seconds, while 'item2' -// will do so after only 240 seconds -$session->markAsTempdata([ - 'item' => 300, - 'item2' => 240, -]); diff --git a/user_guide_src/source/libraries/sessions/029.php b/user_guide_src/source/libraries/sessions/029.php deleted file mode 100644 index d4e8941b5d34..000000000000 --- a/user_guide_src/source/libraries/sessions/029.php +++ /dev/null @@ -1,4 +0,0 @@ -markAsTempdata('item', 300); // Expire in 5 minutes diff --git a/user_guide_src/source/libraries/sessions/030.php b/user_guide_src/source/libraries/sessions/030.php deleted file mode 100644 index 444c045adae9..000000000000 --- a/user_guide_src/source/libraries/sessions/030.php +++ /dev/null @@ -1,3 +0,0 @@ -setTempdata('item', 'value', 300); diff --git a/user_guide_src/source/libraries/sessions/031.php b/user_guide_src/source/libraries/sessions/031.php deleted file mode 100644 index f7099d76289a..000000000000 --- a/user_guide_src/source/libraries/sessions/031.php +++ /dev/null @@ -1,4 +0,0 @@ - true, 'message' => 'Thanks for joining!']; -$session->setTempdata($tempdata, null, $expire); diff --git a/user_guide_src/source/libraries/sessions/032.php b/user_guide_src/source/libraries/sessions/032.php deleted file mode 100644 index ec1e40879798..000000000000 --- a/user_guide_src/source/libraries/sessions/032.php +++ /dev/null @@ -1,3 +0,0 @@ -getTempdata('item'); diff --git a/user_guide_src/source/libraries/sessions/034.php b/user_guide_src/source/libraries/sessions/034.php deleted file mode 100644 index f44b959eee81..000000000000 --- a/user_guide_src/source/libraries/sessions/034.php +++ /dev/null @@ -1,3 +0,0 @@ -getTempdata(); diff --git a/user_guide_src/source/libraries/sessions/035.php b/user_guide_src/source/libraries/sessions/035.php deleted file mode 100644 index f063fa2907f4..000000000000 --- a/user_guide_src/source/libraries/sessions/035.php +++ /dev/null @@ -1,3 +0,0 @@ -removeTempdata('item'); diff --git a/user_guide_src/source/libraries/sessions/037.php b/user_guide_src/source/libraries/sessions/037.php deleted file mode 100644 index 9f474a3c7d31..000000000000 --- a/user_guide_src/source/libraries/sessions/037.php +++ /dev/null @@ -1,3 +0,0 @@ -destroy(); diff --git a/user_guide_src/source/libraries/sessions/039.php b/user_guide_src/source/libraries/sessions/039.php deleted file mode 100644 index 45f2c4ce4272..000000000000 --- a/user_guide_src/source/libraries/sessions/039.php +++ /dev/null @@ -1,17 +0,0 @@ -close(); diff --git a/user_guide_src/source/libraries/sessions/045.php b/user_guide_src/source/libraries/sessions/045.php deleted file mode 100644 index b9327e133172..000000000000 --- a/user_guide_src/source/libraries/sessions/045.php +++ /dev/null @@ -1,25 +0,0 @@ -setFlashdata('alerts', 'Operation successful!'); - -/* - * Get flash value 'Operation successful!' in another controller. - * - * echo session()->getFlashdata('alerts'); - */ - -// You can switch the session key type from Flashdata to Tempdata like this: -session()->markAsTempdata('alerts'); - -// Or simply rewrite it directly -session()->setTempdata('alerts', 'Operation successful!'); - -/* - * Get temp value 'Operation successful!' in another controller. - * - * echo session()->getTempdata('alerts'); - * - * But flash value will be empty 'null'. - * - * echo session()->getFlashdata('alerts'); - */ diff --git a/user_guide_src/source/libraries/throttler.rst b/user_guide_src/source/libraries/throttler.rst deleted file mode 100644 index 7da7dbd307c0..000000000000 --- a/user_guide_src/source/libraries/throttler.rst +++ /dev/null @@ -1,109 +0,0 @@ -######### -Throttler -######### - -.. contents:: - :local: - :depth: 2 - -The Throttler class provides a very simple way to limit an activity to a certain number of attempts within a set period -of time. This is most often used for performing rate limiting on APIs, or restricting the number of attempts a user can -make against a form to help prevent brute force attacks. The class itself can be used for anything that you need to -throttle based on actions within a set time interval. - -******** -Overview -******** - -The Throttler implements a simplified version of the `Token Bucket `_ -algorithm. This basically treats each action that you want to limit as a bucket. When you call the ``check()`` method, -you tell it how large the bucket is (how many tokens it can hold) and the time interval. By default, each ``check()`` -call uses 1 of the available tokens. Let's walk through an example to make this clear. - -Let's say we want an action to happen once every second. The first call to the Throttler would look like the following. -The first parameter is the bucket name, the second parameter the number of tokens the bucket holds, and the third the -amount of time it takes the bucket to refill: - -.. literalinclude:: throttler/001.php - -Here we're using one of the :doc:`global constants ` for the time, to make it a little more -readable. This says that the bucket allows 60 actions every minute, or 1 action every second. - -Let's say that a third-party script was trying to hit a URL repeatedly. At first, it would be able to use all 60 of -those tokens in less than a second. However, after that the Throttler would only allow one action per second, -potentially slowing down the requests enough that the attack is no longer worth it. - -.. note:: For the Throttler class to work, the Cache library must be set up to use a handler other than dummy. For best - performance, an in-memory cache, like Redis or Memcached, is recommended. - -************* -Rate Limiting -************* - -The Throttler class does not do any rate limiting or request throttling on its own, but it is the key to making it work. -An example :doc:`Filter ` is provided that implements very simple rate limiting at one request per -second per IP address. Here we will run through how it works, and how you could set it up and start using it in your -application. - -The Code -======== - -You could make your own Throttler filter, at **app/Filters/Throttle.php**, along the lines of: - -.. literalinclude:: throttler/002.php - -When run, this method first grabs an instance of the throttler. Next, it uses the IP address as the bucket name, and -sets the limit to one request per second. If the throttler rejects the check, returning false, then we return a Response -with the status code set to 429 - Too Many Requests, and the script execution ends before it ever hits the controller. -This example will throttle based on a single IP address across all requests made to the site, not per page. - -Applying the Filter -=================== - -We don't necessarily need to throttle every page on the site. For many web applications, it makes the most sense to -apply this only to POST requests, though APIs might want to limit every request made by a user. In order to apply this -to incoming requests, you need to edit **app/Config/Filters.php** and first add an alias to the filter: - -.. literalinclude:: throttler/003.php - -Next, we assign it to all POST requests made on the site: - -.. literalinclude:: throttler/004.php - -.. Warning:: If you use ``$methods`` filters, you should :ref:`disable Auto Routing (Legacy) ` - because :ref:`auto-routing-legacy` permits any HTTP method to access a controller. Accessing the controller with a - method you don't expect could bypass the filter. - -And that's all there is to it. Now all POST requests made on the site will be rate limited. - -*************** -Class Reference -*************** - -.. php:method:: check(string $key, int $capacity, int $seconds[, int $cost = 1]) - - :param string $key: The name of the bucket - :param int $capacity: The number of tokens the bucket holds - :param int $seconds: The number of seconds it takes for a bucket to completely fill - :param int $cost: The number of tokens that are spent on this action - :returns: true if the action can be performed, false if not - :rtype: bool - - Checks to see if there are any tokens left within the bucket, or if too many have been used within the allotted time - limit. During each check the available tokens are reduced by ``$cost`` if successful. - -.. php:method:: getTokenTime() - - :returns: The number of seconds until another token should be available. - :rtype: integer - - After ``check()`` has been run and returned false, this method can be used to determine the time until a new token - should be available and the action can be tried again. In this case, the minimum enforced wait time is one second. - -.. php:method:: remove(string $key) : self - - :param string $key: The name of the bucket - :returns: ``$this`` - :rtype: self - - Removes & resets the bucket. Won't fail if the bucket doesn't exist. diff --git a/user_guide_src/source/libraries/throttler/001.php b/user_guide_src/source/libraries/throttler/001.php deleted file mode 100644 index 8b3cc13038aa..000000000000 --- a/user_guide_src/source/libraries/throttler/001.php +++ /dev/null @@ -1,4 +0,0 @@ -check($name, 60, MINUTE); diff --git a/user_guide_src/source/libraries/throttler/002.php b/user_guide_src/source/libraries/throttler/002.php deleted file mode 100644 index 9e3fec98c963..000000000000 --- a/user_guide_src/source/libraries/throttler/002.php +++ /dev/null @@ -1,41 +0,0 @@ -|null $arguments - * - * @return ResponseInterface|void - */ - public function before(RequestInterface $request, $arguments = null) - { - $throttler = service('throttler'); - - // Restrict an IP address to no more than 1 request - // per second across the entire site. - if ($throttler->check(md5($request->getIPAddress()), 60, MINUTE) === false) { - return service('response')->setStatusCode(429); - } - } - - /** - * We don't have anything to do here. - * - * @param list|null $arguments - * - * @return void - */ - public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) - { - // ... - } -} diff --git a/user_guide_src/source/libraries/throttler/003.php b/user_guide_src/source/libraries/throttler/003.php deleted file mode 100644 index b365df88fa53..000000000000 --- a/user_guide_src/source/libraries/throttler/003.php +++ /dev/null @@ -1,15 +0,0 @@ - \App\Filters\Throttle::class, - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/throttler/004.php b/user_guide_src/source/libraries/throttler/004.php deleted file mode 100644 index 246b034d035e..000000000000 --- a/user_guide_src/source/libraries/throttler/004.php +++ /dev/null @@ -1,14 +0,0 @@ - ['throttle'], - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst deleted file mode 100644 index af466742f1db..000000000000 --- a/user_guide_src/source/libraries/time.rst +++ /dev/null @@ -1,473 +0,0 @@ -############### -Times and Dates -############### - -CodeIgniter provides a fully localized, immutable date/time class that is built on PHP's DateTimeImmutable class, but -uses the Intl extension's features to convert times across timezones and display the output correctly for different -locales. This class is the ``Time`` class and lives in the ``CodeIgniter\I18n`` namespace. - -.. note:: Since the Time class extends ``DateTimeImmutable``, if there are features that you need that this class - doesn't provide, you can likely find them within the `DateTimeImmutable`_ class itself. - -.. _DateTimeImmutable: https://www.php.net/manual/en/class.datetimeimmutable.php - -.. note:: Prior to v4.3.0, the Time class extended ``DateTime`` and some inherited methods changed the current object - state. The bug was fixed in v4.3.0. If you need the old Time class for backward compatibility, you can use the - deprecated ``TimeLegacy`` class for the time being. - -.. contents:: - :local: - :depth: 2 - -************* -Instantiating -************* - -There are several ways that a new Time instance can be created. The first is simply to create a new instance like any -other class. - -When you do it this way, you can pass in a string representing the desired time. This can be any string that PHP's -`DateTimeImmutable`_ constructor can parse. See `Supported Date and Time Formats`_ for details. - -.. _Supported Date and Time Formats: https://www.php.net/manual/en/datetime.formats.php - -.. literalinclude:: time/001.php - -You can pass in strings representing the timezone and the locale in the second and the third parameters, respectively. -The timezone can be any one supported by PHP's `DateTimeZone `__ class. The -locale can be any one supported by PHP's `Locale `__ class. If no locale -or timezone is provided, the application defaults will be used. - -.. literalinclude:: time/002.php - -now() -===== - -The Time class has several helper methods to instantiate the class. The first of these is the ``now()`` method that -returns a new instance set to the current time. You can pass in strings representing the timezone and locale in the -first and second parameters, respectively. If no locale or timezone is provided, the application defaults will be used. - -.. literalinclude:: time/003.php - -parse() -======= - -This helper method is a static version of the default constructor. It takes a string acceptable as DateTimeImmutable's -constructor as the first parameter, a timezone as the second parameter, and the locale as the third parameter: - -.. literalinclude:: time/004.php - -today() -======= - -Returns a new instance with the date set to the current date, and the time set to midnight. It accepts strings for the -timezone and locale in the first and second parameters: - -.. literalinclude:: time/005.php - -yesterday() -=========== - -Returns a new instance with the date set to yesterday's date and the time set to midnight. It accepts strings for the -timezone and locale in the first and second parameters: - -.. literalinclude:: time/006.php - -tomorrow() -========== - -Returns a new instance with the date set to tomorrow's date and the time set to midnight. It accepts strings for the -timezone and locale in the first and second parameters: - -.. literalinclude:: time/007.php - -createFromDate() -================ - -Given separate inputs for **year**, **month**, and **day**, it will return a new instance. If any of these parameters -are not provided, it will use the current year, month and day. Accepts strings for the timezone and locale in the fourth -and fifth parameters: - -.. literalinclude:: time/008.php - -createFromTime() -================ - -Like ``createFromDate()``, except it is only concerned with the **hours**, **minutes**, and **seconds**. Uses the -current day for the date portion of the Time instance. Accepts strings for the timezone and locale in the fourth and -fifth parameters: - -.. literalinclude:: time/009.php - -create() -======== - -A combination of the previous two methods, this takes **year**, **month**, **day**, **hour**, **minutes**, and -**seconds** as separate parameters. Any value not provided will use the current date and time. Accepts strings for the -timezone and locale in the seventh and eighth parameters: - -.. literalinclude:: time/010.php - -createFromFormat() -================== - -This is a replacement for DateTimeImmutable's method of the same name. This allows the timezone to be set at the same -time, and returns a ``Time`` instance, instead of DateTimeImmutable: - -.. literalinclude:: time/011.php - -.. _time-createfromtimestamp: - -createFromTimestamp() -===================== - -This method takes a UNIX timestamp and, optionally, the timezone and locale, to create a new Time instance: - -.. literalinclude:: time/012.php - -If you do not explicitly pass a timezone, it returns a Time instance with **UTC**. - -.. note:: We recommend always calling ``createFromTimestamp()`` with 2 parameters (i.e. explicitly pass a timezone) - unless using UTC as the default timezone. - -.. note:: From v4.4.6 up to, but not including, v4.6.0, this method returned a Time instance with the default timezone - when no timezone was specified. - -createFromInstance() -==================== - -When working with other libraries that provide a DateTime instance, you can use this method to convert that to a Time -instance, optionally setting the locale. The timezone will be automatically determined from the DateTime instance passed -in: - -.. literalinclude:: time/013.php - -toDateTime() -============ - -While not an instantiator, this method is the opposite of the ``createFromInstance()`` method, allowing you to convert a -Time instance into a DateTime instance. This preserves the timezone setting, but loses the locale, since DateTime is not -aware of locales: - -.. literalinclude:: time/014.php - - -******************** -Displaying the Value -******************** - -Since the Time class extends DateTimeImmutable, you get all of the output methods that it provides, including the -``format()`` method. However, the DateTimeImmutable methods do not provide a localized result. The Time class does -provide a number of helper methods to display localized versions of the value, though. - -toLocalizedString() -=================== - -This is the localized version of DateTimeImmutable's ``format()`` method. Instead of using the values you might be -familiar with, though, you must use values acceptable to the -`IntlDateFormatter `__ class. A full listing of values can be -found `here `__. - -.. literalinclude:: time/015.php - -.. _time-todatetimestring: - -toDateTimeString() -================== - -This is the first of three helper methods to work with the -`IntlDateFormatter `_ without having to remember their -values. This will return a localized version of a string formatted as ``Y-m-d H:i:s``: - -.. literalinclude:: time/016.php - -toDateString() -============== - -Displays just the localized date portion of the Time: - -.. literalinclude:: time/017.php - -toTimeString() -============== - -Displays just the localized time portion of the value: - -.. literalinclude:: time/018.php - -humanize() -========== - -This method returns a string that displays the difference between the current date/time and the instance in a -human-readable format that is geared towards being easily understood. It can create strings like '3 hours ago', 'in 1 -month', etc.: - -.. literalinclude:: time/019.php - -The exact time displayed is determined in the following manner: - -=============================== ================================= -Time difference Result -=============================== ================================= -1 year < $time < 2 years in 1 year / 1 year ago -1 month < $time < 1 year in 6 months / 6 months ago -7 days < $time < 1 month in 3 weeks / 3 weeks ago -today < $time < 7 days in 4 days / 4 days ago -$time == yesterday / tomorrow Yesterday / Tomorrow -59 minutes < $time < 1 day in 2 hours / 2 hours ago -now < $time < 1 hour in 35 minutes / 35 minutes ago -$time == now Now -=============================== ================================= - -The result strings come from the language file, **system/Language/en/Time.php**. If you want to overwrite them, create -**app/Language/{locale}/Time.php**. - -****************************** -Working with Individual Values -****************************** - -The Time object provides a number of methods that allow you to get and set individual items, like the year, month, hour, -etc., of an existing instance. All of the values retrieved through the following methods will be fully localized and -respect the locale that the Time instance was created with. - -All of the following ``getX()`` and ``setX()`` methods can also be used as if they were class properties. So, methods -like ``getYear()`` can also be accessed through ``$time->year``, and so on. - -Getters -======= - -The following basic getters exist: - -.. literalinclude:: time/020.php - -In addition to these, a number of methods exist to provide additional information about the date: - -.. literalinclude:: time/021.php - -getAge() --------- - -Returns the age, in years, between the Time instance and the current time. Perfect for checking the age of someone based -on their birthday: - -.. literalinclude:: time/022.php - -getDST() --------- - -Returns boolean true/false based on whether the Time instance is currently observing Daylight Saving Time: - -.. literalinclude:: time/023.php - -getLocal() ----------- - -Returns boolean true if the Time instance is in the same timezone as the application is currently running in: - -.. literalinclude:: time/024.php - -getUtc() --------- - -Returns boolean true if the Time instance is in UTC time: - -.. literalinclude:: time/025.php - -getTimezone() -------------- - -Returns a new `DateTimeZone `__ object set to the timezone of the -Time instance: - -.. literalinclude:: time/026.php - -getTimezoneName() ------------------ - -Returns the full `timezone string `__ of the Time instance: - -.. literalinclude:: time/027.php - -Setters -======= - -The following basic setters exist. If any of the values set are out of range, an ``InvalidArgumentException`` will be -thrown. - -.. note:: All setters will return a new Time instance, leaving the original instance untouched. - -.. note:: All setters will throw an InvalidArgumentException if the value is out of range. - -.. literalinclude:: time/028.php - -setTimezone() -------------- - -Converts the time from its current timezone into the new one: - -.. literalinclude:: time/029.php - -setTimestamp() --------------- - -Returns a new instance with the date set to the new timestamp: - -.. literalinclude:: time/030.php - -.. note:: Prior to v4.6.0, due to a bug, this method might return an incorrect date/time. See - :ref:`Upgrading Guide ` for details. - -Modifying the Value -=================== - -The following methods allow you to modify the date by adding values to or subtracting values from the current Time. This -will not modify the existing Time instance, but will return a new instance. - -.. literalinclude:: time/031.php - -addCalendarMonths() / subCalendarMonths() ------------------------------------------ - -Modifies the current Time by adding or subtracting whole calendar months. These methods can be useful if you require -that no calendar months be skipped in recurring dates. Refer to the table below for a comparison between ``addMonths()`` -and ``addCalendarMonths()`` for an initial date of ``2025-01-31``. - -======= =========== =================== -$months addMonths() addCalendarMonths() -======= =========== =================== -1 2025-03-03 2025-02-28 -2 2025-03-31 2025-03-31 -3 2025-05-01 2025-04-30 -4 2025-05-31 2025-05-31 -5 2025-07-01 2025-06-30 -6 2025-07-31 2025-07-31 -======= =========== =================== - -Comparing Two Times -=================== - -The following methods allow you to compare one Time instance with another. All comparisons are first converted to UTC -before comparisons are done, to ensure that different timezones respond correctly. - -equals() --------- - -Determines if the datetime passed in is equal to the current instance. Equal in this case means that they represent the -same moment in time, and are not required to be in the same timezone, as both times are converted to UTC and compared -that way: - -.. literalinclude:: time/032.php - -The value being tested against can be a Time instance, a DateTime instance, or a string with the full date time in a -manner that a new DateTime instance can understand. When passing a string as the first parameter, you can pass a -timezone string in as the second parameter. If no timezone is given, the system default will be used: - -.. literalinclude:: time/033.php - -sameAs() --------- - -This is identical to the ``equals()`` method, except that it only returns true when the date, time, AND timezone are all -identical: - -.. literalinclude:: time/034.php - -isBefore() ----------- - -Checks if the current instance is before the passed-in time. The comparison is done against the UTC versions of both -times: - -.. literalinclude:: time/035.php - -The value being tested against can be a Time instance, a DateTime instance, or a string with the full date time in a -manner that a new DateTime instance can understand. When passing a string as the first parameter, you can pass a -timezone string in as the second parameter. If no timezone is given, the system default will be used: - -.. literalinclude:: time/036.php - -isAfter() ---------- - -Works exactly the same as ``isBefore()``, except that it checks if the time is after the time passed in: - -.. literalinclude:: time/037.php - -.. _time-comparing-two-times-isPast: - -isPast() --------- - -.. versionadded:: 4.7.0 - -Determines if the current instance's time is in the past, relative to "now". It returns a boolean true/false: - -.. literalinclude:: time/043.php - -.. _time-comparing-two-times-isFuture: - -isFuture() ----------- - -.. versionadded:: 4.7.0 - -Determines if the current instance's time is in the future, relative to "now". It returns a boolean true/false: - -.. literalinclude:: time/044.php - -.. _time-viewing-differences: - -Viewing Differences -=================== - -To compare two Times directly, you would use the ``difference()`` method, which returns a -``CodeIgniter\I18n\TimeDifference`` instance. - -The first parameter is either a Time instance, a DateTime instance, or a string with the date/time. If a string is -passed in the first parameter, the second parameter can be a timezone string: - -.. literalinclude:: time/038.php - -Once you have the TimeDifference instance, you have several methods you can use to find information about the difference -between the two times. The value returned will be negative if it was in the past, or positive if in the future from the -original time: - -.. literalinclude:: time/039.php - -.. note:: Prior to v4.4.7, Time always converted the time zones to UTC before comparison. This could lead to unexpected - results when the compared period contained a day that differed from 24 hours due to Daylight Saving Time (DST). - - Starting with v4.4.7, when comparing date/times that are in the same time zone, the comparison is performed as is, - without conversion to UTC. - - .. literalinclude:: time/042.php - -You can use either the ``getX()`` methods, or access the calculated values as if they were properties: - -.. literalinclude:: time/040.php - -humanize() ----------- - -Much like Time's ``humanize()`` method, this returns a string that displays the difference between the times in a -human-readable format that is geared towards being easily understood. It can create strings like '3 hours ago', 'in 1 -month', etc. The biggest difference is in how very recent dates are handled: - -.. literalinclude:: time/041.php - -The exact time displayed is determined in the following manner: - -=============================== ================================= -Time difference Result -=============================== ================================= -1 year < $time < 2 years in 1 year / 1 year ago -1 month < $time < 1 year in 6 months / 6 months ago -7 days < $time < 1 month in 3 weeks / 3 weeks ago -today < $time < 7 days in 4 days / 4 days ago -1 hour < $time < 1 day in 8 hours / 8 hours ago -1 minute < $time < 1 hour in 35 minutes / 35 minutes ago -$time < 1 minute Now -=============================== ================================= - -The result strings come from the language file, **system/Language/en/Time.php**. If you want to overwrite them, create -**app/Language/{locale}/Time.php**. diff --git a/user_guide_src/source/libraries/time/001.php b/user_guide_src/source/libraries/time/001.php deleted file mode 100644 index ccaf074129ad..000000000000 --- a/user_guide_src/source/libraries/time/001.php +++ /dev/null @@ -1,8 +0,0 @@ -toLocalizedString('MMM d, yyyy'); // March 9, 2016 - -// Locale: fa -$time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); -echo $time->toLocalizedString('MMM d, yyyy'); // مارس ۹, ۲۰۱۶ diff --git a/user_guide_src/source/libraries/time/016.php b/user_guide_src/source/libraries/time/016.php deleted file mode 100644 index fe67508a4743..000000000000 --- a/user_guide_src/source/libraries/time/016.php +++ /dev/null @@ -1,11 +0,0 @@ -toDateTimeString(); // 2016-03-09 12:00:00 - -// Locale: fa -$time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); -echo $time->toDateTimeString(); // ۲۰۱۶-۰۳-۰۹ ۱۲:۰۰:۰۰ diff --git a/user_guide_src/source/libraries/time/017.php b/user_guide_src/source/libraries/time/017.php deleted file mode 100644 index 6047929bd310..000000000000 --- a/user_guide_src/source/libraries/time/017.php +++ /dev/null @@ -1,11 +0,0 @@ -toDateString(); // 2016-03-09 - -// Locale: fa -$time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); -echo $time->toDateString(); // ۲۰۱۶-۰۳-۰۹ diff --git a/user_guide_src/source/libraries/time/018.php b/user_guide_src/source/libraries/time/018.php deleted file mode 100644 index b53dd96999c3..000000000000 --- a/user_guide_src/source/libraries/time/018.php +++ /dev/null @@ -1,11 +0,0 @@ -toTimeString(); // 12:00:00 - -// Locale: fa -$time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); -echo $time->toTimeString(); // ۱۲:۰۰:۰۰ diff --git a/user_guide_src/source/libraries/time/019.php b/user_guide_src/source/libraries/time/019.php deleted file mode 100644 index cc355921289d..000000000000 --- a/user_guide_src/source/libraries/time/019.php +++ /dev/null @@ -1,8 +0,0 @@ -humanize(); // 1 year ago diff --git a/user_guide_src/source/libraries/time/020.php b/user_guide_src/source/libraries/time/020.php deleted file mode 100644 index a35758a4343f..000000000000 --- a/user_guide_src/source/libraries/time/020.php +++ /dev/null @@ -1,20 +0,0 @@ -getYear(); // '2016' -echo $time->getMonth(); // '8' -echo $time->getDay(); // '12' -echo $time->getHour(); // '16' -echo $time->getMinute(); // '15' -echo $time->getSecond(); // '23' - -echo $time->year; // '2016' -echo $time->month; // '8' -echo $time->day; // '12' -echo $time->hour; // '16' -echo $time->minute; // '15' -echo $time->second; // '23' diff --git a/user_guide_src/source/libraries/time/021.php b/user_guide_src/source/libraries/time/021.php deleted file mode 100644 index fb384942c7f7..000000000000 --- a/user_guide_src/source/libraries/time/021.php +++ /dev/null @@ -1,20 +0,0 @@ -getDayOfWeek(); // '6' -echo $time->getDayOfYear(); // '225' -echo $time->getWeekOfMonth(); // '2' -echo $time->getWeekOfYear(); // '33' -echo $time->getTimestamp(); // 1471018523 - UNIX timestamp (locale independent) -echo $time->getQuarter(); // '3' - -echo $time->dayOfWeek; // '6' -echo $time->dayOfYear; // '225' -echo $time->weekOfMonth; // '2' -echo $time->weekOfYear; // '33' -echo $time->timestamp; // 1471018523 -echo $time->quarter; // '3' diff --git a/user_guide_src/source/libraries/time/022.php b/user_guide_src/source/libraries/time/022.php deleted file mode 100644 index deda59e0b0c3..000000000000 --- a/user_guide_src/source/libraries/time/022.php +++ /dev/null @@ -1,8 +0,0 @@ -getAge(); // 5 -echo $time->age; // 5 diff --git a/user_guide_src/source/libraries/time/023.php b/user_guide_src/source/libraries/time/023.php deleted file mode 100644 index 9f0b0803eda4..000000000000 --- a/user_guide_src/source/libraries/time/023.php +++ /dev/null @@ -1,6 +0,0 @@ -getDst(); // false -echo Time::createFromDate(2012, 9, 1)->dst; // true diff --git a/user_guide_src/source/libraries/time/024.php b/user_guide_src/source/libraries/time/024.php deleted file mode 100644 index ab73eb62cb0b..000000000000 --- a/user_guide_src/source/libraries/time/024.php +++ /dev/null @@ -1,6 +0,0 @@ -getLocal(); // true -echo Time::now('Europe/London')->local; // false diff --git a/user_guide_src/source/libraries/time/025.php b/user_guide_src/source/libraries/time/025.php deleted file mode 100644 index 50b14fdc507f..000000000000 --- a/user_guide_src/source/libraries/time/025.php +++ /dev/null @@ -1,6 +0,0 @@ -getUtc(); // false -echo Time::now('UTC')->utc; // true diff --git a/user_guide_src/source/libraries/time/026.php b/user_guide_src/source/libraries/time/026.php deleted file mode 100644 index 2aff6825c8fd..000000000000 --- a/user_guide_src/source/libraries/time/026.php +++ /dev/null @@ -1,9 +0,0 @@ -getTimezone(); -$tz = Time::now()->timezone; - -echo $tz->getName(); -echo $tz->getOffset(); diff --git a/user_guide_src/source/libraries/time/027.php b/user_guide_src/source/libraries/time/027.php deleted file mode 100644 index 666bbd2798e2..000000000000 --- a/user_guide_src/source/libraries/time/027.php +++ /dev/null @@ -1,6 +0,0 @@ -getTimezoneName(); // America/Chicago -echo Time::now('Europe/London')->timezoneName; // Europe/London diff --git a/user_guide_src/source/libraries/time/028.php b/user_guide_src/source/libraries/time/028.php deleted file mode 100644 index 97a3c26764d3..000000000000 --- a/user_guide_src/source/libraries/time/028.php +++ /dev/null @@ -1,10 +0,0 @@ -setYear(2017); -$time = $time->setMonth(4); // April -$time = $time->setMonth('April'); -$time = $time->setMonth('Feb'); // February -$time = $time->setDay(25); -$time = $time->setHour(14); // 2:00 pm -$time = $time->setMinute(30); -$time = $time->setSecond(54); diff --git a/user_guide_src/source/libraries/time/029.php b/user_guide_src/source/libraries/time/029.php deleted file mode 100644 index fbff5ab5fe98..000000000000 --- a/user_guide_src/source/libraries/time/029.php +++ /dev/null @@ -1,12 +0,0 @@ -setTimezone('Europe/London'); // Returns new instance converted to new timezone - -echo $time->getTimezoneName(); // American/Chicago -echo $time2->getTimezoneName(); // Europe/London - -echo $time->toDateTimeString(); // 2020-05-13 10:00:00 -echo $time2->toDateTimeString(); // 2020-05-13 18:00:00 diff --git a/user_guide_src/source/libraries/time/030.php b/user_guide_src/source/libraries/time/030.php deleted file mode 100644 index 5ca37d326925..000000000000 --- a/user_guide_src/source/libraries/time/030.php +++ /dev/null @@ -1,11 +0,0 @@ -setTimestamp(strtotime('April 1, 2017')); - -echo $time->toDateTimeString(); // 2017-05-10 00:00:00 -echo $time2->toDateTimeString(); // 2017-04-01 00:00:00 diff --git a/user_guide_src/source/libraries/time/031.php b/user_guide_src/source/libraries/time/031.php deleted file mode 100644 index 914ff279871d..000000000000 --- a/user_guide_src/source/libraries/time/031.php +++ /dev/null @@ -1,17 +0,0 @@ -addSeconds(23); -$time = $time->addMinutes(15); -$time = $time->addHours(12); -$time = $time->addDays(21); -$time = $time->addMonths(14); -$time = $time->addCalendarMonths(2); -$time = $time->addYears(5); - -$time = $time->subSeconds(23); -$time = $time->subMinutes(15); -$time = $time->subHours(12); -$time = $time->subDays(21); -$time = $time->subMonths(14); -$time = $time->subCalendarMonths(2); -$time = $time->subYears(5); diff --git a/user_guide_src/source/libraries/time/032.php b/user_guide_src/source/libraries/time/032.php deleted file mode 100644 index ce6490e3243a..000000000000 --- a/user_guide_src/source/libraries/time/032.php +++ /dev/null @@ -1,8 +0,0 @@ -equals($time2); // true diff --git a/user_guide_src/source/libraries/time/033.php b/user_guide_src/source/libraries/time/033.php deleted file mode 100644 index 73962921a299..000000000000 --- a/user_guide_src/source/libraries/time/033.php +++ /dev/null @@ -1,3 +0,0 @@ -equals('January 11, 2017 03:50:00', 'Europe/London'); // true diff --git a/user_guide_src/source/libraries/time/034.php b/user_guide_src/source/libraries/time/034.php deleted file mode 100644 index bf14f31ebada..000000000000 --- a/user_guide_src/source/libraries/time/034.php +++ /dev/null @@ -1,9 +0,0 @@ -sameAs($time2); // false -$time2->sameAs('January 10, 2017 21:50:00', 'America/Chicago'); // true diff --git a/user_guide_src/source/libraries/time/035.php b/user_guide_src/source/libraries/time/035.php deleted file mode 100644 index 5b31605a00e7..000000000000 --- a/user_guide_src/source/libraries/time/035.php +++ /dev/null @@ -1,9 +0,0 @@ -isBefore($time2); // true -$time2->isBefore($time1); // false diff --git a/user_guide_src/source/libraries/time/036.php b/user_guide_src/source/libraries/time/036.php deleted file mode 100644 index 817f31e4dce8..000000000000 --- a/user_guide_src/source/libraries/time/036.php +++ /dev/null @@ -1,3 +0,0 @@ -isBefore('March 15, 2013', 'America/Chicago'); // false diff --git a/user_guide_src/source/libraries/time/037.php b/user_guide_src/source/libraries/time/037.php deleted file mode 100644 index cb6abda7f960..000000000000 --- a/user_guide_src/source/libraries/time/037.php +++ /dev/null @@ -1,9 +0,0 @@ -isAfter($time2); // false -$time2->isAfter($time1); // true diff --git a/user_guide_src/source/libraries/time/038.php b/user_guide_src/source/libraries/time/038.php deleted file mode 100644 index 4ada6f1ea0c7..000000000000 --- a/user_guide_src/source/libraries/time/038.php +++ /dev/null @@ -1,9 +0,0 @@ -difference(Time::now()); -$diff = $time->difference(new \DateTime('July 4, 1975', 'America/Chicago')); -$diff = $time->difference('July 4, 1975 13:32:05', 'America/Chicago'); diff --git a/user_guide_src/source/libraries/time/039.php b/user_guide_src/source/libraries/time/039.php deleted file mode 100644 index 9c31042b668b..000000000000 --- a/user_guide_src/source/libraries/time/039.php +++ /dev/null @@ -1,16 +0,0 @@ -difference($test); - -echo $diff->getYears(); // -7 -echo $diff->getMonths(); // -84 -echo $diff->getWeeks(); // -365 -echo $diff->getDays(); // -2557 -echo $diff->getHours(); // -61368 -echo $diff->getMinutes(); // -3682080 -echo $diff->getSeconds(); // -220924800 diff --git a/user_guide_src/source/libraries/time/040.php b/user_guide_src/source/libraries/time/040.php deleted file mode 100644 index 1af52b88fd75..000000000000 --- a/user_guide_src/source/libraries/time/040.php +++ /dev/null @@ -1,9 +0,0 @@ -years; // -7 -echo $diff->months; // -84 -echo $diff->weeks; // -365 -echo $diff->days; // -2557 -echo $diff->hours; // -61368 -echo $diff->minutes; // -3682080 -echo $diff->seconds; // -220924800 diff --git a/user_guide_src/source/libraries/time/041.php b/user_guide_src/source/libraries/time/041.php deleted file mode 100644 index 8e97fe3bbb26..000000000000 --- a/user_guide_src/source/libraries/time/041.php +++ /dev/null @@ -1,10 +0,0 @@ -difference($test); - -echo $diff->humanize(); // 1 year ago diff --git a/user_guide_src/source/libraries/time/042.php b/user_guide_src/source/libraries/time/042.php deleted file mode 100644 index 6f2c77498e6f..000000000000 --- a/user_guide_src/source/libraries/time/042.php +++ /dev/null @@ -1,13 +0,0 @@ -difference($test); - -echo $diff->getDays(); -// 0 in v4.4.6 or before -// 1 in v4.4.7 or later diff --git a/user_guide_src/source/libraries/time/043.php b/user_guide_src/source/libraries/time/043.php deleted file mode 100644 index b256fff3ddce..000000000000 --- a/user_guide_src/source/libraries/time/043.php +++ /dev/null @@ -1,6 +0,0 @@ -isPast(); // true diff --git a/user_guide_src/source/libraries/time/044.php b/user_guide_src/source/libraries/time/044.php deleted file mode 100644 index d8cc511065c7..000000000000 --- a/user_guide_src/source/libraries/time/044.php +++ /dev/null @@ -1,6 +0,0 @@ -isFuture(); // true diff --git a/user_guide_src/source/libraries/typography.rst b/user_guide_src/source/libraries/typography.rst deleted file mode 100644 index 2e3037005c0c..000000000000 --- a/user_guide_src/source/libraries/typography.rst +++ /dev/null @@ -1,67 +0,0 @@ -########## -Typography -########## - -The Typography library contains methods that help you format text in semantically relevant ways. - -.. contents:: - :local: - :depth: 2 - -******************* -Loading the Library -******************* - -Like all services in CodeIgniter, it can be loaded via ``Config\Services``, though you usually will not need to load it -manually: - -.. literalinclude:: typography/001.php - -************************** -Available Instance Methods -************************** - -The following functions are available: - -.. php:method:: autoTypography($str[, $reduceLinebreaks = false]) - - :param string $str: Input string - :param bool $reduceLinebreaks: Whether to reduce multiple instances of double newlines to two - :returns: HTML-formatted typography-safe string - :rtype: string - - Formats text so that it is semantically and typographically correct HTML. - - Usage example: - - .. literalinclude:: typography/002.php - - .. note:: Typographic formatting can be processor-intensive, particularly if you have a lot of content being - formatted. If you choose to use this function, you may want to consider :doc:`caching <../general/caching>` your - pages. - -.. php:method:: formatCharacters($str) - - :param string $str: Input string - :returns: String with formatted characters. - :rtype: string - - This function mainly converts double and single quotes to curly entities, but it also converts em-dashes, double - spaces, and ampersands. - - Usage example: - - .. literalinclude:: typography/003.php - -.. php:method:: nl2brExceptPre($str) - - :param string $str: Input string - :returns: String with HTML-formatted line breaks - :rtype: string - - Converts newlines to ``
`` tags unless they appear within ``
`` tags. This function is identical to the
-    native PHP ``nl2br()`` function, except that it ignores ``
`` tags.
-
-    Usage example:
-
-    .. literalinclude:: typography/004.php
diff --git a/user_guide_src/source/libraries/typography/001.php b/user_guide_src/source/libraries/typography/001.php
deleted file mode 100644
index 9685611c7691..000000000000
--- a/user_guide_src/source/libraries/typography/001.php
+++ /dev/null
@@ -1,3 +0,0 @@
-autoTypography($string);
diff --git a/user_guide_src/source/libraries/typography/003.php b/user_guide_src/source/libraries/typography/003.php
deleted file mode 100644
index 1c2d51a9afdd..000000000000
--- a/user_guide_src/source/libraries/typography/003.php
+++ /dev/null
@@ -1,3 +0,0 @@
-formatCharacters($string);
diff --git a/user_guide_src/source/libraries/typography/004.php b/user_guide_src/source/libraries/typography/004.php
deleted file mode 100644
index 3d5b4347aafc..000000000000
--- a/user_guide_src/source/libraries/typography/004.php
+++ /dev/null
@@ -1,3 +0,0 @@
-nl2brExceptPre($string);
diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst
deleted file mode 100644
index 879553aac273..000000000000
--- a/user_guide_src/source/libraries/uploaded_files.rst
+++ /dev/null
@@ -1,411 +0,0 @@
-###########################
-Working with Uploaded Files
-###########################
-
-CodeIgniter makes working with files uploaded through a form much simpler and more secure than using PHP's ``$_FILES``
-array directly. The UploadedFile class extends the :doc:`File class ` and thus gains all of the
-features of that class.
-
-.. note:: This is not the same as the File Uploading class in CodeIgniter 3. This provides a raw interface to the
-    uploaded files with a few small features.
-
-.. contents::
-    :local:
-    :depth: 2
-
-.. _file-upload-form-tutorial:
-
-*************************
-File Upload Form Tutorial
-*************************
-
-Uploading a file involves the following general process:
-
-- An upload form is displayed, allowing a user to select a file and upload it.
-- When the form is submitted, the file is uploaded to the destination you specify.
-- Along the way, the file is validated to make sure it is allowed to be uploaded based on the preferences you set.
-- Once uploaded, the user will be shown a success message.
-
-To demonstrate this process, here is a brief tutorial. Afterward, you'll find reference information.
-
-Creating the Upload Form
-========================
-
-Using a text editor, create a form called **upload_form.php**. In it, place this code and save it to your **app/Views**
-directory:
-
-.. literalinclude:: uploaded_files/001.php
-
-You'll notice we are using a form helper to create the opening form tag. File uploads require a multipart form, so the
-helper creates the proper syntax for you.
-
-You'll also notice we have an ``$errors`` variable. This is so we can show error messages in the event the user does
-something wrong.
-
-The Success Page
-================
-
-Using a text editor, create a form called **upload_success.php**. In it, place this code and save it to your
-**app/Views** directory::
-
-    
-    
-    
-        Upload Form
-    
-    
-
-    

Your file was successfully uploaded!

- -
    -
  • name: getBasename()) ?>
  • -
  • size: getSizeByBinaryUnit(\CodeIgniter\Files\FileSizeUnit::KB)) ?> KB
  • -
  • extension: guessExtension()) ?>
  • -
- -

- - - - -The Controller -============== - -Using a text editor, create a controller called **Upload.php**. In it, place this code and save it to your -**app/Controllers** directory: - -.. literalinclude:: uploaded_files/002.php - -Only the :ref:`rules-for-file-uploads` can be used to validate uploaded files. - -Therefore, the rule ``required`` cannot be used either, so if the file is required, use the rule ``uploaded`` instead. - -Note that an empty array (``[]``) is passed as the first argument to ``$this->validateData()``. This is because the file -validation rules get the data for the uploaded file directly from the Request object. - -If the form has fields other than the file upload, pass the field data as the first argument. - -The Routes -========== - -Using a text editor, open **app/Config/Routes.php**. In it, add the following two routes: - -.. literalinclude:: uploaded_files/021.php - -The Upload Directory -==================== - -The uploaded files are stored in the **writable/uploads/** directory. - -Try it! -======= - -To try your form, visit your site using a URL similar to this one:: - - example.com/index.php/upload/ - -You should see an upload form. Try uploading an image file (either a **jpg**, **gif**, **png**, or **webp**). If the -path in your controller is correct, it should work. - -.. _uploaded-files-accessing-files: - -*************** -Accessing Files -*************** - -All Files -========= - -When you upload files, they can be accessed natively in PHP through the ``$_FILES`` superglobal. This array has some -major shortcomings when working with multiple files uploaded at once, and has potential security flaws many developers -are not aware of. CodeIgniter helps with both of these situations by standardizing your usage of files behind a common -interface. - -Files are accessed through the current ``IncomingRequest`` instance. To retrieve all files that were uploaded with this -request, use ``getFiles()``. This will return an array of files represented by instances of -``CodeIgniter\HTTP\Files\UploadedFile``: - -.. literalinclude:: uploaded_files/003.php - -Of course, there are multiple ways to name the file input, and anything but the simplest can create strange results. The -array is returned in a manner that you would expect. With the simplest usage, a single file might be submitted like:: - - - -This would return a simple array like:: - - [ - 'avatar' => // UploadedFile instance, - ]; - -.. note:: The UploadedFile instance corresponds to ``$_FILES``. Even if a user just clicks the submit button and does - not upload any file, the instance will still exist. You can check that the file was actually uploaded with the - ``isValid()`` method in UploadedFile. See :ref:`verify-a-file`. - -If you used array notation for the name, the input would look something like:: - - - -The array returned by ``getFiles()`` would look more like this:: - - [ - 'my-form' => [ - 'details' => [ - 'avatar' => // UploadedFile instance - ], - ], - ] - - -In some cases, you may specify an array of files to upload:: - - Upload an avatar: - Upload an avatar: - -In this case, the returned array of files would be more like:: - - [ - 'my-form' => [ - 'details' => [ - 'avatars' => [ - 0 => // UploadedFile instance, - 1 => // UploadedFile instance, - ], - ], - ], - ] - -Single File -=========== - -If you just need to access a single file, you can use ``getFile()`` to retrieve the file instance directly. This will -return an instance of ``CodeIgniter\HTTP\Files\UploadedFile``. - -Simplest usage --------------- - -With the simplest usage, a single file might be submitted like:: - - - -This would return a simple file instance like: - -.. literalinclude:: uploaded_files/004.php - -Array notation --------------- - -If you used array notation for the name, the input would look something like:: - - - -To get the file instance: - -.. literalinclude:: uploaded_files/005.php - -Multiple files -============== - -:: - - - -In the controller: - -.. literalinclude:: uploaded_files/006.php - -Here, ``images`` is a loop from the form field name. - -If there are multiple files with the same name, you can use ``getFile()`` to retrieve every file individually. - -In the controller: - -.. literalinclude:: uploaded_files/007.php - -You might find it easier to use ``getFileMultiple()`` to get an array of uploaded files with the same name: - -.. literalinclude:: uploaded_files/008.php - -Another example:: - - Upload an avatar: - Upload an avatar: - -In the controller: - -.. literalinclude:: uploaded_files/009.php - -.. note:: Using ``getFiles()`` is more appropriate. - -********************* -Working with the File -********************* - -Once you've retrieved the UploadedFile instance, you can get information about the file in safe ways, as well as move -the file to a new location. - -.. _verify-a-file: - -Verify a File -============= - -You can check that a file was actually uploaded via HTTP with no errors by calling the ``isValid()`` method: - -.. literalinclude:: uploaded_files/010.php - -As seen in this example, if a file had an upload error, you can retrieve the error code (an integer) and the error -message with the ``getError()`` and ``getErrorString()`` methods. The following errors can be discovered through this -method: - -* The file exceeds your ``upload_max_filesize`` ini directive. -* The file exceeds the upload limit defined in your form. -* The file was only partially uploaded. -* No file was uploaded. -* The file could not be written on disk. -* File could not be uploaded: missing temporary directory. -* File upload was stopped by a PHP extension. - -File Names -========== - -getName() ---------- - -You can retrieve the original filename provided by the client with the ``getName()`` method. This will typically be the -filename sent by the client, and should not be trusted. If the file has been moved, this will return the final name of -the moved file: - -.. literalinclude:: uploaded_files/011.php - -getClientName() ---------------- - -Always returns the original name of the uploaded file as sent by the client, even if the file has been moved: - -.. literalinclude:: uploaded_files/012.php - -getTempName() -------------- - -To get the full path of the temp file that was created during the upload, you can use the ``getTempName()`` method: - -.. literalinclude:: uploaded_files/013.php - -Other File Info -=============== - -getClientExtension() --------------------- - -Returns the original file extension, based on the file name that was uploaded: - -.. literalinclude:: uploaded_files/014.php - -.. warning:: This is NOT a trusted source. For a trusted version, use ``guessExtension()`` instead. - -getClientMimeType() -------------------- - -Returns the mime type of the file as provided by the client. This is NOT a trusted value. For a trusted version, use -``getMimeType()`` instead: - -.. literalinclude:: uploaded_files/015.php - -getClientPath() ---------------- - -.. versionadded:: 4.4.0 - -Returns the `webkit relative path `_ of the -uploaded file when the client has uploaded files via directory upload. In PHP versions below 8.1, this returns ``null``. - -.. literalinclude:: uploaded_files/023.php - -.. _uploaded-files-moving-files: - -Moving Files -============ - -.. warning:: - Do not let user input directly decide the destination directory. The ``$targetPath`` argument of ``move()`` and the - ``$folderName`` argument of ``store()`` are never sanitized, so an attacker-controlled value containing ``../`` can - move the uploaded file outside the intended directory. Use directories controlled by your application. - - Filenames are only sanitized by default: ``move()`` sanitizes the client-provided name when the ``$name`` argument - is omitted, and ``store()`` generates a random name when ``$fileName`` is omitted. A caller-supplied ``$name`` or - ``$fileName`` is NOT sanitized, so if you pass one, generate it yourself or sanitize it with - :php:func:`sanitize_filename`. - - Sanitizing a client-provided filename does not make it safe to keep in a web-accessible directory where scripts can - execute. Some web servers select a handler from any extension in a filename, including an extension before the final - one. Keep uploads outside the public directory with ``store()`` when possible. If they must be public, disable - script execution in the upload directory and pass ``$file->getRandomName()`` as the second argument to ``move()``. - -with Original Filename ----------------------- - -Each file can be moved to its new location with the aptly named ``move()`` method. This takes the directory to move the -file to as the first parameter: - -.. literalinclude:: uploaded_files/016.php - -By default, the client-provided filename is sanitized and used. - -with New Filename ------------------ - -You can specify a new filename by passing it as the second parameter: - -.. literalinclude:: uploaded_files/017.php - -Overwriting Existing File -------------------------- - -By default, if the destination file already exists, a new filename will be used. For example, if **image_name.jpg** -already exists in the directory, then the filename will be **image_name_1.jpg** automatically. - -You can overwrite the existing file by passing ``true`` as the third parameter: - -.. literalinclude:: uploaded_files/022.php - -Check if the File Moved ------------------------ - -Once the file has been moved, the temporary file is deleted. You can check if a file has been moved already with the -``hasMoved()`` method, which returns a boolean: - -.. literalinclude:: uploaded_files/018.php - -When Moving Fails ------------------ - -Moving an uploaded file can fail, with an ``HTTPException``, under several circumstances: - -- the file has already been moved -- the file did not upload successfully -- the file move operation fails (e.g., improper permissions) - -Store Files -=========== - -Each file can be moved to its new location with the aptly named ``store()`` method. - -With the simplest usage, a single file might be submitted like:: - - - -By default, uploaded files are saved in the **writable/uploads** directory. A **YYYYMMDD** folder and a random file name -will be created. The method returns a file path: - -.. literalinclude:: uploaded_files/019.php - -You can specify a directory to move the file to as the first parameter, and a new filename by passing it as the second -parameter: - -.. literalinclude:: uploaded_files/020.php - -Moving an uploaded file can fail, with an ``HTTPException``, under several circumstances: - -- the file has already been moved -- the file did not upload successfully -- the file move operation fails (e.g., improper permissions) diff --git a/user_guide_src/source/libraries/uploaded_files/001.php b/user_guide_src/source/libraries/uploaded_files/001.php deleted file mode 100644 index f6f2e95c29cf..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/001.php +++ /dev/null @@ -1,19 +0,0 @@ - - - - Upload Form - - - - -
  • - - - - -

    - - - - - diff --git a/user_guide_src/source/libraries/uploaded_files/002.php b/user_guide_src/source/libraries/uploaded_files/002.php deleted file mode 100644 index af304c239186..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/002.php +++ /dev/null @@ -1,50 +0,0 @@ - []]); - } - - public function upload() - { - $validationRule = [ - 'userfile' => [ - 'label' => 'Image File', - 'rules' => [ - 'uploaded[userfile]', - 'is_image[userfile]', - 'mime_in[userfile,image/jpg,image/jpeg,image/gif,image/png,image/webp]', - 'max_size[userfile,100]', - 'max_dims[userfile,1024,768]', - ], - ], - ]; - if (! $this->validateData([], $validationRule)) { - $data = ['errors' => $this->validator->getErrors()]; - - return view('upload_form', $data); - } - - $img = $this->request->getFile('userfile'); - - if (! $img->hasMoved()) { - $filepath = WRITEPATH . 'uploads/' . $img->store(); - - $data = ['uploaded_fileinfo' => new File($filepath)]; - - return view('upload_success', $data); - } - - $data = ['errors' => 'The file has already been moved.']; - - return view('upload_form', $data); - } -} diff --git a/user_guide_src/source/libraries/uploaded_files/003.php b/user_guide_src/source/libraries/uploaded_files/003.php deleted file mode 100644 index 17141efbdde8..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/003.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getFiles(); diff --git a/user_guide_src/source/libraries/uploaded_files/004.php b/user_guide_src/source/libraries/uploaded_files/004.php deleted file mode 100644 index e5f6440d96fb..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/004.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getFile('userfile'); diff --git a/user_guide_src/source/libraries/uploaded_files/005.php b/user_guide_src/source/libraries/uploaded_files/005.php deleted file mode 100644 index ad71bd5575fb..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/005.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getFile('my-form.details.avatar'); diff --git a/user_guide_src/source/libraries/uploaded_files/006.php b/user_guide_src/source/libraries/uploaded_files/006.php deleted file mode 100644 index f0be5ba1aafb..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/006.php +++ /dev/null @@ -1,10 +0,0 @@ -request->getFiles()) { - foreach ($imagefile['images'] as $img) { - if ($img->isValid() && ! $img->hasMoved()) { - $newName = $img->getRandomName(); - $img->move(WRITEPATH . 'uploads', $newName); - } - } -} diff --git a/user_guide_src/source/libraries/uploaded_files/007.php b/user_guide_src/source/libraries/uploaded_files/007.php deleted file mode 100644 index da51d17dbd15..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/007.php +++ /dev/null @@ -1,4 +0,0 @@ -request->getFile('images.0'); -$file2 = $this->request->getFile('images.1'); diff --git a/user_guide_src/source/libraries/uploaded_files/008.php b/user_guide_src/source/libraries/uploaded_files/008.php deleted file mode 100644 index 646e6bb0b8b9..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/008.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getFileMultiple('images'); diff --git a/user_guide_src/source/libraries/uploaded_files/009.php b/user_guide_src/source/libraries/uploaded_files/009.php deleted file mode 100644 index d18a755ba234..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/009.php +++ /dev/null @@ -1,4 +0,0 @@ -request->getFile('my-form.details.avatars.0'); -$file2 = $this->request->getFile('my-form.details.avatars.1'); diff --git a/user_guide_src/source/libraries/uploaded_files/010.php b/user_guide_src/source/libraries/uploaded_files/010.php deleted file mode 100644 index 094ea73c1064..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/010.php +++ /dev/null @@ -1,5 +0,0 @@ -isValid()) { - throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')'); -} diff --git a/user_guide_src/source/libraries/uploaded_files/011.php b/user_guide_src/source/libraries/uploaded_files/011.php deleted file mode 100644 index 057a56b3e9a0..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/011.php +++ /dev/null @@ -1,3 +0,0 @@ -getName(); diff --git a/user_guide_src/source/libraries/uploaded_files/012.php b/user_guide_src/source/libraries/uploaded_files/012.php deleted file mode 100644 index 4fb0cae0ad12..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/012.php +++ /dev/null @@ -1,3 +0,0 @@ -getClientName(); diff --git a/user_guide_src/source/libraries/uploaded_files/013.php b/user_guide_src/source/libraries/uploaded_files/013.php deleted file mode 100644 index c9e4774a4bbf..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/013.php +++ /dev/null @@ -1,3 +0,0 @@ -getTempName(); diff --git a/user_guide_src/source/libraries/uploaded_files/014.php b/user_guide_src/source/libraries/uploaded_files/014.php deleted file mode 100644 index 867877238c76..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/014.php +++ /dev/null @@ -1,3 +0,0 @@ -getClientExtension(); diff --git a/user_guide_src/source/libraries/uploaded_files/015.php b/user_guide_src/source/libraries/uploaded_files/015.php deleted file mode 100644 index dd1288e441c3..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/015.php +++ /dev/null @@ -1,5 +0,0 @@ -getClientMimeType(); - -echo $type; // image/png diff --git a/user_guide_src/source/libraries/uploaded_files/016.php b/user_guide_src/source/libraries/uploaded_files/016.php deleted file mode 100644 index 12499a3ca1ba..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/016.php +++ /dev/null @@ -1,3 +0,0 @@ -move(WRITEPATH . 'uploads'); diff --git a/user_guide_src/source/libraries/uploaded_files/017.php b/user_guide_src/source/libraries/uploaded_files/017.php deleted file mode 100644 index 2e6b39645a4b..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/017.php +++ /dev/null @@ -1,4 +0,0 @@ -getRandomName(); -$file->move(WRITEPATH . 'uploads', $newName); diff --git a/user_guide_src/source/libraries/uploaded_files/018.php b/user_guide_src/source/libraries/uploaded_files/018.php deleted file mode 100644 index 7f49d1f5232e..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/018.php +++ /dev/null @@ -1,5 +0,0 @@ -isValid() && ! $file->hasMoved()) { - $file->move($path); -} diff --git a/user_guide_src/source/libraries/uploaded_files/019.php b/user_guide_src/source/libraries/uploaded_files/019.php deleted file mode 100644 index 90f9495eaf7b..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/019.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getFile('userfile')->store(); diff --git a/user_guide_src/source/libraries/uploaded_files/020.php b/user_guide_src/source/libraries/uploaded_files/020.php deleted file mode 100644 index 0e552f417d52..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/020.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getFile('userfile')->store('head_img/', 'user_name.jpg'); diff --git a/user_guide_src/source/libraries/uploaded_files/021.php b/user_guide_src/source/libraries/uploaded_files/021.php deleted file mode 100644 index c7cfcddc76f7..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/021.php +++ /dev/null @@ -1,18 +0,0 @@ -get('/', 'Home::index'); - -$routes->get('upload', 'Upload::index'); // Add this line. -$routes->post('upload/upload', 'Upload::upload'); // Add this line. - -// ... diff --git a/user_guide_src/source/libraries/uploaded_files/022.php b/user_guide_src/source/libraries/uploaded_files/022.php deleted file mode 100644 index e834acba3d23..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/022.php +++ /dev/null @@ -1,3 +0,0 @@ -move(WRITEPATH . 'uploads', null, true); diff --git a/user_guide_src/source/libraries/uploaded_files/023.php b/user_guide_src/source/libraries/uploaded_files/023.php deleted file mode 100644 index f8accc9087b1..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/023.php +++ /dev/null @@ -1,4 +0,0 @@ -getClientPath(); -echo $clientPath; // dir/file.txt, or dir/sub_dir/file.txt diff --git a/user_guide_src/source/libraries/uri.rst b/user_guide_src/source/libraries/uri.rst deleted file mode 100644 index 9ef3ecf8e026..000000000000 --- a/user_guide_src/source/libraries/uri.rst +++ /dev/null @@ -1,253 +0,0 @@ -***************** -Working with URIs -***************** - -CodeIgniter provides an object-oriented solution for working with URIs in your application. Using this makes it simple -to ensure that the structure is always correct, no matter how complex the URI might be, as well as to add a relative URI -to an existing one and have it resolved safely and correctly. - -.. contents:: - :local: - :depth: 2 - -====================== -Creating URI instances -====================== - -Creating a URI instance is as simple as creating a new class instance. - -When you create the new instance, you can pass a full or partial URL in the constructor and it will be parsed into its -appropriate sections: - -.. literalinclude:: uri/001.php - :lines: 2- - -Alternatively, you can use the :php:func:`service()` function to return an instance for you: - -.. literalinclude:: uri/003.php - :lines: 2- - -Since v4.4.0, if you don't pass a URL, it returns the current URI: - -.. literalinclude:: uri/002.php - :lines: 2- - -.. note:: The above code returns a ``SiteURI`` instance, which extends the ``URI`` class. The ``URI`` class is for - general URIs, but the ``SiteURI`` class is for your site URIs. - -The Current URI ---------------- - -When you need an object representing the current URL of the request, you can use the :php:func:`current_url()` function -available in the :doc:`../helpers/url_helper`: - -.. literalinclude:: uri/004.php - :lines: 2- - -You must pass ``true`` as the first parameter. Otherwise, it will return the string representation of the current URL. - -This URI is based on the path (relative to your ``baseURL``) as determined by the current request object and your -settings in ``Config\App`` (``baseURL``, ``indexPage``, and ``forceGlobalSecureRequests``). - -Assuming that you're in a controller that extends ``CodeIgniter\Controller``, you can also get the current SiteURI -instance: - -.. literalinclude:: uri/005.php - :lines: 2- - -=========== -URI Strings -=========== - -Many times, all you really want is to get a string representation of a URI. This is easy to do by simply casting the URI -as a string: - -.. literalinclude:: uri/006.php - -If you know the pieces of the URI and just want to ensure it's all formatted correctly, you can generate a string using -the URI class' static ``createURIString()`` method: - -.. literalinclude:: uri/007.php - -.. important:: When ``URI`` is cast to a string, it will attempt to adjust project URLs to the settings defined in - ``Config\App``. If you need the exact, unaltered string representation then use ``URI::createURIString()`` instead. - -============= -The URI Parts -============= - -Once you have a URI instance, you can set or retrieve any of the various parts of the URI. This section will provide -details on what those parts are, and how to work with them. - -Scheme ------- - -The scheme is frequently 'http' or 'https', but any scheme is supported, including 'file', 'mailto', etc. - -.. literalinclude:: uri/008.php - -Authority ---------- - -Many URIs contain several elements that are collectively known as the 'authority'. This includes any user info, the host -and the port number. You can retrieve all of these pieces as one single string with the ``getAuthority()`` method, or -you can manipulate the individual parts. - -.. literalinclude:: uri/009.php - -By default, this will not display the password portion since you wouldn't want to show that to anyone. If you want to -show the password, you can use the ``showPassword()`` method. This URI instance will continue to show that password -until you turn it off again, so always make sure that you turn it off as soon as you are finished with it: - -.. literalinclude:: uri/010.php - -If you do not want to display the port, pass in ``true`` as the only parameter: - -.. literalinclude:: uri/011.php - -.. note:: If the current port is the default port for the scheme, it will never be displayed. - -UserInfo --------- - -The userinfo section is simply the username and password that you might see with an FTP URI. While you can get this as -part of the Authority, you can also retrieve it yourself: - -.. literalinclude:: uri/012.php - -By default, it will not display the password, but you can override that with the ``showPassword()`` method: - -.. literalinclude:: uri/013.php - -Host ----- - -The host portion of the URI is typically the domain name of the URL. This can be easily set and retrieved with the -``getHost()`` and ``setHost()`` methods: - -.. literalinclude:: uri/014.php - -Port ----- - -The port is an integer between 0 and 65535. Each scheme has a default value associated with it. - -.. literalinclude:: uri/015.php - -When using the ``setPort()`` method, the port will be checked to ensure that it is within the valid range, and then -assigned. - -Path ----- - -The path is all of the segments within the site itself. As expected, the ``getPath()`` and ``setPath()`` methods can be -used to manipulate it: - -.. literalinclude:: uri/016.php - -.. note:: When the path is set, it is sanitized to encode any dangerous characters and remove dot segments for safety. - -.. note:: Since v4.4.0, the ``SiteURI::getRoutePath()`` method returns the URI path relative to baseURL, and the - ``SiteURI::getPath()`` method always returns the full URI path with leading ``/``. - -Query ------ - -The query data can be manipulated through the class using simple string representations. - -Getting/Setting Query -^^^^^^^^^^^^^^^^^^^^^ - -Query values can only be set as a string currently. - -.. literalinclude:: uri/017.php - -The ``setQuery()`` method overwrites existing query variables. - -.. note:: Query values cannot contain fragments. An InvalidArgumentException will be thrown if they do. - -Setting Query from Array -^^^^^^^^^^^^^^^^^^^^^^^^ - -You can set query values using an array: - -.. literalinclude:: uri/018.php - -The ``setQueryArray()`` method overwrites existing query variables. - -Adding Query Value -^^^^^^^^^^^^^^^^^^ - -You can add a value to the query variables collection without destroying the existing query variables with the -``addQuery()`` method. The first parameter is the name of the variable, and the second parameter is the value: - -.. literalinclude:: uri/019.php - -Filtering Query Values -^^^^^^^^^^^^^^^^^^^^^^ - -You can filter the query values returned by passing an options array to the ``getQuery()`` method, with either an *only* -or an *except* key: - -.. literalinclude:: uri/020.php - -This only changes the values returned during this one call. - -Changing Query Values -^^^^^^^^^^^^^^^^^^^^^ - -If you need to modify the URI's query values more permanently, you can use the ``stripQuery()`` and ``keepQuery()`` -methods to change the actual object's query variable collection: - -.. literalinclude:: uri/021.php - -.. note:: By default, the ``setQuery()`` and ``setQueryArray()`` methods use the native ``parse_str()`` function to - prepare data. If you want to use more liberal rules (which allow key names to contain dots), you can use a special - method ``useRawQueryString()`` beforehand. - -Fragment --------- - -Fragments are the portion at the end of the URL, preceded by the pound sign (``#``). In HTML URLs these are links to an -on-page anchor. Media URIs can make use of them in various other ways. - -.. literalinclude:: uri/022.php - -============ -URI Segments -============ - -Each section of the path between the slashes is a single segment. - -.. note:: In the case of your site URI, URI Segments mean only the URI path part relative to the baseURL. If your - baseURL contains subfolders, the values will be different from the current URI path. - -The URI class provides a simple way to determine what the values of the segments are. The segments start at 1 being the -furthest left of the path. - -.. literalinclude:: uri/023.php - -You can also set a different default value for a particular segment by using the second parameter of the -``getSegment()`` method. The default is an empty string. - -.. literalinclude:: uri/024.php - -.. note:: You can get the last +1 segment. When you try to get the last +2 or higher segment, an exception will be - thrown by default. You can prevent exceptions from being thrown with the ``setSilent()`` method. - -You can get a count of the total segments: - -.. literalinclude:: uri/025.php - -Finally, you can retrieve an array of all of the segments: - -.. literalinclude:: uri/026.php - -=========================== -Disable Throwing Exceptions -=========================== - -By default, some methods of this class may throw an exception. If you want to disable it, you can set a special flag -that will prevent throwing exceptions. - -.. literalinclude:: uri/027.php diff --git a/user_guide_src/source/libraries/uri/001.php b/user_guide_src/source/libraries/uri/001.php deleted file mode 100644 index 7219d03d248f..000000000000 --- a/user_guide_src/source/libraries/uri/001.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getUri(); diff --git a/user_guide_src/source/libraries/uri/006.php b/user_guide_src/source/libraries/uri/006.php deleted file mode 100644 index 3cdabe4db4e8..000000000000 --- a/user_guide_src/source/libraries/uri/006.php +++ /dev/null @@ -1,4 +0,0 @@ -getScheme(); // 'http' -$uri->setScheme('https'); diff --git a/user_guide_src/source/libraries/uri/009.php b/user_guide_src/source/libraries/uri/009.php deleted file mode 100644 index 44043fbe63d0..000000000000 --- a/user_guide_src/source/libraries/uri/009.php +++ /dev/null @@ -1,5 +0,0 @@ -getAuthority(); // user@example.com:21 diff --git a/user_guide_src/source/libraries/uri/010.php b/user_guide_src/source/libraries/uri/010.php deleted file mode 100644 index 7b723837fd7f..000000000000 --- a/user_guide_src/source/libraries/uri/010.php +++ /dev/null @@ -1,7 +0,0 @@ -getAuthority(); // user@example.com:21 -echo $uri->showPassword()->getAuthority(); // user:password@example.com:21 - -// Turn password display off again. -$uri->showPassword(false); diff --git a/user_guide_src/source/libraries/uri/011.php b/user_guide_src/source/libraries/uri/011.php deleted file mode 100644 index ac1297380583..000000000000 --- a/user_guide_src/source/libraries/uri/011.php +++ /dev/null @@ -1,3 +0,0 @@ -getAuthority(true); // user@example.com diff --git a/user_guide_src/source/libraries/uri/012.php b/user_guide_src/source/libraries/uri/012.php deleted file mode 100644 index 0f733222f408..000000000000 --- a/user_guide_src/source/libraries/uri/012.php +++ /dev/null @@ -1,3 +0,0 @@ -getUserInfo(); // user diff --git a/user_guide_src/source/libraries/uri/013.php b/user_guide_src/source/libraries/uri/013.php deleted file mode 100644 index 65836aa97865..000000000000 --- a/user_guide_src/source/libraries/uri/013.php +++ /dev/null @@ -1,4 +0,0 @@ -showPassword()->getUserInfo(); // user:password -$uri->showPassword(false); diff --git a/user_guide_src/source/libraries/uri/014.php b/user_guide_src/source/libraries/uri/014.php deleted file mode 100644 index 79192a56955d..000000000000 --- a/user_guide_src/source/libraries/uri/014.php +++ /dev/null @@ -1,6 +0,0 @@ -getHost(); // www.example.com -echo $uri->setHost('anotherexample.com')->getHost(); // anotherexample.com diff --git a/user_guide_src/source/libraries/uri/015.php b/user_guide_src/source/libraries/uri/015.php deleted file mode 100644 index f5b43c3a65d0..000000000000 --- a/user_guide_src/source/libraries/uri/015.php +++ /dev/null @@ -1,6 +0,0 @@ -getPort(); // 21 -echo $uri->setPort(2201)->getPort(); // 2201 diff --git a/user_guide_src/source/libraries/uri/016.php b/user_guide_src/source/libraries/uri/016.php deleted file mode 100644 index f9d82a86759d..000000000000 --- a/user_guide_src/source/libraries/uri/016.php +++ /dev/null @@ -1,6 +0,0 @@ -getPath(); // '/some/path' -echo $uri->setPath('/another/path')->getPath(); // '/another/path' diff --git a/user_guide_src/source/libraries/uri/017.php b/user_guide_src/source/libraries/uri/017.php deleted file mode 100644 index dd45fb157f4b..000000000000 --- a/user_guide_src/source/libraries/uri/017.php +++ /dev/null @@ -1,6 +0,0 @@ -getQuery(); // 'foo=bar' -$uri->setQuery('foo=bar&bar=baz'); diff --git a/user_guide_src/source/libraries/uri/018.php b/user_guide_src/source/libraries/uri/018.php deleted file mode 100644 index 64d5ab6f359c..000000000000 --- a/user_guide_src/source/libraries/uri/018.php +++ /dev/null @@ -1,3 +0,0 @@ -setQueryArray(['foo' => 'bar', 'bar' => 'baz']); diff --git a/user_guide_src/source/libraries/uri/019.php b/user_guide_src/source/libraries/uri/019.php deleted file mode 100644 index 076fbf4652c1..000000000000 --- a/user_guide_src/source/libraries/uri/019.php +++ /dev/null @@ -1,3 +0,0 @@ -addQuery('foo', 'bar'); diff --git a/user_guide_src/source/libraries/uri/020.php b/user_guide_src/source/libraries/uri/020.php deleted file mode 100644 index 53c3b8d66dd9..000000000000 --- a/user_guide_src/source/libraries/uri/020.php +++ /dev/null @@ -1,9 +0,0 @@ -getQuery(['only' => ['foo']]); - -// Returns 'foo=bar&baz=foz' -echo $uri->getQuery(['except' => ['bar']]); diff --git a/user_guide_src/source/libraries/uri/021.php b/user_guide_src/source/libraries/uri/021.php deleted file mode 100644 index ed2976e6e1d3..000000000000 --- a/user_guide_src/source/libraries/uri/021.php +++ /dev/null @@ -1,9 +0,0 @@ -stripQuery('foo', 'bar'); - -// Leaves just the 'foo' variable -$uri->keepQuery('foo'); diff --git a/user_guide_src/source/libraries/uri/022.php b/user_guide_src/source/libraries/uri/022.php deleted file mode 100644 index e2df019dcb87..000000000000 --- a/user_guide_src/source/libraries/uri/022.php +++ /dev/null @@ -1,6 +0,0 @@ -getFragment(); // 'first-heading' -echo $uri->setFragment('second-heading')->getFragment(); // 'second-heading' diff --git a/user_guide_src/source/libraries/uri/023.php b/user_guide_src/source/libraries/uri/023.php deleted file mode 100644 index 34e8764cd045..000000000000 --- a/user_guide_src/source/libraries/uri/023.php +++ /dev/null @@ -1,8 +0,0 @@ -getSegment(1) === 'users') { - echo $uri->getSegment(2); -} diff --git a/user_guide_src/source/libraries/uri/024.php b/user_guide_src/source/libraries/uri/024.php deleted file mode 100644 index 61a951db93c3..000000000000 --- a/user_guide_src/source/libraries/uri/024.php +++ /dev/null @@ -1,14 +0,0 @@ -getSegment(3, 'foo'); -// will print 'bar' -echo $uri->getSegment(4, 'bar'); -// will throw an exception -echo $uri->getSegment(5, 'baz'); -// will print 'baz' -echo $uri->setSilent()->getSegment(5, 'baz'); -// will print '' (empty string) -echo $uri->setSilent()->getSegment(5); diff --git a/user_guide_src/source/libraries/uri/025.php b/user_guide_src/source/libraries/uri/025.php deleted file mode 100644 index ce130a2c6f8b..000000000000 --- a/user_guide_src/source/libraries/uri/025.php +++ /dev/null @@ -1,3 +0,0 @@ -getTotalSegments(); // 3 diff --git a/user_guide_src/source/libraries/uri/026.php b/user_guide_src/source/libraries/uri/026.php deleted file mode 100644 index f2d8bb72553f..000000000000 --- a/user_guide_src/source/libraries/uri/026.php +++ /dev/null @@ -1,12 +0,0 @@ -getSegments(); - -/* - * Produces: - * [ - * 0 => 'users', - * 1 => '15', - * 2 => 'profile', - * ] - */ diff --git a/user_guide_src/source/libraries/uri/027.php b/user_guide_src/source/libraries/uri/027.php deleted file mode 100644 index 8ad2f883ffe4..000000000000 --- a/user_guide_src/source/libraries/uri/027.php +++ /dev/null @@ -1,7 +0,0 @@ -setSilent(); - -// Enable throwing exceptions (default) -$uri->setSilent(false); diff --git a/user_guide_src/source/libraries/user_agent.rst b/user_guide_src/source/libraries/user_agent.rst deleted file mode 100644 index bf589aadaac6..000000000000 --- a/user_guide_src/source/libraries/user_agent.rst +++ /dev/null @@ -1,148 +0,0 @@ -################ -User Agent Class -################ - -The User Agent Class provides functions that help identify information about the browser, mobile device, or robot -visiting your site. - -.. contents:: - :local: - :depth: 2 - -************************** -Using the User Agent Class -************************** - -Initializing the Class -====================== - -The User Agent class is always available directly from the current :doc:`IncomingRequest ` -instance. By default, you will have a request instance in your controller that you can retrieve the User Agent class -from: - -.. literalinclude:: user_agent/001.php - -User Agent Definitions -====================== - -The user agent name definitions are in a config file located at: **app/Config/UserAgents.php**. You may add items to the -various user agent arrays if needed. - -Example -======= - -When the User Agent class is initialized, it will attempt to determine whether the user agent browsing your site is a -web browser, a mobile device, or a robot. It will also gather the platform information if it is available: - -.. literalinclude:: user_agent/002.php - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\HTTP - -.. php:class:: UserAgent - - .. php:method:: isBrowser([$key = null]) - - :param string $key: Optional browser name - :returns: true if the user agent is a (specified) browser, false if not - :rtype: bool - - Returns true/false (boolean) if the user agent is a known web browser. - - .. literalinclude:: user_agent/003.php - - .. note:: The string "Safari" in this example is an array key in the list of browser definitions. You can find - this list in **app/Config/UserAgents.php** if you want to add new browsers or change the strings. - - .. php:method:: isMobile([$key = null]) - - :param string $key: Optional mobile device name - :returns: true if the user agent is a (specified) mobile device, false if not - :rtype: bool - - Returns true/false (boolean) if the user agent is a known mobile device. - - .. literalinclude:: user_agent/004.php - - .. php:method:: isRobot([$key = null]) - - :param string $key: Optional robot name - :returns: true if the user agent is a (specified) robot, false if not - :rtype: bool - - Returns true/false (boolean) if the user agent is a known robot. - - .. note:: The user agent library only contains the most common robot definitions. It is not a complete list of - bots. There are hundreds of them, so searching for each one would not be very efficient. If you find that - some bots that commonly visit your site are missing from the list, you can add them to your - **app/Config/UserAgents.php** file. - - .. php:method:: isReferral() - - :returns: true if the user agent is a referral, false if not - :rtype: bool - - Returns true/false (boolean) if the user agent was referred from another site. - - .. php:method:: getBrowser() - - :returns: Detected browser or an empty string - :rtype: string - - Returns a string containing the name of the web browser viewing your site. - - .. php:method:: getVersion() - - :returns: Detected browser version or an empty string - :rtype: string - - Returns a string containing the version number of the web browser viewing your site. - - .. php:method:: getMobile() - - :returns: Detected mobile device brand or an empty string - :rtype: string - - Returns a string containing the name of the mobile device viewing your site. - - .. php:method:: getRobot() - - :returns: Detected robot name or an empty string - :rtype: string - - Returns a string containing the name of the robot viewing your site. - - .. php:method:: getPlatform() - - :returns: Detected operating system or an empty string - :rtype: string - - Returns a string containing the platform viewing your site (Linux, Windows, OS X, etc.). - - .. php:method:: getReferrer() - - :returns: Detected referrer or an empty string - :rtype: string - - The referrer, if the user agent was referred from another site. Typically you'll test for this as follows: - - .. literalinclude:: user_agent/005.php - - .. php:method:: getAgentString() - - :returns: Full user agent string or an empty string - :rtype: string - - Returns a string containing the full user agent string. Typically it will be something like this:: - - Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.4) Gecko/20060613 Camino/1.0.2 - - .. php:method:: parse($string) - - :param string $string: A custom user-agent string - :rtype: void - - Parses a custom user-agent string, different from the one reported by the current visitor. diff --git a/user_guide_src/source/libraries/user_agent/001.php b/user_guide_src/source/libraries/user_agent/001.php deleted file mode 100644 index f8af7f7cfaee..000000000000 --- a/user_guide_src/source/libraries/user_agent/001.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getUserAgent(); diff --git a/user_guide_src/source/libraries/user_agent/002.php b/user_guide_src/source/libraries/user_agent/002.php deleted file mode 100644 index 0a92a06bc2f7..000000000000 --- a/user_guide_src/source/libraries/user_agent/002.php +++ /dev/null @@ -1,17 +0,0 @@ -request->getUserAgent(); - -if ($agent->isBrowser()) { - $currentAgent = $agent->getBrowser() . ' ' . $agent->getVersion(); -} elseif ($agent->isRobot()) { - $currentAgent = $agent->getRobot(); -} elseif ($agent->isMobile()) { - $currentAgent = $agent->getMobile(); -} else { - $currentAgent = 'Unidentified User Agent'; -} - -echo $currentAgent; - -echo $agent->getPlatform(); // Platform info (Windows, Linux, Mac, etc.) diff --git a/user_guide_src/source/libraries/user_agent/003.php b/user_guide_src/source/libraries/user_agent/003.php deleted file mode 100644 index 0abfbf22d7d8..000000000000 --- a/user_guide_src/source/libraries/user_agent/003.php +++ /dev/null @@ -1,7 +0,0 @@ -isBrowser('Safari')) { - echo 'You are using Safari.'; -} elseif ($agent->isBrowser()) { - echo 'You are using a browser.'; -} diff --git a/user_guide_src/source/libraries/user_agent/004.php b/user_guide_src/source/libraries/user_agent/004.php deleted file mode 100644 index 80405bff519d..000000000000 --- a/user_guide_src/source/libraries/user_agent/004.php +++ /dev/null @@ -1,9 +0,0 @@ -isMobile('iphone')) { - echo view('iphone/home'); -} elseif ($agent->isMobile()) { - echo view('mobile/home'); -} else { - echo view('web/home'); -} diff --git a/user_guide_src/source/libraries/user_agent/005.php b/user_guide_src/source/libraries/user_agent/005.php deleted file mode 100644 index 80aad0f42c59..000000000000 --- a/user_guide_src/source/libraries/user_agent/005.php +++ /dev/null @@ -1,5 +0,0 @@ -isReferral()) { - echo $agent->getReferrer(); -} diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst deleted file mode 100644 index c7cfae2b3abf..000000000000 --- a/user_guide_src/source/libraries/validation.rst +++ /dev/null @@ -1,1074 +0,0 @@ -.. _validation: - -########## -Validation -########## - -CodeIgniter provides a comprehensive data validation class that helps minimize the amount of code you'll write. - -.. contents:: - :local: - :depth: 2 - -******** -Overview -******** - -Before explaining CodeIgniter's approach to data validation, let's describe the ideal scenario: - -#. A form is displayed. -#. You fill it in and submit it. -#. If you submitted something invalid, or perhaps missed a required item, the form is redisplayed containing your data - along with an error message describing the problem. -#. This process continues until you have submitted a valid form. - -On the receiving end, the script must: - -#. Check for required data. -#. Verify that the data is of the correct type, and meets the correct criteria. For example, if a username is submitted - it must be validated to contain only permitted characters. It must be of a minimum length, and not exceed a maximum - length. The username can't be someone else's existing username, or perhaps even a reserved word. Etc. -#. Sanitize the data for security. -#. Pre-format the data if needed. -#. Prep the data for insertion in the database. - -Although there is nothing terribly complex about the above process, it usually requires a significant amount of code, -and to display error messages, various control structures are usually placed within the form HTML. Form validation, -while simple to create, is generally very messy and tedious to implement. - -************************ -Form Validation Tutorial -************************ - -What follows is a "hands-on" tutorial for implementing CodeIgniter's Form Validation. - -In order to implement form validation, you'll need three things: - -#. A :doc:`View ` file containing a form. -#. A View file containing a "success" message to be displayed upon successful submission. -#. A :doc:`controller ` method to receive and process the submitted data. - -Let's create those three things, using a member sign-up form as the example. - -The Form -======== - -Using a text editor, create a form called **signup.php**. In it, place this code and save it to your **app/Views/** -folder:: - - - - My Form - - - - - - - -
    Username
    - - -
    Password
    - - -
    Password Confirm
    - - -
    Email Address
    - - -
    - - - - - - -The Success Page -================ - -Using a text editor, create a form called **success.php**. In it, place this code and save it to your **app/Views/** -folder:: - - - - My Form - - - -

    Your form was successfully submitted!

    - -

    - - - - -The Controller -============== - -Using a text editor, create a controller called **Form.php**. In it, place this code and save it to your -**app/Controllers/** folder: - -.. literalinclude:: validation/001.php - -.. note:: The :ref:`$this->request->is() ` method can be used since v4.3.0. In previous versions, - you need to use ``if (strtolower($this->request->getMethod()) !== 'post')``. - -.. note:: The :ref:`$this->validator->getValidated() ` method can be used since - v4.4.0. - -The Routes -========== - -Then add routes for the controller in **app/Config/Routes.php**: - -.. literalinclude:: validation/039.php - :lines: 2- - -Try it! -======= - -To try your form, visit your site using a URL similar to this one:: - - example.com/index.php/form/ - -If you submit the form, you should simply see the form reload. That's because you haven't set up any validation rules in -:ref:`controller-validatedata` yet. - -The ``validateData()`` method is a method in the Controller. It uses the **Validation class** inside. See -:ref:`controller-validatedata`. - -.. note:: Since you haven't told the ``validateData()`` method to validate anything yet, it **returns false** (boolean - false) **by default**. The ``validateData()`` method only returns true if it has successfully applied your rules - without any of them failing. - -Explanation -=========== - -You'll notice several things about the above pages. - -signup.php ----------- - -The form (**signup.php**) is a standard web form with a couple of exceptions: - -#. It uses a :doc:`form helper ` to create the form opening and closing. Technically, this isn't - necessary. You could create the form using standard HTML. However, the benefit of using the helper is that it - generates the action URL for you, based on the URL in your config file. This makes your application more portable in - the event your URLs change. -#. At the top of the form, you'll notice the following function call: :: - - - - This function will return any error messages sent back by the validator. If there are no messages, it returns an - empty string. - -Form.php --------- - -The controller (**Form.php**) has one property: ``$helpers``. It loads the form helper used by your view files. - -The controller has one method: ``index()``. This method returns the **signup** view to show the form when a non-POST -request comes. Otherwise, it uses the Controller-provided :ref:`controller-validatedata` method. It also runs the -validation routine. Based on whether the validation was successful, it either presents the form or the success page. - -Add Validation Rules -==================== - -Then add validation rules in the controller (**Form.php**): - -.. literalinclude:: validation/002.php - :lines: 2- - -If you submit the form, you should see the success page or the form with error messages. - -********************* -Config for Validation -********************* - -.. _validation-traditional-and-strict-rules: - -Traditional and Strict Rules -============================ - -CodeIgniter 4 has two kinds of Validation rule classes. - -The default rule classes (**Strict Rules**) have the namespace ``CodeIgniter\Validation\StrictRules``, and they provide -strict validation. - -The traditional rule classes (**Traditional Rules**) have the namespace ``CodeIgniter\Validation``. They are provided -for backward compatibility only. They may not validate non-string values correctly and need not be used in new projects. - -.. note:: Since v4.3.0, **Strict Rules** are used by default for better security. - -Strict Rules ------------- - -.. versionadded:: 4.2.0 - -The **Strict Rules** don't use implicit type conversion. - -Traditional Rules ------------------ - -.. important:: Traditional Rules exist only for backward compatibility. Do not use them in new projects. Even if you are - already using them, we recommend switching to Strict Rules. - -.. warning:: When validating data that contains non-string values, such as JSON data, you should use **Strict Rules**. - -The **Traditional Rules** implicitly assume that string values are validated, and the input value may be converted -implicitly to a string value. It works for most basic cases like validating POST data. - -However, for example, if you use JSON input data, it may be of type bool/null/array. When you validate the boolean -``true``, it is converted to the string ``'1'`` with the Traditional rule classes. If you validate it with the -``integer`` rule, ``'1'`` passes the validation. - -Using Traditional Rules ------------------------ - -.. warning:: The **Traditional Rules** are provided for backward compatibility only. They may not validate non-string - values correctly and need not be used in new projects. - -If you want to use traditional rules, you need to change the rule classes in **app/Config/Validation.php**: - -.. literalinclude:: validation/003.php - -******************* -Loading the Library -******************* - -The library is loaded as a service named **validation**: - -.. literalinclude:: validation/004.php - :lines: 2- - -This automatically loads the ``Config\Validation`` file, which contains settings for including multiple Rulesets, and -collections of rules that can be easily reused. - -.. note:: You may never need to use this method, as both the :doc:`Controller ` and the - :doc:`Model ` provide methods to make validation even easier. - -******************** -How Validation Works -******************** - -- The validation never changes the data to be validated. -- The validation checks each field in turn according to the Validation Rules you set. If any rule returns false, the - check for that field ends there. -- The Format Rules do not permit an empty string. If you want to permit an empty string, add the ``permit_empty`` rule. -- If a field does not exist in the data to be validated, the value is interpreted as ``null``. If you want to check that - the field exists, add the ``field_exists`` rule. - -.. note:: The ``field_exists`` rule can be used since v4.5.0. - -************************ -Setting Validation Rules -************************ - -CodeIgniter lets you set as many validation rules as you need for a given field, cascading them in order. To set -validation rules, you will use the ``setRule()``, ``setRules()``, or ``withRequest()`` methods. - -Setting a Single Rule -===================== - -setRule() ---------- - -This method sets a single rule. It has the method signature:: - - setRule(string $field, ?string $label, array|string $rules[, array $errors = []]) - -The ``$rules`` parameter takes in either a pipe-delimited list of rules or an array collection of rules: - -.. literalinclude:: validation/005.php - :lines: 2- - -The value you pass to ``$field`` must match the key of any data array that is sent in. If the data is taken directly -from ``$_POST``, then it must be an exact match for the form input name. - -.. warning:: Prior to v4.2.0, this method's third parameter, ``$rules``, was typehinted to accept ``string``. In v4.2.0 - and after, the typehint was removed to allow arrays, too. To avoid LSP being broken in extending classes overriding - this method, the child class's method should also be modified to remove the typehint. - -Setting Multiple Rules -====================== - -setRules() ----------- - -Like ``setRule()``, but accepts an array of field names and their rules: - -.. literalinclude:: validation/006.php - :lines: 2- - -To give a labeled error message, you can set it up as follows: - -.. literalinclude:: validation/007.php - :lines: 2- - -.. note:: ``setRules()`` will overwrite any rules that were set previously. To add more than one rule to an existing set - of rules, use ``setRule()`` multiple times. - -.. _validation-dot-array-syntax: - -Setting Rules for Array Data -============================ - -If your data is in a nested associative array, you can use "dot array syntax" to easily validate your data: - -.. literalinclude:: validation/009.php - :lines: 2- - -You can use the ``*`` wildcard symbol to match any one level of the array: - -.. literalinclude:: validation/010.php - :lines: 2- - -.. note:: Prior to v4.4.4, due to a bug, the wildcard ``*`` validated data in incorrect dimensions. See - :ref:`Upgrading ` for details. - -The "dot array syntax" can also be useful when you have single-dimension array data. For example, data returned by a -multi-select dropdown: - -.. literalinclude:: validation/011.php - :lines: 2- - -.. _validation-withrequest: - -withRequest() -============= - -.. important:: This method exists only for backward compatibility. Do not use it in new projects. Even if you are - already using it, we recommend that you use another, more appropriate method. - -.. warning:: If you want to validate POST data only, don't use ``withRequest()``. This method uses - :ref:`$request->getVar() ` which returns ``$_GET``, ``$_POST`` or ``$_COOKIE`` data in - that order (depending on **php.ini** - `request-order `_). Newer values override older - values. POST values may be overridden by the cookies if they have the same name. - -One of the most common times you will use the validation library is when validating data that was input from an HTTP -Request. If desired, you can pass an instance of the current Request object and it will take all of the input data and -set it as the data to be validated: - -.. literalinclude:: validation/008.php - :lines: 2- - -.. warning:: When you use this method, you should use the :ref:`getValidated() ` - method to get the validated data. Because this method gets JSON data from - :ref:`$request->getJSON() ` when the request is a JSON request - (``Content-Type: application/json``), or gets raw data from - :ref:`$request->getRawInput() ` when the request is a PUT, PATCH, or DELETE - request and is not an HTML form post (``Content-Type: multipart/form-data``), or gets data from - :ref:`$request->getVar() `, and an attacker could change what data is validated. - -.. note:: The :ref:`getValidated() ` method can be used since v4.4.0. - -*********************** -Working with Validation -*********************** - -Running Validation -================== - -The ``run()`` method runs validation. It has the method signature:: - - run(?array $data = null, ?string $group = null, ?string $dbGroup = null): bool - -The ``$data`` is an array of data to validate. The optional second parameter ``$group`` is the -:ref:`predefined group of rules ` to apply. The optional third parameter ``$dbGroup`` is the database -group to use. - -This method returns true if the validation is successful. - -.. literalinclude:: validation/043.php - :lines: 2- - -Running Multiple Validations -============================ - -.. note:: The ``run()`` method will not reset the error state. Should a previous run fail, ``run()`` will always return - false and ``getErrors()`` will return all previous errors until explicitly reset. - -If you intend to run multiple validations, for instance on different data sets or with different rules after one -another, you might need to call ``$validation->reset()`` before each run to get rid of errors from the previous run. Be -aware that ``reset()`` will invalidate any data, rule or custom error you previously set, so ``setRules()``, -``setRuleGroup()`` etc. need to be repeated: - -.. literalinclude:: validation/019.php - :lines: 2- - -Validating 1 Value -================== - -The ``check()`` method validates one value against the rules. The first parameter ``$value`` is the value to validate. -The second parameter ``$rule`` holds the validation rules. The optional third parameter ``$errors`` is the custom error -message. - -.. literalinclude:: validation/012.php - :lines: 2- - -.. note:: Prior to v4.4.0, this method's second parameter, ``$rule``, was typehinted to accept ``string``. In v4.4.0 and - after, the typehint was removed to allow arrays, too. - -.. note:: This method calls the ``setRule()`` method to set the rules internally. - -.. _validation-getting-validated-data: - -Getting Validated Data -====================== - -.. versionadded:: 4.4.0 - -The actual validated data can be retrieved with the ``getValidated()`` method. This method returns an array of only -those elements that have been validated by the validation rules. - -.. literalinclude:: validation/044.php - :lines: 2- - -.. literalinclude:: validation/045.php - :lines: 2- - -.. _saving-validation-rules-to-config-file: - -Saving Sets of Validation Rules to the Config File -================================================== - -A nice feature of the Validation class is that it permits you to store all your validation rules for your entire -application in a config file. You organize the rules into "groups". You can specify a different group every time you run -the validation. - -.. _validation-array: - -How to Save Your Rules ----------------------- - -To store your validation rules, simply create a new public property in the ``Config\Validation`` class with the name of -your group. This element will hold an array with your validation rules. As shown earlier, the validation array will have -this prototype: - -.. literalinclude:: validation/013.php - -How to Specify Rule Group -------------------------- - -You can specify the group to use when you call the ``run()`` method: - -.. literalinclude:: validation/014.php - :lines: 2- - -How to Save Error Messages --------------------------- - -You can also store custom error messages in this configuration file by naming the property the same as the group, with -``_errors`` appended. These will automatically be used for any errors when this group is used: - -.. literalinclude:: validation/015.php - -Or pass all settings in an array: - -.. literalinclude:: validation/016.php - -See :ref:`validation-custom-errors` for details on the formatting of the array. - -Getting & Setting Rule Groups ------------------------------ - -Get Rule Group -^^^^^^^^^^^^^^ - -This method gets a rule group from the validation configuration: - -.. literalinclude:: validation/017.php - :lines: 2- - -Set Rule Group -^^^^^^^^^^^^^^ - -This method sets a rule group from the validation configuration to the validation service: - -.. literalinclude:: validation/018.php - :lines: 2- - -.. _validation-placeholders: - -Validation Placeholders -======================= - -The Validation class provides a simple method to replace parts of your rules based on data that's being passed into it. -This sounds fairly obscure but can be especially handy with the ``is_unique`` validation rule. - -Placeholders are simply the name of the field (or array key) that was passed in as ``$data`` surrounded by curly -brackets. This will be replaced by the **value** of the matched incoming field. An example should clarify this: - -.. literalinclude:: validation/020.php - :lines: 2- - -.. warning:: Since v4.3.5, you must set the validation rules for the placeholder field (the ``id`` field in the sample - code above) for security reasons, because attackers can send any data to your application. - -This set of rules states that the email address should be unique in the database, except for the row that has an id -matching the placeholder's value. Assuming that the form POST data had the following: - -.. literalinclude:: validation/021.php - :lines: 2- - -then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule: - -.. literalinclude:: validation/022.php - :lines: 2- - -So it will ignore the row in the database that has ``id=4`` when it verifies the email is unique. - -.. note:: Since v4.3.5, if the placeholder (``id``) value does not pass the validation, the placeholder would not be - replaced. - -This can also be used to create more dynamic rules at runtime, as long as you take care that any dynamic keys passed in -don't conflict with your form data. - -******************* -Working with Errors -******************* - -The Validation library provides several methods to help you set error messages, provide custom error messages, and -retrieve one or more errors to display. - -By default, error messages are derived from language strings in **system/Language/en/Validation.php**, where each rule -has an entry. In case you want to change a message default, create a file **app/Language/en/Validation.php** (and/or the -corresponding folder of the locale you use in place of/besides ``en``) and place in it keys and values of those error -messages for which you want different defaults. - -.. _validation-custom-errors: - -Setting Custom Error Messages -============================= - -Both the ``setRule()`` and ``setRules()`` methods can accept an array of custom messages that will be used as errors -specific to each field as their last parameter. This allows for a very pleasant experience for the user since the errors -are tailored to each instance. If no custom error message is provided, the default value will be used. - -There are two ways to provide custom error messages. - -As the last parameter: - -.. literalinclude:: validation/023.php - :lines: 2- - -Or in a labeled style: - -.. literalinclude:: validation/024.php - :lines: 2- - -If you'd like to include a field's "human" name, or the optional parameter some rules allow for (such as max_length), or -the value that was validated, you can add the ``{field}``, ``{param}`` and ``{value}`` tags to your message, -respectively:: - - 'min_length' => 'Supplied value ({value}) for {field} must have at least {param} characters.' - -On a field with the human name Username and a rule of ``min_length[6]`` with a value of "Pizza", an error would display: -"Supplied value (Pizza) for Username must have at least 6 characters." - -.. warning:: If you get the error messages with ``getErrors()`` or ``getError()``, the messages are not HTML-escaped. If - you use user input data like ``({value})`` to make the error message, it might contain HTML tags. If you don't - escape the messages before displaying them, XSS attacks are possible. - -.. note:: When using label-style error messages, if you pass the second parameter to ``setRules()``, it will be - overwritten with the value of the first parameter. - -Translation of Messages and Validation Labels -============================================= - -To use translated strings from language files, we can simply use the dot syntax. Let's say we have a file with -translations located here: **app/Language/en/Rules.php**. We can simply use the language lines defined in this file, -like this: - -.. literalinclude:: validation/025.php - :lines: 2- - -.. _validation-getting-all-errors: - -Getting All Errors -================== - -If you need to retrieve all error messages for failed fields, you can use the ``getErrors()`` method: - -.. literalinclude:: validation/026.php - :lines: 2- - -If no errors exist, an empty array will be returned. - -When using a wildcard (``*``), the error will point to a specific field, replacing the asterisk with the appropriate -key/keys:: - - // for data - 'contacts' => [ - 'friends' => [ - [ - 'name' => 'Fred Flintstone', - ], - [ - 'name' => '', - ], - ] - ] - - // rule - 'contacts.friends.*.name' => 'required' - - // error will be - 'contacts.friends.1.name' => 'The contacts.friends.*.name field is required.' - -Getting a Single Error -====================== - -You can retrieve the error for a single field with the ``getError()`` method. The only parameter is the field name: - -.. literalinclude:: validation/027.php - :lines: 2- - -If no error exists, an empty string will be returned. - -.. note:: When using a wildcard, all found errors that match the mask will be combined into one line separated by the - EOL character. - -Check If Error Exists -===================== - -You can check to see if an error exists with the ``hasError()`` method. The only parameter is the field name: - -.. literalinclude:: validation/028.php - :lines: 2- - -When specifying a field with a wildcard, all errors matching the mask will be checked: - -.. literalinclude:: validation/029.php - :lines: 2- - -.. _validation-redirect-and-validation-errors: - -Redirect and Validation Errors -============================== - -PHP shares nothing between requests. So when you redirect if a validation fails, there will be no validation errors in -the redirected request because the validation has run in the previous request. - -In that case, you need to use the Form helper functions :php:func:`validation_errors()`, -:php:func:`validation_list_errors()` and :php:func:`validation_show_error()`. These functions check the validation -errors that are stored in the session. - -To store the validation errors in the session, you need to use ``withInput()`` with :php:func:`redirect() `: - -.. literalinclude:: validation/042.php - :lines: 2- - -.. _validation-customizing-error-display: - -************************* -Customizing Error Display -************************* - -When you call ``$validation->listErrors()`` or ``$validation->showError()``, it loads a view file in the background that -determines how the errors are displayed. By default, they display with a class of ``errors`` on the wrapping div. You -can easily create new views and use them throughout your application. - -Creating the Views -================== - -The first step is to create custom views. These can be placed anywhere that the ``view()`` method can locate them, which -means the standard View directory or any namespaced View folder will work. For example, you could create a new view at -**app/Views/_errors_list.php**: - -.. literalinclude:: validation/030.php - -An array named ``$errors`` is available within the view that contains a list of the errors, where the key is the name of -the field that had the error, and the value is the error message, like this: - -.. literalinclude:: validation/031.php - :lines: 2- - -There are actually two types of views that you can create. The first has an array of all of the errors, and is what we -just looked at. The other type is simpler, and only contains a single variable, ``$error``, that contains the error -message. This is used with the ``showError()`` method where a field must be specified:: - - - -Configuration -============= - -Once you have your views created, you need to let the Validation library know about them. Open -**app/Config/Validation.php**. Inside, you'll find the ``$templates`` property where you can list as many custom views -as you want, and provide a short alias they can be referenced by. If we were to add our example file from above, it -would look something like: - -.. literalinclude:: validation/032.php - -Specifying the Template -======================= - -You can specify the template to use by passing its alias as the first parameter in ``listErrors()``:: - - listErrors('my_list') ?> - -When showing field-specific errors, you can pass the alias as the second parameter to the ``showError()`` method, right -after the name of the field the error should belong to:: - - showError('username', 'my_single') ?> - -********************* -Creating Custom Rules -********************* - -.. _validation-using-rule-classes: - -Using Rule Classes -================== - -Rules are stored within simple, namespaced classes. They can be stored in any location you would like, as long as the -autoloader can find them. These files are called RuleSets. - -Adding a RuleSet ----------------- - -To add a new RuleSet, edit **app/Config/Validation.php** and add the new file to the ``$ruleSets`` array: - -.. literalinclude:: validation/033.php - -You can add it as either a simple string with the fully qualified class name, or using the ``::class`` suffix as shown -above. The primary benefit of using the ``::class`` suffix is that it provides some extra navigation capabilities in -more advanced IDEs. - -Creating a Rule Class ---------------------- - -Within the file itself, each method is a rule and must accept a value to validate as the first parameter, and must -return a boolean true or false value signifying true if it passed the test or false if it did not: - -.. literalinclude:: validation/034.php - -By default, the system will look within **system/Language/en/Validation.php** for the language strings used within -errors. To provide default error messages for your custom rules, you may place them in -**app/Language/en/Validation.php** (and/or the corresponding folder of the locale you use in place of ``en``). Also, in -case you want to use some other language string file in place of the default **Validation.php**, you may provide error -messages by accepting an ``&$error`` variable by reference in the second (or, in case your rule needs to work with -parameters, as described below – the fourth) parameter: - -.. literalinclude:: validation/035.php - -Using a Custom Rule -------------------- - -Your new custom rule could now be used just like any other rule: - -.. literalinclude:: validation/036.php - :lines: 2- - -Allowing Parameters -------------------- - -If your method needs to work with parameters, the function will need a minimum of three parameters: - -1. the value to validate (``$value``) -2. the parameter string (``$params``) -3. an array with all of the data that was submitted with the form (``$data``) -4. (optional) a custom error string (``&$error``), just as described above. - -.. warning:: The field values in ``$data`` are unvalidated (or may be invalid). Using unvalidated input data is a source - of vulnerability. You must perform the necessary validation within your custom rules before using the data in - ``$data``. - -The ``$data`` array is especially handy for rules like ``required_with`` that need to check the value of another -submitted field to base its result on: - -.. literalinclude:: validation/037.php - -.. _validation-using-closure-rule: - -Using Closure Rule -================== - -.. versionadded:: 4.3.0 - -If you only need the functionality of a custom rule once throughout your application, you may use a closure instead of a -rule class. - -You need to use an array for validation rules: - -.. literalinclude:: validation/040.php - :lines: 2- - -You must set the error message for the closure rule. When you specify the error message, set the array key for the -closure rule. In the above code, the ``required`` rule has the key ``0``, and the closure has ``1``. - -Or you can use the following parameters: - -.. literalinclude:: validation/041.php - :lines: 2- - -.. _validation-using-callable-rule: - -Using Callable Rule -=================== - -.. versionadded:: 4.5.0 - -If you would like to use an array callback as a rule, you may use it instead of a Closure Rule. - -You need to use an array for validation rules: - -.. literalinclude:: validation/046.php - :lines: 2- - -You must set the error message for the callable rule. When you specify the error message, set the array key for the -callable rule. In the above code, the ``required`` rule has the key ``0``, and the callable has ``1``. - -Or you can use the following parameters: - -.. literalinclude:: validation/047.php - :lines: 2- - -.. _validation-available-rules: - -*************** -Available Rules -*************** - -.. note:: A rule is a string, so there must be **no spaces** between the parameters, especially for the ``is_unique`` - rule. There can be no spaces before and after ``ignore_value``. - -.. literalinclude:: validation/038.php - :lines: 2- - -.. _rules-for-general-use: - -Rules for General Use -===================== - -The following is a list of all the native rules that are available to use: - -======================= ========== ============================================= =================================================== -Rule Parameter Description Example -======================= ========== ============================================= =================================================== -alpha No Fails if field has anything other than - alphabetic characters in ASCII or is empty. -alpha_dash No Fails if field contains anything other than - alphanumeric characters, underscores or - dashes in ASCII or is empty. -alpha_numeric No Fails if field contains anything other than - alphanumeric characters in ASCII or is empty. -alpha_numeric_punct No Fails if field contains anything other than - alphanumeric, space, or this limited set of - punctuation characters: ``~`` (tilde), - ``!`` (exclamation), ``#`` (number), - ``$`` (dollar), ``%`` (percent), - ``&`` (ampersand), - ``*`` (asterisk), ``-`` (dash), - ``_`` (underscore), ``+`` (plus), - ``=`` (equals), ``|`` (vertical bar), - ``:`` (colon), ``.`` (period) or is empty. -alpha_numeric_space No Fails if field contains anything other than - alphanumeric or space characters in ASCII or - is empty. -alpha_space No Fails if field contains anything other than - alphabetic characters or spaces in ASCII or - is empty. -decimal No Fails if field contains anything other than - a decimal number. Also accepts a ``+`` or - ``-`` sign for the number. -differs Yes Fails if field does not differ from the one ``differs[field_name]`` - in the parameter. -exact_length Yes Fails if field length is not exactly ``exact_length[5]`` or ``exact_length[5,8,12]`` - the parameter value. One or more - comma-separated values are possible. -field_exists Yes Fails if field does not exist. (This rule was - added in v4.5.0.) -greater_than Yes Fails if field is less than or equal to ``greater_than[8]`` - the parameter value or not numeric. -greater_than_equal_to Yes Fails if field is less than the parameter ``greater_than_equal_to[5]`` - value, or not numeric. -hex No Fails if field contains anything other than - hexadecimal characters. -if_exist No If this rule is present, validation will - check the field only when the field key - exists in the data to validate. -in_list Yes Fails if field is not within a predetermined ``in_list[red,blue,green]`` - list. -integer No Fails if field contains anything other than - an integer. -is_natural No Fails if field contains anything other than - a natural number: ``0``, ``1``, ``2``, - ``3``, etc. -is_natural_no_zero No Fails if field contains anything other than - a natural number, except zero: ``1``, ``2``, - ``3``, etc. -is_not_unique Yes Checks the database to see if the given value ``is_not_unique[table.field,where_field,where_value]`` or ``is_not_unique[dbGroup.table.field,where_field,where_value]`` - exists. Can ignore records by field/value to - filter (currently accepts only one filter). - (Since v4.6.0, you can optionally pass - the dbGroup as a parameter) -is_unique Yes Checks if this field value exists in the ``is_unique[table.field,ignore_field,ignore_value]`` or ``is_unique[dbGroup.table.field,ignore_field,ignore_value]`` - database. Optionally set a column and value - to ignore, useful when updating records to - ignore itself. (Since v4.6.0, you can - optionally pass the dbGroup as a parameter) -less_than Yes Fails if field is greater than or equal to ``less_than[8]`` - the parameter value or not numeric. -less_than_equal_to Yes Fails if field is greater than the parameter ``less_than_equal_to[8]`` - value or not numeric. -matches Yes The value must match the value of the field - in the parameter. ``matches[field]`` -max_length Yes Fails if field is longer than the parameter ``max_length[8]`` - value. -min_length Yes Fails if field is shorter than the parameter ``min_length[3]`` - value. -not_in_list Yes Fails if field is within a predetermined ``not_in_list[red,blue,green]`` - list. -numeric No Fails if field contains anything other than - numeric characters. -permit_empty No Allows the field to receive an empty array, - empty string, null or false. On success, it - skips all other validation rules except for - required_with and required_without. -regex_match Yes Fails if field does not match the regular ``regex_match[/regex/]`` - expression. **Note:** Since v4.7.0, if - you're using a placeholder with this rule, - you must use double braces ``{{...}}`` - instead of single ones ``{...}``. -required No Fails if the field is an empty array, empty - string, null or false. -required_with Yes The field is required when any of the other ``required_with[field1,field2]`` - fields is not `empty()`_ in the data. -required_without Yes The field is required when any of the other ``required_without[field1,field2]`` - fields is `empty()`_ in the data. -string No A generic alternative to the **alpha*** rules - that confirms the element is a string -timezone No Fails if field does not match a timezone - per `timezone_identifiers_list()`_ -valid_base64 No Fails if field contains anything other than - valid Base64 characters. -valid_cc_number Yes Verifies that the credit card number matches ``valid_cc_number[amex]`` - the format used by the specified provider. - Currently supported providers are: - American Express (``amex``), - China Unionpay (``unionpay``), - Diners Club Carte Blanche (``carteblanche``), - Diners Club (``dinersclub``), - Discover Card (``discover``), - Interpayment (``interpayment``), - JCB (``jcb``), Maestro (``maestro``), - Dankort (``dankort``), NSPK MIR (``mir``), - Troy (``troy``), MasterCard (``mastercard``), - Visa (``visa``), UATP (``uatp``), - Verve (``verve``), - CIBC Convenience Card (``cibc``), - Royal Bank of Canada Client Card (``rbc``), - TD Canada Trust Access Card (``tdtrust``), - Scotiabank Scotia Card (``scotia``), - BMO ABM Card (``bmoabm``), - HSBC Canada Card (``hsbc``) -valid_date Yes Fails if field does not contain a valid date. ``valid_date[d/m/Y]`` - Any string that `strtotime()`_ accepts is - valid if you don't specify an optional - parameter that matches a date format. - **So it is usually necessary to specify - the parameter.** -valid_email No Fails if field does not contain a valid - email address. -valid_emails No Fails if any value provided in a - comma-separated list is not a valid email. -valid_ip Yes Fails if the supplied IP is not valid. ``valid_ip[ipv6]`` - Accepts an optional parameter of ``ipv4`` or - ``ipv6`` to specify an IP format. -valid_json No Fails if field does not contain a valid JSON - string. -valid_url No Fails if field does not contain (loosely) a - URL. Includes simple strings that could be - hostnames, like "codeigniter". - **Normally,** ``valid_url_strict`` **should - be used.** -valid_url_strict Yes Fails if field does not contain a valid URL. ``valid_url_strict[https]`` - You can optionally specify a list of valid - schemes. If not specified, ``http,https`` - are valid. This rule uses PHP's - ``FILTER_VALIDATE_URL``. -======================= ========== ============================================= =================================================== - -.. note:: You can also use any native PHP functions that return boolean and permit at least one parameter, the field - data to validate. - -.. important:: The Validation library **never alters the data** to validate. - -.. _timezone_identifiers_list(): https://www.php.net/manual/en/function.timezone-identifiers-list.php -.. _strtotime(): https://www.php.net/manual/en/function.strtotime.php -.. _empty(): https://www.php.net/manual/en/function.empty.php - -.. _rules-for-file-uploads: - -Rules for File Uploads -====================== - -When you validate uploaded files, you must use the rules specifically created for file validation. - -.. important:: Only rules that are listed in the table below can be used to validate files. Therefore, if you add any - general rules, like ``permit_empty``, to a file validation rules array or string, the file validation will not work - correctly. - -Since the value of a file upload HTML field doesn't exist, and is stored in the ``$_FILES`` global, the name of the -input field will need to be used twice: once to specify the field name as you would for any other rule, and again as the -first parameter of all file-upload-related rules:: - - // In the HTML - - - // In the controller - $this->validateData([], [ - 'avatar' => 'uploaded[avatar]|max_size[avatar,1024]', - ]); - -See also :ref:`file-upload-form-tutorial`. - -======================= ========== ============================================= =================================================== -Rule Parameter Description Example -======================= ========== ============================================= =================================================== -uploaded Yes Fails if the name of the parameter does not ``uploaded[field_name]`` - match the name of any uploaded files. - If you want the file upload to be optional - (not required), do not define this rule. - -max_size Yes Fails if the uploaded file is larger ``max_size[field_name,2048]`` - than the second parameter - in kilobytes (kb), or if the file - is larger than the allowed maximum size - declared in the php.ini config file - (``upload_max_filesize`` directive). -max_dims Yes Fails if the maximum width and height of an ``max_dims[field_name,300,150]`` - uploaded image exceed the values. The first - parameter is the field name. The second is - the width, and the third is the height. Will - also fail if the file cannot be determined - to be an image or the upload failed with an - error other than ``UPLOAD_ERR_NO_FILE``. -min_dims Yes Fails if the minimum width and height of an ``min_dims[field_name,300,150]`` - uploaded image do not meet values. The first - parameter is the field name. The second is - the width, and the third is the height. Will - also fail if the file cannot be determined - to be an image or the upload failed with an - error other than ``UPLOAD_ERR_NO_FILE``. - (This rule was added in - v4.6.0.) -mime_in Yes Fails if the file's mime type is not one ``mime_in[field_name,image/png,image/jpeg]`` - listed in the parameters. -ext_in Yes Fails if the client filename's extension is ``ext_in[field_name,png,jpg,gif]`` - not one listed in the parameters, or if the - detected MIME type does not match the MIME - types associated with the extension. -is_image Yes Fails if the file cannot be determined to be ``is_image[field_name]`` - an image based on the mime type. -======================= ========== ============================================= =================================================== - -The file validation rules apply to both single and multiple file uploads. - -The ``is_image``, ``mime_in``, and ``ext_in`` rules check the uploaded file and its client filename, but they cannot -guarantee that a web server will not execute a file saved under that name. See :ref:`uploaded-files-moving-files` for -safe storage practices. diff --git a/user_guide_src/source/libraries/validation/001.php b/user_guide_src/source/libraries/validation/001.php deleted file mode 100644 index e3aad548607f..000000000000 --- a/user_guide_src/source/libraries/validation/001.php +++ /dev/null @@ -1,30 +0,0 @@ -request->is('post')) { - return view('signup'); - } - - $rules = [ - // @TODO - ]; - - $data = $this->request->getPost(array_keys($rules)); - - if (! $this->validateData($data, $rules)) { - return view('signup'); - } - - // If you want to get the validated data. - $validData = $this->validator->getValidated(); - - return view('success'); - } -} diff --git a/user_guide_src/source/libraries/validation/002.php b/user_guide_src/source/libraries/validation/002.php deleted file mode 100644 index b8d5811f356d..000000000000 --- a/user_guide_src/source/libraries/validation/002.php +++ /dev/null @@ -1,12 +0,0 @@ - 'required|max_length[30]', - 'password' => 'required|max_length[255]|min_length[10]', - 'passconf' => 'required|max_length[255]|matches[password]', - 'email' => 'required|max_length[254]|valid_email', -]; - -// ... diff --git a/user_guide_src/source/libraries/validation/003.php b/user_guide_src/source/libraries/validation/003.php deleted file mode 100644 index e83233803e7c..000000000000 --- a/user_guide_src/source/libraries/validation/003.php +++ /dev/null @@ -1,19 +0,0 @@ -setRule('username', 'Username', 'required|max_length[30]|min_length[3]'); -$validation->setRule('password', 'Password', ['required', 'max_length[255]', 'min_length[8]', 'alpha_numeric_punct']); diff --git a/user_guide_src/source/libraries/validation/006.php b/user_guide_src/source/libraries/validation/006.php deleted file mode 100644 index bd4dbf10c787..000000000000 --- a/user_guide_src/source/libraries/validation/006.php +++ /dev/null @@ -1,11 +0,0 @@ -setRules([ - 'username' => 'required|max_length[30]', - 'password' => 'required|max_length[255]|min_length[10]', -]); -// or -$validation->setRules([ - 'username' => ['required', 'max_length[30]'], - 'password' => ['required', 'max_length[255]', 'min_length[10]'], -]); diff --git a/user_guide_src/source/libraries/validation/007.php b/user_guide_src/source/libraries/validation/007.php deleted file mode 100644 index c545e70c8e9c..000000000000 --- a/user_guide_src/source/libraries/validation/007.php +++ /dev/null @@ -1,11 +0,0 @@ -setRules([ - 'username' => ['label' => 'Username', 'rules' => 'required|max_length[30]'], - 'password' => ['label' => 'Password', 'rules' => 'required|max_length[255]|min_length[10]'], -]); -// or -$validation->setRules([ - 'username' => ['label' => 'Username', 'rules' => 'required|max_length[30]'], - 'password' => ['label' => 'Password', 'rules' => ['required', 'max_length[255]', 'min_length[10]']], -]); diff --git a/user_guide_src/source/libraries/validation/008.php b/user_guide_src/source/libraries/validation/008.php deleted file mode 100644 index 68c345e5181e..000000000000 --- a/user_guide_src/source/libraries/validation/008.php +++ /dev/null @@ -1,12 +0,0 @@ -withRequest($request)->run()) { - // If you use the input data, you should get it from the getValidated() method. - // Otherwise you may create a vulnerability. - $validData = $validation->getValidated(); - - // ... -} diff --git a/user_guide_src/source/libraries/validation/009.php b/user_guide_src/source/libraries/validation/009.php deleted file mode 100644 index 85be52b7abb2..000000000000 --- a/user_guide_src/source/libraries/validation/009.php +++ /dev/null @@ -1,23 +0,0 @@ - [ - * 'name' => 'Joe Smith', - * 'friends' => [ - * [ - * 'name' => 'Fred Flinstone', - * ], - * [ - * 'name' => 'Wilma', - * ], - * ] - * ] - * ] - */ - -// Joe Smith -$validation->setRules([ - 'contacts.name' => 'required|max_length[60]', -]); diff --git a/user_guide_src/source/libraries/validation/010.php b/user_guide_src/source/libraries/validation/010.php deleted file mode 100644 index 2646fcc32b99..000000000000 --- a/user_guide_src/source/libraries/validation/010.php +++ /dev/null @@ -1,6 +0,0 @@ -setRules([ - 'contacts.friends.*.name' => 'required|max_length[60]', -]); diff --git a/user_guide_src/source/libraries/validation/011.php b/user_guide_src/source/libraries/validation/011.php deleted file mode 100644 index 9b5e03eb4948..000000000000 --- a/user_guide_src/source/libraries/validation/011.php +++ /dev/null @@ -1,17 +0,0 @@ - [ - * 1, - * 2, - * 3, - * ] - * ] - */ - -// Rule -$validation->setRules([ - 'user_ids.*' => 'required|max_length[19]', -]); diff --git a/user_guide_src/source/libraries/validation/012.php b/user_guide_src/source/libraries/validation/012.php deleted file mode 100644 index 9b9e89c21c87..000000000000 --- a/user_guide_src/source/libraries/validation/012.php +++ /dev/null @@ -1,5 +0,0 @@ -check($value, 'required')) { - // $value is valid. -} diff --git a/user_guide_src/source/libraries/validation/013.php b/user_guide_src/source/libraries/validation/013.php deleted file mode 100644 index b43a32f97d4e..000000000000 --- a/user_guide_src/source/libraries/validation/013.php +++ /dev/null @@ -1,19 +0,0 @@ - 'required|max_length[30]', - 'password' => 'required|max_length[255]', - 'pass_confirm' => 'required|max_length[255]|matches[password]', - 'email' => 'required|max_length[254]|valid_email', - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/validation/014.php b/user_guide_src/source/libraries/validation/014.php deleted file mode 100644 index 1aa5b7f521c0..000000000000 --- a/user_guide_src/source/libraries/validation/014.php +++ /dev/null @@ -1,3 +0,0 @@ -run($data, 'signup'); diff --git a/user_guide_src/source/libraries/validation/015.php b/user_guide_src/source/libraries/validation/015.php deleted file mode 100644 index 6e666e41c35d..000000000000 --- a/user_guide_src/source/libraries/validation/015.php +++ /dev/null @@ -1,28 +0,0 @@ - 'required|max_length[30]', - 'password' => 'required|max_length[255]', - 'pass_confirm' => 'required|max_length[255]|matches[password]', - 'email' => 'required|max_length[254]|valid_email', - ]; - - public array $signup_errors = [ - 'username' => [ - 'required' => 'You must choose a username.', - ], - 'email' => [ - 'valid_email' => 'Please check the Email field. It does not appear to be valid.', - ], - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/validation/016.php b/user_guide_src/source/libraries/validation/016.php deleted file mode 100644 index 1eb72bc8c62f..000000000000 --- a/user_guide_src/source/libraries/validation/016.php +++ /dev/null @@ -1,27 +0,0 @@ - [ - 'rules' => 'required|max_length[30]', - 'errors' => [ - 'required' => 'You must choose a Username.', - ], - ], - 'email' => [ - 'rules' => 'required|max_length[254]|valid_email', - 'errors' => [ - 'valid_email' => 'Please check the Email field. It does not appear to be valid.', - ], - ], - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/validation/017.php b/user_guide_src/source/libraries/validation/017.php deleted file mode 100644 index f84561eb5375..000000000000 --- a/user_guide_src/source/libraries/validation/017.php +++ /dev/null @@ -1,3 +0,0 @@ -getRuleGroup('signup'); diff --git a/user_guide_src/source/libraries/validation/018.php b/user_guide_src/source/libraries/validation/018.php deleted file mode 100644 index 245c4b6932cf..000000000000 --- a/user_guide_src/source/libraries/validation/018.php +++ /dev/null @@ -1,3 +0,0 @@ -setRuleGroup('signup'); diff --git a/user_guide_src/source/libraries/validation/019.php b/user_guide_src/source/libraries/validation/019.php deleted file mode 100644 index bf158323f638..000000000000 --- a/user_guide_src/source/libraries/validation/019.php +++ /dev/null @@ -1,10 +0,0 @@ -reset(); - $validation->setRules($userAccountRules); - - if (! $validation->run($user)) { - // handle validation errors - } -} diff --git a/user_guide_src/source/libraries/validation/020.php b/user_guide_src/source/libraries/validation/020.php deleted file mode 100644 index 792b7ba6bbe9..000000000000 --- a/user_guide_src/source/libraries/validation/020.php +++ /dev/null @@ -1,6 +0,0 @@ -setRules([ - 'id' => 'max_length[19]|is_natural_no_zero', - 'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,{id}]', -]); diff --git a/user_guide_src/source/libraries/validation/021.php b/user_guide_src/source/libraries/validation/021.php deleted file mode 100644 index fa1b37d0f839..000000000000 --- a/user_guide_src/source/libraries/validation/021.php +++ /dev/null @@ -1,6 +0,0 @@ - 4, - 'email' => 'foo@example.com', -]; diff --git a/user_guide_src/source/libraries/validation/022.php b/user_guide_src/source/libraries/validation/022.php deleted file mode 100644 index f3dda9e966df..000000000000 --- a/user_guide_src/source/libraries/validation/022.php +++ /dev/null @@ -1,6 +0,0 @@ -setRules([ - 'id' => 'max_length[19]|is_natural_no_zero', - 'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,4]', -]); diff --git a/user_guide_src/source/libraries/validation/023.php b/user_guide_src/source/libraries/validation/023.php deleted file mode 100644 index eaea12a57c7d..000000000000 --- a/user_guide_src/source/libraries/validation/023.php +++ /dev/null @@ -1,16 +0,0 @@ -setRules( - [ - 'username' => 'required|max_length[30]|is_unique[users.username]', - 'password' => 'required|max_length[254]|min_length[10]', - ], - [ // Errors - 'username' => [ - 'required' => 'All accounts must have usernames provided', - ], - 'password' => [ - 'min_length' => 'Your password is too short. You want to get hacked?', - ], - ], -); diff --git a/user_guide_src/source/libraries/validation/024.php b/user_guide_src/source/libraries/validation/024.php deleted file mode 100644 index a8fb8151d6d4..000000000000 --- a/user_guide_src/source/libraries/validation/024.php +++ /dev/null @@ -1,18 +0,0 @@ -setRules([ - 'username' => [ - 'label' => 'Username', - 'rules' => 'required|max_length[30]|is_unique[users.username]', - 'errors' => [ - 'required' => 'All accounts must have {field} provided', - ], - ], - 'password' => [ - 'label' => 'Password', - 'rules' => 'required|max_length[255]|min_length[10]', - 'errors' => [ - 'min_length' => 'Your {field} is too short. You want to get hacked?', - ], - ], -]); diff --git a/user_guide_src/source/libraries/validation/025.php b/user_guide_src/source/libraries/validation/025.php deleted file mode 100644 index 60f53893edce..000000000000 --- a/user_guide_src/source/libraries/validation/025.php +++ /dev/null @@ -1,18 +0,0 @@ -setRules([ - 'username' => [ - 'label' => 'Rules.username', - 'rules' => 'required|max_length[30]|is_unique[users.username]', - 'errors' => [ - 'required' => 'Rules.username.required', - ], - ], - 'password' => [ - 'label' => 'Rules.password', - 'rules' => 'required|max_length[255]|min_length[10]', - 'errors' => [ - 'min_length' => 'Rules.password.min_length', - ], - ], -]); diff --git a/user_guide_src/source/libraries/validation/026.php b/user_guide_src/source/libraries/validation/026.php deleted file mode 100644 index 4488f2a6be57..000000000000 --- a/user_guide_src/source/libraries/validation/026.php +++ /dev/null @@ -1,10 +0,0 @@ -getErrors(); -/* - * Produces: - * [ - * 'field1' => 'error message', - * 'field2' => 'error message', - * ] - */ diff --git a/user_guide_src/source/libraries/validation/027.php b/user_guide_src/source/libraries/validation/027.php deleted file mode 100644 index 2a3cffba88fc..000000000000 --- a/user_guide_src/source/libraries/validation/027.php +++ /dev/null @@ -1,3 +0,0 @@ -getError('username'); diff --git a/user_guide_src/source/libraries/validation/028.php b/user_guide_src/source/libraries/validation/028.php deleted file mode 100644 index 2334c3c00f50..000000000000 --- a/user_guide_src/source/libraries/validation/028.php +++ /dev/null @@ -1,5 +0,0 @@ -hasError('username')) { - echo $validation->getError('username'); -} diff --git a/user_guide_src/source/libraries/validation/029.php b/user_guide_src/source/libraries/validation/029.php deleted file mode 100644 index 5470a1eecea6..000000000000 --- a/user_guide_src/source/libraries/validation/029.php +++ /dev/null @@ -1,12 +0,0 @@ - 'Error', - * 'foo.baz.bar' => 'Error', - * ] - */ - -// returns true -$validation->hasError('foo.*.bar'); diff --git a/user_guide_src/source/libraries/validation/030.php b/user_guide_src/source/libraries/validation/030.php deleted file mode 100644 index 86e4aaf85583..000000000000 --- a/user_guide_src/source/libraries/validation/030.php +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/user_guide_src/source/libraries/validation/031.php b/user_guide_src/source/libraries/validation/031.php deleted file mode 100644 index abac67b15dec..000000000000 --- a/user_guide_src/source/libraries/validation/031.php +++ /dev/null @@ -1,6 +0,0 @@ - 'The username field must be unique.', - 'email' => 'You must provide a valid email address.', -]; diff --git a/user_guide_src/source/libraries/validation/032.php b/user_guide_src/source/libraries/validation/032.php deleted file mode 100644 index cf8bcf8b9bdc..000000000000 --- a/user_guide_src/source/libraries/validation/032.php +++ /dev/null @@ -1,18 +0,0 @@ - 'CodeIgniter\Validation\Views\list', - 'single' => 'CodeIgniter\Validation\Views\single', - 'my_list' => '_errors_list', - ]; - - // ... -} diff --git a/user_guide_src/source/libraries/validation/033.php b/user_guide_src/source/libraries/validation/033.php deleted file mode 100644 index aa67529ba959..000000000000 --- a/user_guide_src/source/libraries/validation/033.php +++ /dev/null @@ -1,23 +0,0 @@ -setRules([ - 'foo' => 'required|max_length[19]|even', -]); diff --git a/user_guide_src/source/libraries/validation/037.php b/user_guide_src/source/libraries/validation/037.php deleted file mode 100644 index 1a05b912d397..000000000000 --- a/user_guide_src/source/libraries/validation/037.php +++ /dev/null @@ -1,35 +0,0 @@ -required($value ?? ''); - - if ($present) { - return true; - } - - // Still here? Then we fail this test if - // any of the fields are present in $data - // as $fields in the list - $requiredFields = []; - - foreach ($params as $field) { - if (array_key_exists($field, $data)) { - $requiredFields[] = $field; - } - } - - // Remove any keys with empty values since, that means they - // weren't truly there, as far as this is concerned. - $requiredFields = array_filter($requiredFields, static fn ($item) => ! empty($data[$item])); - - return empty($requiredFields); - } -} diff --git a/user_guide_src/source/libraries/validation/038.php b/user_guide_src/source/libraries/validation/038.php deleted file mode 100644 index 1330267ebfce..000000000000 --- a/user_guide_src/source/libraries/validation/038.php +++ /dev/null @@ -1,12 +0,0 @@ -setRules([ - 'name' => "max_length[36]|is_unique[supplier.name,uuid, {$uuid}]", // is not ok - 'name' => "max_length[36]|is_unique[supplier.name,uuid,{$uuid} ]", // is not ok - 'name' => "max_length[36]|is_unique[supplier.name,uuid,{$uuid}]", // is ok - 'name' => 'max_length[36]|is_unique[supplier.name,uuid,{uuid}]', // is ok - see "Validation Placeholders" -]); -// Warning: If `$uuid` is a user input, be sure to validate the format of the value before using it. -// Otherwise, it is vulnerable. diff --git a/user_guide_src/source/libraries/validation/039.php b/user_guide_src/source/libraries/validation/039.php deleted file mode 100644 index 041e8a782240..000000000000 --- a/user_guide_src/source/libraries/validation/039.php +++ /dev/null @@ -1,8 +0,0 @@ -get('form', 'Form::index'); -$routes->post('form', 'Form::index'); - -// ... diff --git a/user_guide_src/source/libraries/validation/040.php b/user_guide_src/source/libraries/validation/040.php deleted file mode 100644 index e73f1feca62c..000000000000 --- a/user_guide_src/source/libraries/validation/040.php +++ /dev/null @@ -1,21 +0,0 @@ -setRules( - [ - 'foo' => [ - 'required', - static fn ($value) => (int) $value % 2 === 0, - ], - ], - [ - // Errors - 'foo' => [ - // Specify the array key for the closure rule. - 1 => 'The value is not even.', - ], - ], -); - -if (! $validation->run($data)) { - // handle validation errors -} diff --git a/user_guide_src/source/libraries/validation/041.php b/user_guide_src/source/libraries/validation/041.php deleted file mode 100644 index bb8e4085632e..000000000000 --- a/user_guide_src/source/libraries/validation/041.php +++ /dev/null @@ -1,16 +0,0 @@ -setRules([ - 'foo' => [ - 'required', - static function ($value, $data, &$error, $field) { - if ((int) $value % 2 === 0) { - return true; - } - - $error = 'The value is not even.'; - - return false; - }, - ], -]); diff --git a/user_guide_src/source/libraries/validation/042.php b/user_guide_src/source/libraries/validation/042.php deleted file mode 100644 index 057364b4fe7a..000000000000 --- a/user_guide_src/source/libraries/validation/042.php +++ /dev/null @@ -1,6 +0,0 @@ -validateData($data, $rules)) { - return redirect()->back()->withInput(); -} diff --git a/user_guide_src/source/libraries/validation/043.php b/user_guide_src/source/libraries/validation/043.php deleted file mode 100644 index 5700734ce975..000000000000 --- a/user_guide_src/source/libraries/validation/043.php +++ /dev/null @@ -1,9 +0,0 @@ -run($data)) { - // handle validation errors -} -// or -if (! $validation->run($data, 'signup')) { - // handle validation errors -} diff --git a/user_guide_src/source/libraries/validation/044.php b/user_guide_src/source/libraries/validation/044.php deleted file mode 100644 index df2598d1906c..000000000000 --- a/user_guide_src/source/libraries/validation/044.php +++ /dev/null @@ -1,21 +0,0 @@ -setRules([ - 'username' => 'required', - 'password' => 'required|min_length[10]', -]); - -$data = [ - 'username' => 'john', - 'password' => 'BPi-$Swu7U5lm$dX', - 'csrf_token' => '8b9218a55906f9dcc1dc263dce7f005a', -]; - -if ($validation->run($data)) { - $validatedData = $validation->getValidated(); - // $validatedData = [ - // 'username' => 'john', - // 'password' => 'BPi-$Swu7U5lm$dX', - // ]; -} diff --git a/user_guide_src/source/libraries/validation/045.php b/user_guide_src/source/libraries/validation/045.php deleted file mode 100644 index 401897f0e927..000000000000 --- a/user_guide_src/source/libraries/validation/045.php +++ /dev/null @@ -1,18 +0,0 @@ -validateData($data, [ - 'username' => 'required', - 'password' => 'required|min_length[10]', -])) { - // The validation failed. - return view('login', [ - 'errors' => $this->validator->getErrors(), - ]); -} - -// The validation was successful. - -// Get the validated data. -$validData = $this->validator->getValidated(); diff --git a/user_guide_src/source/libraries/validation/046.php b/user_guide_src/source/libraries/validation/046.php deleted file mode 100644 index d9c244cdf31e..000000000000 --- a/user_guide_src/source/libraries/validation/046.php +++ /dev/null @@ -1,41 +0,0 @@ -setRules( - [ - 'foo' => [ - 'required', - // Specify the method in this controller as a rule. - [$this, '_ruleEven'], - ], - ], - [ - // Errors - 'foo' => [ - // Specify the array key for the callable rule. - 1 => 'The value is not even.', - ], - ], - ); - - if (! $validation->run($data)) { - // handle validation errors - } - - // ... - } -} diff --git a/user_guide_src/source/libraries/validation/047.php b/user_guide_src/source/libraries/validation/047.php deleted file mode 100644 index 6c2bb674f800..000000000000 --- a/user_guide_src/source/libraries/validation/047.php +++ /dev/null @@ -1,22 +0,0 @@ -` if that -fits your needs better. - -.. contents:: - :local: - :depth: 2 - -************ -Entity Usage -************ - -At its core, an Entity class is simply a class that represents a single database row. It has class properties to -represent the database columns, and provides any additional methods to implement the business logic for that row. - -.. note:: For ease of understanding, the explanation here is based on the case of using a database. However, Entity can - also be used for data that does not come from a database. - -The core feature, though, is that it doesn't know anything about how to persist itself. That's the responsibility of the -model or the repository class. That way, if anything changes in how you need to save the object, you don't have to -change how that object is used throughout the application. - -This makes it possible to use JSON or XML files to store the objects during a rapid prototyping stage, and then easily -switch to a database when you've proven the concept works. - -Let's walk through a very simple User Entity and how we'd work with it to help make things clear. - -Assume you have a database table named ``users`` that has the following schema:: - - id - integer - username - string - email - string - password - string - created_at - datetime - -Create the Entity Class -======================= - -Now create a new Entity class. Since there's no default location to store these classes, and it doesn't fit in with the -existing directory structure, create a new directory at **app/Entities**. Create the Entity itself at -**app/Entities/User.php**. - -.. literalinclude:: entities/001.php - -At its simplest, this is all you need to do, though we'll make it more useful in a minute. - -Create the Model -================ - -Create the model first at **app/Models/UserModel.php** so that we can interact with it: - -.. literalinclude:: entities/002.php - -The model uses the ``users`` table in the database for all of its activities. - -We've set the ``$allowedFields`` property to include all of the fields that we want outside classes to change. The -``id``, ``created_at``, and ``updated_at`` fields are handled automatically by the class or the database, so we don't -want to change those. - -Finally, we've set our Entity class as the ``$returnType``. This ensures that all built-in methods on the model that -return rows from the database will return instances of our User Entity class instead of an object or array like normal. - -.. note:: - Of course, if you add a custom method to your model, you must implement it so that instances of ``$returnType`` are - returned. - -Working with the Entity Class -============================= - -Now that all of the pieces are in place, you would work with the Entity class as you would any other class: - -.. literalinclude:: entities/003.php - -You may have noticed that the ``User`` class has not set any properties for the columns, but you can still access them -as if they were public properties. The base class, ``CodeIgniter\Entity\Entity``, takes care of this for you, as well as -providing the ability to check the properties with ``isset()``, ``unset()`` them, and keep track of what columns have -changed since the object was created or pulled from the database. - -.. note:: The Entity class stores the data in the class property ``$attributes`` internally. - -When the User is passed to the model's ``save()`` method, it automatically takes care of reading the properties and -saving any changes to columns listed in the model's ``$allowedFields`` property. It also knows whether to create a new -row, or update an existing one. - -.. note:: When we call the ``insert()`` method, all the values from the Entity are passed to the method, but when we - call the ``update()`` method, only the values that have changed are passed. - -Filling Properties Quickly -========================== - -The Entity class also provides a method, ``fill()``, that allows you to shove an array of key/value pairs into the class -and populate the class properties. Any property in the array will be set on the Entity. However, when saving through the -model, only the fields in ``$allowedFields`` will actually be saved to the database, so you can store additional data on -your entities without worrying much about stray fields getting saved incorrectly. - -.. literalinclude:: entities/004.php - -You can also pass the data in the constructor and the data will be passed through the ``fill()`` method during -instantiation. - -.. literalinclude:: entities/005.php - -Bulk Accessing Properties -========================= - -The Entity class has two methods to extract all available properties into an array: ``toArray()`` and ``toRawArray()``. -Using the raw version will bypass magic "getter" methods and casts. Both methods can take a boolean first parameter to -specify whether returned values should be filtered by those that have changed, and a boolean final parameter to make the -method recursive, in case of nested Entities. - -Hidden properties -================= - -An Entity may have hidden attributes - their names start with an underscore (``_``). By default, these hidden properties -are not included when you call ``toArray()``. However, you can still access them directly if needed. - -If you want hidden properties to appear in the ``toArray()`` output, you'll need to use the ``datamap`` feature - it -makes those properties "visible". - -Keep in mind that the smart ``__get()`` and ``__set()`` methods (described in the next section) ignore leading -underscores in property names. This means that two attributes with the same name (one starting with ``_`` and one -without) will both use the same getter and setter, so you have to choose which one to handle by default. - -.. literalinclude:: entities/028.php - -*********************** -Handling Business Logic -*********************** - -While the examples above are convenient, they don't help enforce any business logic. The base Entity class implements -some smart ``__get()`` and ``__set()`` methods that will check for special methods and use those instead of using the -attributes directly, allowing you to enforce any business logic or data conversion that you need. - -Here's an updated User entity to provide some examples of how this could be used: - -.. literalinclude:: entities/006.php - -The first thing to notice is the name of the methods we've added. For each one, the class expects the snake_case column -name to be converted into PascalCase, and prefixed with either ``set`` or ``get``. These methods will then be -automatically called whenever you set or retrieve the class property using the direct syntax (i.e., ``$user->email``). -The methods do not need to be public unless you want them accessed from other classes. For example, the ``created_at`` -class property will be accessed through the ``setCreatedAt()`` and ``getCreatedAt()`` methods. - -.. note:: This only works when trying to access the properties from outside of the class. Any methods internal to the - class must call the ``setX()`` and ``getX()`` methods directly. - -In the ``setPassword()`` method we ensure that the password is always hashed. - -In ``setCreatedAt()`` we convert the string we receive from the model into a DateTime object, ensuring that our timezone -is UTC so we can easily convert to the viewer's current timezone. In ``getCreatedAt()``, it converts the time to a -formatted string in the application's current timezone. - -While fairly simple, these examples show that using Entity classes can provide a very flexible way to enforce business -logic and create objects that are pleasant to use. - -.. literalinclude:: entities/007.php - -.. _entities-special-getter-setter: - -Special Getter/Setter -===================== - -.. versionadded:: 4.4.0 - -For example, if your Entity's parent class already has a ``getParent()`` method defined, and your Entity also has a -column named ``parent``, when you try to add business logic to the ``getParent()`` method in your Entity class, the -method is already defined. - -In such a case, you can use the special getter/setter. Instead of ``getX()``/``setX()``, set ``_getX()``/``_setX()``. - -In the above example, if your Entity has the ``_getParent()`` method, the method will be used when you get -``$entity->parent``, and the ``_setParent()`` method will be used when you set ``$entity->parent``. - -************ -Data Mapping -************ - -At many points in your career, you will run into situations where the use of an application has changed and the original -column names in the database no longer make sense. Or you find that your coding style prefers camelCase class -properties, but your database schema requires snake_case names. These situations can be easily handled with the Entity -class' data mapping features. - -As an example, imagine you have the simplified User Entity that is used throughout your application: - -.. literalinclude:: entities/008.php - -Your boss comes to you and says that no one uses usernames anymore, so you're switching to just use emails for login. -But they do want to personalize the application a bit, so they want you to change the ``name`` field to represent a -user's full name now, not their username like it does currently. To keep things tidy and ensure things continue making -sense in the database, you whip up a migration to rename the ``name`` field to ``full_name`` for clarity. - -Ignoring how contrived this example is, we now have two choices on how to fix the User class. We could modify the class -property from ``$name`` to ``$full_name``, but that would require changes throughout the application. Instead, we can -simply map the ``full_name`` column in the database to the ``$name`` property, and be done with the Entity changes: - -.. literalinclude:: entities/009.php - -By adding our new database name to the ``$datamap`` array, we can tell the class what class property the database column -should be accessible through. The key of the array is the class property to map it to, and the value in the array is the -name of the column in the database. - -In this example, when the model sets the ``full_name`` field on the User class, it actually assigns that value to the -class' ``$name`` property, so it can be set and retrieved through ``$user->name``. The value will also still be -accessible through the original ``$user->full_name``, as this is needed for the model to get the data back out and save -it to the database. However, ``unset()`` and ``isset()`` only work on the mapped property, ``$user->name``, not on the -database column name, ``$user->full_name``. - -.. note:: When you use Data Mapping, you must define ``set*()`` and ``get*()`` methods for the database column name. In - this example, you must define ``setFullName()`` and ``getFullName()``. - -******** -Mutators -******** - -Date Mutators -============= - -By default, the Entity class will convert fields named ``created_at``, ``updated_at``, or ``deleted_at`` into -:doc:`Time ` instances whenever they are set or retrieved. The Time class provides a large number of -helpful methods in an immutable, localized way. - -You can define which properties are automatically converted by adding the name to the ``$dates`` property: - -.. literalinclude:: entities/010.php - -Now, when any of those properties are set, they will be converted to a Time instance, using the application's current -timezone, as set in **app/Config/App.php**: - -.. literalinclude:: entities/011.php - -.. _entities-property-casting: - -Property Casting -================ - -You can specify that properties in your Entity should be converted to common data types with the ``$casts`` property. -This option should be an array where the key is the name of the class property, and the value is the data type it should -be cast to. - -Property casting affects both read (get) and write (set), but some types affect only read (get). - -Scalar Type Casting -------------------- - -Properties can be cast to any of the following data types: **integer**, **float**, **double**, **string**, **boolean**, -**object**, **array**, **datetime**, **timestamp**, **uri**, **int-bool** and **enum**. Add a question mark at the -beginning of the type to mark the property as nullable, i.e., **?string**, **?integer**. - -.. note:: **int-bool** can be used since v4.3.0. - -.. note:: **enum** can be used since v4.7.0. - -For example, if you had a User entity with an ``is_banned`` property, you can cast it as a boolean: - -.. literalinclude:: entities/012.php - -Array/Json Casting ------------------- - -Array/Json casting is especially useful with fields that store serialized arrays or JSON. When you read the property's -value: - -* with the **array** cast, the value is automatically unserialized. -* with the **json** cast, the value is automatically converted with ``json_decode($value, false)``. -* with the **json-array** cast, the value is automatically converted with ``json_decode($value, true)``. - -Unlike the rest of the data types that you can cast properties into, these cast types also convert the value whenever -the property is set: - -* the **array** cast serializes the value. -* the **json** and **json-array** casts use ``json_encode()`` on the value. - -.. literalinclude:: entities/013.php - -.. literalinclude:: entities/014.php - -.. warning:: The ``array`` cast uses PHP serialization. Only read values previously written through the same Entity - cast. Never store untrusted serialized strings directly in an ``array``-cast field. - -CSV Casting ------------ - -If you know you have a flat array of simple values, encoding them as a serialized or JSON string may be more complex -than the original structure. Casting as Comma-Separated Values (CSV) is a simpler alternative that will result in a -string that uses less space and is more easily read by humans: - -.. literalinclude:: entities/015.php - -Stored in the database as "red,yellow,green": - -.. literalinclude:: entities/016.php - -.. note:: Casting as CSV uses PHP's internal ``implode`` and ``explode`` methods and assumes all values are string-safe - and free of commas. For more complex data casts try ``array`` or ``json``. - -Enum Casting ------------- - -.. versionadded:: 4.7.0 - -You can cast properties to PHP enums. You must specify the enum class name as a parameter. - -Enum casting supports: - -* **Backed enums** (string or int) - The backing value is stored in the database -* **Unit enums** - The case name is stored in the database as a string - -For example, if you had a User entity with a ``status`` property using a backed enum: - -.. literalinclude:: entities/024.php - -You can cast it in your Entity: - -.. literalinclude:: entities/025.php - -Now, when you access the ``status`` property, it will automatically be converted to a ``UserStatus`` enum instance: - -.. literalinclude:: entities/026.php - -For nullable enums: - -.. literalinclude:: entities/027.php - -Custom Casting --------------- - -You can define your own conversion types for getting and setting data. - -First, you need to create a handler class for your type. Let's say the class will be located in the -**app/Entities/Cast** directory: - -.. literalinclude:: entities/017.php - -Now you need to register it: - -.. literalinclude:: entities/018.php - -If you don't need to change values when getting or setting a value, just don't implement the appropriate method: - -.. literalinclude:: entities/019.php - -Parameters ----------- - -In some cases, one type is not enough. In this situation, you can use additional parameters. Additional parameters are -indicated in square brackets and listed with a comma like ``type[param1, param2]``. - -.. literalinclude:: entities/020.php - -.. literalinclude:: entities/021.php - -.. note:: If the casting type is marked as nullable like ``?bool`` and the passed value is not null, then the parameter - with the value ``nullable`` will be passed to the casting type handler. If the casting type has predefined - parameters, then ``nullable`` will be added to the end of the list. - -******************************* -Checking for Changed Attributes -******************************* - -You can check if an Entity attribute has changed since it was created. The only parameter is the name of the attribute -to check: - -.. literalinclude:: entities/022.php - -Or, to check the whole entity for changed values, omit the parameter: - -.. literalinclude:: entities/023.php - -Deep Change Tracking -==================== - -.. versionadded:: 4.7.0 - -The Entity class performs **deep comparison** for objects and arrays to accurately detect changes in their internal -state. - -Scalar Values -------------- - -For scalar values (strings, integers, floats, booleans, null), the Entity uses direct comparison. When all attributes in -an Entity are scalars, an optimized comparison is used for better performance. - -Objects and Arrays ------------------- - -For objects and arrays, the Entity JSON-encodes and normalizes the values for comparison. This means that modifications -to nested structures, object properties, array elements, nested entities (using ``toRawArray()``), enums (``BackedEnum`` -and ``UnitEnum``), datetime objects (``DateTimeInterface``), collections (``Traversable``), value objects with -``__toString()``, and objects implementing ``JsonSerializable`` or ``toArray()`` will be properly detected. diff --git a/user_guide_src/source/models/entities/001.php b/user_guide_src/source/models/entities/001.php deleted file mode 100644 index 2da022b25edd..000000000000 --- a/user_guide_src/source/models/entities/001.php +++ /dev/null @@ -1,10 +0,0 @@ -find($id); - -// Display -echo $user->username; -echo $user->email; - -// Updating -unset($user->username); - -if (! isset($user->username)) { - $user->username = 'something new'; -} - -$userModel->save($user); - -// Create -$user = new \App\Entities\User(); -$user->username = 'foo'; -$user->email = 'foo@example.com'; -$userModel->save($user); diff --git a/user_guide_src/source/models/entities/004.php b/user_guide_src/source/models/entities/004.php deleted file mode 100644 index e5307d38b1a2..000000000000 --- a/user_guide_src/source/models/entities/004.php +++ /dev/null @@ -1,7 +0,0 @@ -request->getPost(); - -$user = new \App\Entities\User(); -$user->fill($data); -$userModel->save($user); diff --git a/user_guide_src/source/models/entities/005.php b/user_guide_src/source/models/entities/005.php deleted file mode 100644 index 5dd5d47af1f5..000000000000 --- a/user_guide_src/source/models/entities/005.php +++ /dev/null @@ -1,6 +0,0 @@ -request->getPost(); - -$user = new \App\Entities\User($data); -$userModel->save($user); diff --git a/user_guide_src/source/models/entities/006.php b/user_guide_src/source/models/entities/006.php deleted file mode 100644 index 0a271a37a73d..000000000000 --- a/user_guide_src/source/models/entities/006.php +++ /dev/null @@ -1,35 +0,0 @@ -attributes['password'] = password_hash($pass, PASSWORD_BCRYPT); - - return $this; - } - - public function setCreatedAt(string $dateString) - { - $this->attributes['created_at'] = new Time($dateString, 'UTC'); - - return $this; - } - - public function getCreatedAt(string $format = 'Y-m-d H:i:s') - { - // Convert to CodeIgniter\I18n\Time object - $this->attributes['created_at'] = $this->mutateDate($this->attributes['created_at']); - - $timezone = $this->timezone ?? app_timezone(); - - $this->attributes['created_at']->setTimezone($timezone); - - return $this->attributes['created_at']->format($format); - } -} diff --git a/user_guide_src/source/models/entities/007.php b/user_guide_src/source/models/entities/007.php deleted file mode 100644 index 36a39a017e43..000000000000 --- a/user_guide_src/source/models/entities/007.php +++ /dev/null @@ -1,5 +0,0 @@ -password = 'my great password'; -$user->setPassword('my great password'); diff --git a/user_guide_src/source/models/entities/008.php b/user_guide_src/source/models/entities/008.php deleted file mode 100644 index f0612ce0e4b9..000000000000 --- a/user_guide_src/source/models/entities/008.php +++ /dev/null @@ -1,17 +0,0 @@ - null, - 'name' => null, // Represents a username - 'email' => null, - 'password' => null, - 'created_at' => null, - 'updated_at' => null, - ]; -} diff --git a/user_guide_src/source/models/entities/009.php b/user_guide_src/source/models/entities/009.php deleted file mode 100644 index 772cb6509d38..000000000000 --- a/user_guide_src/source/models/entities/009.php +++ /dev/null @@ -1,22 +0,0 @@ - null, - 'full_name' => null, // In the $attributes, the key is the db column name - 'email' => null, - 'password' => null, - 'created_at' => null, - 'updated_at' => null, - ]; - - protected $datamap = [ - // property_name => db_column_name - 'name' => 'full_name', - ]; -} diff --git a/user_guide_src/source/models/entities/010.php b/user_guide_src/source/models/entities/010.php deleted file mode 100644 index e8636fa0fbcc..000000000000 --- a/user_guide_src/source/models/entities/010.php +++ /dev/null @@ -1,10 +0,0 @@ -created_at = 'April 15, 2017 10:30:00'; - -// Can now use any Time methods: -echo $user->created_at->humanize(); -echo $user->created_at->setTimezone('Europe/London')->toDateString(); diff --git a/user_guide_src/source/models/entities/012.php b/user_guide_src/source/models/entities/012.php deleted file mode 100644 index 0c14d2f822c6..000000000000 --- a/user_guide_src/source/models/entities/012.php +++ /dev/null @@ -1,13 +0,0 @@ - 'boolean', - 'is_banned_nullable' => '?boolean', - ]; -} diff --git a/user_guide_src/source/models/entities/013.php b/user_guide_src/source/models/entities/013.php deleted file mode 100644 index 460f42435304..000000000000 --- a/user_guide_src/source/models/entities/013.php +++ /dev/null @@ -1,14 +0,0 @@ - 'array', - 'options_object' => 'json', - 'options_array' => 'json-array', - ]; -} diff --git a/user_guide_src/source/models/entities/014.php b/user_guide_src/source/models/entities/014.php deleted file mode 100644 index 0a6523818e5c..000000000000 --- a/user_guide_src/source/models/entities/014.php +++ /dev/null @@ -1,9 +0,0 @@ -find(15); -$options = $user->options; - -$options['foo'] = 'bar'; - -$user->options = $options; -$userModel->save($user); diff --git a/user_guide_src/source/models/entities/015.php b/user_guide_src/source/models/entities/015.php deleted file mode 100644 index 079797096bec..000000000000 --- a/user_guide_src/source/models/entities/015.php +++ /dev/null @@ -1,12 +0,0 @@ - 'csv', - ]; -} diff --git a/user_guide_src/source/models/entities/016.php b/user_guide_src/source/models/entities/016.php deleted file mode 100644 index 739ab9f3237a..000000000000 --- a/user_guide_src/source/models/entities/016.php +++ /dev/null @@ -1,3 +0,0 @@ -colors = ['red', 'yellow', 'green']; diff --git a/user_guide_src/source/models/entities/017.php b/user_guide_src/source/models/entities/017.php deleted file mode 100644 index cfbd01207678..000000000000 --- a/user_guide_src/source/models/entities/017.php +++ /dev/null @@ -1,19 +0,0 @@ - 'base64', - ]; - - // Bind the type to the handler - protected $castHandlers = [ - 'base64' => Cast\CastBase64::class, - ]; -} - -// ... - -$entity->key = 'test'; // dGVzdA== -echo $entity->key; // test diff --git a/user_guide_src/source/models/entities/019.php b/user_guide_src/source/models/entities/019.php deleted file mode 100644 index d05789504a66..000000000000 --- a/user_guide_src/source/models/entities/019.php +++ /dev/null @@ -1,13 +0,0 @@ - 'class[App\SomeClass, param2, param3]', - ]; - - // Bind the type to the handler - protected $castHandlers = [ - 'class' => 'SomeHandler', - ]; -} diff --git a/user_guide_src/source/models/entities/021.php b/user_guide_src/source/models/entities/021.php deleted file mode 100644 index 1ea3a26de623..000000000000 --- a/user_guide_src/source/models/entities/021.php +++ /dev/null @@ -1,24 +0,0 @@ - - * string(13) "App\SomeClass" - * [1]=> - * string(6) "param2" - * [2]=> - * string(6) "param3" - * } - */ - } -} diff --git a/user_guide_src/source/models/entities/022.php b/user_guide_src/source/models/entities/022.php deleted file mode 100644 index 07dc560038a3..000000000000 --- a/user_guide_src/source/models/entities/022.php +++ /dev/null @@ -1,7 +0,0 @@ -hasChanged('name'); // false - -$user->name = 'Fred'; -$user->hasChanged('name'); // true diff --git a/user_guide_src/source/models/entities/023.php b/user_guide_src/source/models/entities/023.php deleted file mode 100644 index 1e336bcf9d3c..000000000000 --- a/user_guide_src/source/models/entities/023.php +++ /dev/null @@ -1,3 +0,0 @@ -hasChanged(); // true diff --git a/user_guide_src/source/models/entities/024.php b/user_guide_src/source/models/entities/024.php deleted file mode 100644 index c5730ea04b99..000000000000 --- a/user_guide_src/source/models/entities/024.php +++ /dev/null @@ -1,10 +0,0 @@ - 'enum[App\Enums\UserStatus]', - ]; -} diff --git a/user_guide_src/source/models/entities/026.php b/user_guide_src/source/models/entities/026.php deleted file mode 100644 index d289af310151..000000000000 --- a/user_guide_src/source/models/entities/026.php +++ /dev/null @@ -1,17 +0,0 @@ -find(1); - -// Returns a UserStatus enum instance -echo $user->status->value; // 'active' - -// Set using enum -$user->status = UserStatus::Inactive; - -// Or set using the backing value (will be converted to enum on read) -$user->status = 'pending'; - -// Note: Internally, enums are always stored as their backing value (string/int) -// in the entity's $attributes array diff --git a/user_guide_src/source/models/entities/027.php b/user_guide_src/source/models/entities/027.php deleted file mode 100644 index 15f88f7b5e61..000000000000 --- a/user_guide_src/source/models/entities/027.php +++ /dev/null @@ -1,12 +0,0 @@ - '?enum[App\Enums\UserStatus]', - ]; -} diff --git a/user_guide_src/source/models/entities/028.php b/user_guide_src/source/models/entities/028.php deleted file mode 100644 index c45bbb8597c5..000000000000 --- a/user_guide_src/source/models/entities/028.php +++ /dev/null @@ -1,41 +0,0 @@ - '_role', - ]; - - protected $attributes = [ - '__secure' => 'On', - '_role' => 'user', - 'about' => '', - ]; -} - -$user = new User(['__secure' => 'Off', 'about' => 'Hi, I am John!', '_role' => 'admin']); - -echo 'Secure: ' . $user->__secure; -print_r($user->toArray()); -print_r($user->toRawArray()); - -/** - * Output: - * - * Secure: Off - * Array - * ( - * [about] => Hi, I am John! - * [_role] => admin - * ) - * Array - * ( - * [__secure] => Off - * [_role] => admin - * [about] => Hi, I am John! - * ) - */ diff --git a/user_guide_src/source/models/index.rst b/user_guide_src/source/models/index.rst deleted file mode 100644 index b43776b4b8f3..000000000000 --- a/user_guide_src/source/models/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -############# -Modeling Data -############# - -CodeIgniter comes with rich tools for modeling and working with your database tables and records. - -.. toctree:: - :titlesonly: - - Using CodeIgniter's Model - Using Entity Classes diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst deleted file mode 100644 index c6a90fb488ce..000000000000 --- a/user_guide_src/source/models/model.rst +++ /dev/null @@ -1,1071 +0,0 @@ -######################### -Using CodeIgniter's Model -######################### - -.. contents:: - :local: - :depth: 3 - -Models -****** - -CodeIgniter's Model provides convenience features and additional functionality that people commonly use to make working -with a **single table** in your database more convenient. - -It comes out of the box with helper methods for many of the standard ways you would need to interact with a database -table, including finding records, updating records, deleting records, and more. - -.. _accessing-models: - -Accessing Models -**************** - -Models are typically stored in the **app/Models** directory. They should have a namespace that matches their location -within the directory, like ``namespace App\Models``. - -You can access models within your classes by creating a new instance or using the :php:func:`model()` helper function. - -.. literalinclude:: model/001.php - -The ``model()`` function uses ``Factories::models()`` internally. See :ref:`factories-loading-class` for details on the -first parameter. - -CodeIgniter's Model -******************* - -CodeIgniter does provide a model class that has a few nice features, including: - -- automatic database connection -- basic CRUD methods -- :ref:`in-model validation ` -- :ref:`automatic pagination ` -- and more - -This class provides a solid base from which to build your own models, allowing you to rapidly build out your -application's model layer. - -Creating Your Model -******************* - -To take advantage of CodeIgniter's model, you would simply create a new model class that extends ``CodeIgniter\Model``: - -.. literalinclude:: model/002.php - -This empty class provides convenient access to the database connection, the Query Builder, and a number of additional -convenience methods. - -initialize() -============ - -Should you need additional setup in your model, you may extend the ``initialize()`` method, which will be run -immediately after the Model's constructor. This allows you to perform extra steps without repeating the constructor -parameters, for example extending other models: - -.. literalinclude:: model/003.php - -Connecting to the Database -========================== - -When the class is first instantiated, if no database connection instance is passed to the constructor, and if you don't -set the ``$DBGroup`` property on your model class, it will automatically connect to the default database group, as set -in the database configuration. - -You can modify which group is used on a per-model basis by adding the ``$DBGroup`` property to your class. This ensures -that within the model any references to ``$this->db`` are made through the appropriate connection. - -.. literalinclude:: model/004.php - -You would replace "group_name" with the name of a defined database group from the database configuration file. - -Configuring Your Model -====================== - -The model class has some configuration options that can be set to allow the class' methods to work seamlessly for you. -The first two are used by all of the CRUD methods to determine what table to use and how we can find the required -records: - -.. literalinclude:: model/005.php - -$table ------- - -Specifies the database table that this model primarily works with. This only applies to the built-in CRUD methods. You -are not restricted to using only this table in your own queries. - -$primaryKey ------------ - -This is the name of the column that uniquely identifies the records in this table. This does not necessarily have to -match the primary key that is specified in the database, but is used with methods like ``find()`` to know what column to -match the specified value to. - -.. note:: All Models must have a primaryKey specified to allow all of the features to work as expected. - -$useAutoIncrement ------------------ - -Specifies if the table uses an auto-increment feature for `$primaryKey`_. If set to ``false`` then you are responsible -for providing a primary key value for every record in the table. This feature may be handy when we want to implement a -1:1 relation or use UUIDs for our model. The default value is ``true``. - -.. note:: If you set `$useAutoIncrement`_ to ``false``, then make sure to set your primary key in the database to - ``unique``. This way you will make sure that all of the Model's features will still work the same as before. - -$returnType ------------ - -The Model's **find*()** methods will take a step of work away from you and automatically return the resulting data, -instead of the Result object. - -This setting allows you to define the type of data that is returned. Valid values are '**array**' (the default), -'**object**', or the **fully qualified name of a class** that can be used with the Result object's -``getCustomResultObject()`` method. - -Using the special ``::class`` constant of the class will allow most IDEs to auto-complete the name and allow functions -like refactoring to better understand your code. - -.. _model-use-soft-deletes: - -$useSoftDeletes ---------------- - -If true, then any ``delete()`` method calls will set ``deleted_at`` in the database, instead of actually deleting the -row. This can preserve data when it might be referenced elsewhere, or can maintain a "recycle bin" of objects that can -be restored, or even simply preserve it as part of a security trail. If true, the -**find*()** methods will only return non-deleted rows, unless the ``withDeleted()`` method is called prior to calling the **find*()** -method. - -This requires either a DATETIME or INTEGER field in the database as per the model's `$dateFormat`_ setting. The default -field name is ``deleted_at``, but this name can be configured to any name of your choice by using the `$deletedField`_ -property. - -.. important:: The ``deleted_at`` field in the database must be nullable. - -.. _model-allowed-fields: - -$allowedFields --------------- - -This array should be updated with the field names that can be set during ``save()``, ``insert()``, ``update()``, or -``replace()`` methods. Any field names other than these will be discarded. This helps to protect against just taking -input from a form and throwing it all at the model, resulting in potential mass assignment vulnerabilities. - -.. note:: The `$primaryKey`_ field should never be an allowed field. - -$allowEmptyInserts ------------------- - -.. versionadded:: 4.3.0 - -Whether to allow inserting empty data. The default value is ``false``, meaning that if you try to insert empty data, a -``DataException`` with "There is no data to insert." will be raised. - -You may also change this setting with the :ref:`model-allow-empty-inserts` method. - -.. _model-update-only-changed: - -$updateOnlyChanged ------------------- - -.. versionadded:: 4.5.0 - -Whether to update only the changed fields of an :doc:`Entity <./entities>`. The default value is ``true``, meaning that -only changed field data is used when updating the database. So if you try to update an Entity without changes, a -``DataException`` with "There is no data to update." will be raised. - -Setting this property to ``false`` will ensure that all allowed fields of an Entity are submitted to the database and -updated at any time. - -$casts ------- - -.. versionadded:: 4.5.0 - -This allows you to convert data retrieved from a database into the appropriate PHP type. This option should be an array -where the key is the name of the field, and the value is the data type. See :ref:`model-field-casting` for details. - -Dates ------ - -$useTimestamps -^^^^^^^^^^^^^^ - -This boolean value determines whether the current date is automatically added to all inserts and updates. If ``true``, -it will set the current time in the format specified by `$dateFormat`_. This requires that the table have columns named -**created_at**, **updated_at** and **deleted_at** in the appropriate data type. See also `$createdField`_, -`$updatedField`_, and `$deletedField`_. - -$dateFormat -^^^^^^^^^^^ - -This value works with `$useTimestamps`_ and `$useSoftDeletes`_ to ensure that the correct type of date value gets -inserted into the database. By default, this creates DATETIME values, but valid options are: ``'datetime'``, ``'date'``, -or ``'int'`` (a UNIX timestamp). Using `$useSoftDeletes`_ or `$useTimestamps`_ with an invalid or missing `$dateFormat`_ -will cause an exception. - -$createdField -^^^^^^^^^^^^^ - -Specifies which database field to use for the data record's create timestamp. Set to an empty string (``''``) to avoid -updating it (even if `$useTimestamps`_ is enabled). - -$updatedField -^^^^^^^^^^^^^ - -Specifies which database field to use for the data record's update timestamp. Set to an empty string (``''``) to avoid -updating it (even if `$useTimestamps`_ is enabled). - -$deletedField -^^^^^^^^^^^^^ - -Specifies which database field to use for soft deletions. See :ref:`model-use-soft-deletes`. - -Validation ----------- - -$validationRules -^^^^^^^^^^^^^^^^ - -Contains either an array of validation rules as described in :ref:`validation-array` or a string containing the name of -a validation group, as described in the same section. See also :ref:`model-setting-validation-rules`. - -$validationMessages -^^^^^^^^^^^^^^^^^^^ - -Contains an array of custom error messages that should be used during validation, as described in -:ref:`validation-custom-errors`. See also :ref:`model-setting-validation-rules`. - -$skipValidation -^^^^^^^^^^^^^^^ - -Whether validation should be skipped during all **inserts** and **updates**. The default value is ``false``, meaning -that validation will always be attempted. This is primarily used by the ``skipValidation()`` method, but may be changed -to ``true`` so this model will never validate. - -.. _clean-validation-rules: - -$cleanValidationRules -^^^^^^^^^^^^^^^^^^^^^ - -Whether validation rules for fields missing from the passed data should be removed. This is used in **updates**. The -default value is ``true``, meaning that validation rules for the fields that are not present in the passed data will be -(temporarily) removed before the validation. This is to avoid validation errors when updating only some fields. - -You can also change the value with the ``cleanRules()`` method. - -.. note:: Prior to v4.2.7, ``$cleanValidationRules`` did not work due to a bug. - -Callbacks ---------- - -$allowCallbacks -^^^^^^^^^^^^^^^ - -Whether the callbacks defined below should be used. See :ref:`model-events`. - -$beforeInsert -^^^^^^^^^^^^^ -$afterInsert -^^^^^^^^^^^^ -$beforeUpdate -^^^^^^^^^^^^^ -$afterUpdate -^^^^^^^^^^^^ -$beforeFind -^^^^^^^^^^^ -$afterFind -^^^^^^^^^^ -$beforeDelete -^^^^^^^^^^^^^ -$afterDelete -^^^^^^^^^^^^ -$beforeInsertBatch -^^^^^^^^^^^^^^^^^^ -$afterInsertBatch -^^^^^^^^^^^^^^^^^ -$beforeUpdateBatch -^^^^^^^^^^^^^^^^^^ -$afterUpdateBatch -^^^^^^^^^^^^^^^^^ - -These arrays allow you to specify callback methods that will be run on the data at the time specified in the property -name. See :ref:`model-events`. - -.. _model-field-casting: - -Model Field Casting -******************* - -.. versionadded:: 4.5.0 - -When retrieving data from a database, data of integer type may be converted to string type in PHP. You may also want to -convert date/time data into a Time object in PHP. - -Model Field Casting allows you to convert data retrieved from a database into the appropriate PHP type. - -.. important:: - If you use this feature with the :doc:`Entity <./entities>`, do not use - :ref:`Entity Property Casting `. Using both at the same time does not work. - - Entity Property Casting works at (1)(4), but this casting works at (2)(3):: - - [App Code] --- (1) --> [Entity] --- (2) --> [Database] - [App Code] <-- (4) --- [Entity] <-- (3) --- [Database] - - When using this casting, the Entity will have correctly typed PHP values in the attributes. This behavior is - completely different from the previous behavior. Do not expect the attributes to hold raw data from the database. - -Defining Data Types -=================== - -The ``$casts`` property sets its definition. This option should be an array where the key is the name of the field, and -the value is the data type: - -.. literalinclude:: model/057.php - -Data Types -========== - -The following types are provided by default. Add a question mark at the beginning of the type to mark the field as -nullable, i.e., ``?int``, ``?datetime``. - -+---------------+----------------+---------------------------+ -| Type | PHP Value Type | DB Column Type | -+===============+================+===========================+ -|``int`` | int | int type | -+---------------+----------------+---------------------------+ -|``float`` | float | float (numeric) type | -+---------------+----------------+---------------------------+ -|``bool`` | bool | bool/int/string type | -+---------------+----------------+---------------------------+ -|``int-bool`` | bool | int type (1 or 0) | -+---------------+----------------+---------------------------+ -|``array`` | array | string type (serialized) | -+---------------+----------------+---------------------------+ -|``csv`` | array | string type (CSV) | -+---------------+----------------+---------------------------+ -|``json`` | stdClass | json/string type | -+---------------+----------------+---------------------------+ -|``json-array`` | array | json/string type | -+---------------+----------------+---------------------------+ -|``datetime`` | Time | datetime type | -+---------------+----------------+---------------------------+ -|``timestamp`` | Time | int type (UNIX timestamp) | -+---------------+----------------+---------------------------+ -|``uri`` | URI | string type | -+---------------+----------------+---------------------------+ -|``enum`` | Enum | string/int type | -+---------------+----------------+---------------------------+ - -csv ---- - -Casting as ``csv`` uses PHP's internal ``implode()`` and ``explode()`` functions and assumes all values are string-safe -and free of commas. For more complex data casts try ``array`` or ``json``. - -datetime --------- - -You can pass a parameter like ``datetime[ms]`` for date/time with milliseconds, or ``datetime[us]`` for date/time with -microseconds. - -The datetime format is set in the ``dateFormat`` array of the -:ref:`database configuration ` in the **app/Config/Database.php** file. - -.. note:: - When you set ``ms`` or ``us`` as a parameter, **Model** takes care of the fractional seconds of the Time. But - **Query Builder** does not. So you still need to use the ``format()`` method when you pass the Time to Query - Builder's methods like ``where()``: - - .. literalinclude:: model/063.php - :lines: 2- - -.. note:: Prior to v4.6.0, you could not use ``ms`` or ``us`` as a parameter, because the fractional seconds of Time - were lost due to bugs. - -timestamp ---------- - -The timezone of the ``Time`` instance created will be the default timezone (app's timezone), not UTC. - -enum ----- - -.. versionadded:: 4.7.0 - -You can cast fields to PHP enums. You must specify the enum class name as a parameter, like -``enum[App\Enums\StatusEnum]``. - -Enum casting supports: - -* **Backed enums** (string or int) - The backing value is stored in the database -* **Unit enums** - The case name is stored in the database as a string - -Custom Casting -============== - -You can define your own conversion types. - -Creating Custom Handlers ------------------------- - -First, you need to create a handler class for your type. Let's say the class will be located in the **app/Models/Cast** -directory: - -.. literalinclude:: model/058.php - -If you don't need to change values when getting or setting a value, just don't implement the appropriate method: - -.. literalinclude:: model/060.php - -Registering Custom Handlers ---------------------------- - -Now you need to register it: - -.. literalinclude:: model/059.php - -Parameters ----------- - -In some cases, one type is not enough. In this situation, you can use additional parameters. Additional parameters are -indicated in square brackets and listed with a comma like ``type[param1, param2]``. - -.. literalinclude:: model/061.php - -.. literalinclude:: model/062.php - -.. note:: If the casting type is marked as nullable like ``?bool`` and the passed value is not null, then the parameter - with the value ``nullable`` will be passed to the casting type handler. If the casting type has predefined - parameters, then ``nullable`` will be added to the end of the list. - -Working with Data -***************** - -Finding Data -============ - -Several functions are provided for doing basic CRUD work on your tables, including ``find()``, ``insert()``, -``update()``, ``delete()`` and more. - -find() ------- - -Returns a single row where the primary key matches the value passed in as the first parameter: - -.. literalinclude:: model/006.php - -The value is returned in the format specified in `$returnType`_. - -You can specify more than one row to return by passing an array of primaryKey values instead of just one: - -.. literalinclude:: model/007.php - -.. note:: If ``find()`` is called without parameters or with ``null``, it will return all rows in that model's table, - effectively acting like ``findAll()``, though less explicit. - -findColumn() ------------- - -Returns null or an indexed array of column values: - -.. literalinclude:: model/008.php - -``$columnName`` should be the name of a single column. Otherwise, you will get a ``DataException``. - -findAll() ---------- - -Returns all results: - -.. literalinclude:: model/009.php - -This query may be modified by interjecting Query Builder commands as needed prior to calling this method: - -.. literalinclude:: model/010.php - -You can pass in limit and offset values as the first and second parameters, respectively: - -.. literalinclude:: model/011.php - -first() -------- - -Returns the first row in the result set. This is best used in combination with the query builder. - -.. literalinclude:: model/012.php - -withDeleted() -------------- - -If `$useSoftDeletes`_ is true, then the -**find*()** methods will not return any rows where ``deleted_at IS NOT NULL``. To temporarily override this, you can use the ``withDeleted()`` method prior to calling the **find*()** -method. - -.. literalinclude:: model/013.php - -onlyDeleted() -------------- - -Whereas ``withDeleted()`` will return both deleted and not-deleted rows, this method modifies the next **find*()** -methods to return only soft deleted rows: - -.. literalinclude:: model/014.php - -Saving Data -=========== - -insert() --------- - -The first parameter is an associative array of data to create a new row of data in the database. If an object is passed -instead of an array, it will attempt to convert it to an array. - -The array's keys must match the name of the columns in the `$table`_, while the array's values are the values to save -for that key. - -The optional second parameter is of type boolean, and if it is set to false, the method will return a boolean value, -which indicates the success or failure of the query. - -You can retrieve the last inserted row's primary key using the ``getInsertID()`` method. - -.. literalinclude:: model/015.php - -.. _model-allow-empty-inserts: - -allowEmptyInserts() -------------------- - -.. versionadded:: 4.3.0 - -You can use the ``allowEmptyInserts()`` method to insert empty data. By default, the Model throws an exception when you -try to insert empty data. But if you call this method, the check will no longer be performed. - -.. literalinclude:: model/056.php - -You may also change this setting with the `$allowEmptyInserts`_ property. - -You can enable the check again by calling ``allowEmptyInserts(false)``. - -update() --------- - -Updates an existing record in the database. The first parameter is the `$primaryKey`_ of the record to update. An -associative array of data is passed into this method as the second parameter. The array's keys must match the name of -the columns in the `$table`_, while the array's values are the values to save for that key: - -.. literalinclude:: model/016.php - -.. important:: Since v4.3.0, this method raises a ``DatabaseException`` if it generates an SQL statement without a WHERE - clause. In previous versions, if it was called without `$primaryKey`_ specified and an SQL statement was generated - without a WHERE clause, the query would still execute and all records in the table would be updated. - -Multiple records may be updated with a single call by passing an array of primary keys as the first parameter: - -.. literalinclude:: model/017.php - -When you need a more flexible solution, you can leave the parameters empty, and it functions like the Query Builder's -update command, with the added benefit of validation, events, etc: - -.. literalinclude:: model/018.php - -.. _model-replace: - -replace() ---------- - -Pass an associative array to ``replace($data)`` to perform the Query Builder's -:php:meth:`CodeIgniter\\Database\\BaseBuilder::replace()` operation. The model validates the supplied data and handles -timestamps, but does not trigger model callbacks. - -Since v4.7.6, fields outside `$allowedFields`_ are discarded when field protection is enabled, except for a supplied -`$primaryKey`_. Supplied timestamp values not listed in `$allowedFields`_ are discarded and, when timestamps are -enabled, replaced by generated ones. Pass ``true`` as the second argument to return the SQL instead of executing it. - -If field protection removes all data from a non-empty input, or leaves only its primary key after removing other fields, -``replace()`` throws a ``DataException`` before generating timestamps. Explicitly passing ``null`` or an empty array -still allows the method to use data previously set on the Query Builder. - -.. warning:: Field protection does not authorize access to a record. A supplied primary key is retained even for - auto-incrementing keys, so untrusted input can select the record to replace. Use a trusted identifier and verify - that the caller is authorized to modify the target record; do not rely on ``$allowedFields`` alone when passing - request data to ``replace()``. - -.. important:: Field protection filters input; it does not guarantee that existing values of omitted columns are - preserved. Depending on the database driver, replacement may delete the existing row and insert a new one, using - defaults for omitted columns. Use ``update()`` to change selected fields of an existing row. - -Fields used to match existing rows must be in ``$allowedFields`` or be the primary key. Filtering a unique column can -change whether a replacement matches an existing row. With PostgreSQL, the first remaining field is used for matching; -ensure that it is a primary or unique key to avoid matching multiple rows. - -.. _model-save: - -save() ------- - -This is a wrapper around the ``insert()`` and ``update()`` methods that handles inserting or updating the record -automatically, based on whether it finds an array key matching the **primary key** value: - -.. literalinclude:: model/019.php - -The save method can also make working with custom class result objects much simpler by recognizing a non-simple object -and grabbing its public and protected values into an array, which is then passed to the appropriate insert or update -method. This allows you to work with Entity classes in a very clean way. Entity classes are simple classes that -represent a single instance of an object type, like a user, a blog post, a job, etc. This class is responsible for -maintaining the business logic surrounding the object itself, like formatting elements in a certain way, etc. They -shouldn't have any idea about how they are saved to the database. At their simplest, they might look like this: - -.. literalinclude:: model/020.php - -A very simple model to work with this might look like: - -.. literalinclude:: model/021.php - -This model works with data from the ``jobs`` table, and returns all results as an instance of ``App\Entities\Job``. When -you need to persist that record to the database, you will need to either write custom methods, or use the model's -``save()`` method to inspect the class, grab any public and protected properties, and save them to the database: - -.. literalinclude:: model/022.php - -.. note:: If you find yourself working with Entities a lot, CodeIgniter provides a built-in - :doc:`Entity class ` that provides several handy features that make developing Entities simpler. - -.. _model-saving-dates: - -Saving Dates ------------- - -.. versionadded:: 4.5.0 - -When saving data, if you pass :doc:`Time <../libraries/time>` instances, they are converted to strings with the format -defined in ``dateFormat['datetime']`` and ``dateFormat['date']`` in the -:ref:`database configuration `. - -.. note:: Prior to v4.5.0, the date/time formats were hard coded as ``Y-m-d H:i:s`` and ``Y-m-d`` in the Model class. - -Primary Key Validation ----------------------- - -.. versionadded:: 4.7.0 - -The ``insert()``, ``insertBatch()`` (when `$useAutoIncrement`_ is ``false``), ``update()``, and ``delete()`` methods -validate primary key values before executing database queries. Invalid values such as ``null``, ``0``, ``'0'``, empty -strings, booleans, empty arrays, or nested arrays will throw an ``InvalidArgumentException`` with a specific error -message. - -If you need to customize this behavior (e.g., to allow ``0`` as a valid primary key for legacy systems), you can -override the ``validateID()`` method in your model. - -Deleting Data -============= - -delete() --------- - -Takes a primary key value as the first parameter and deletes the matching record from the model's table: - -.. literalinclude:: model/023.php - -If the model's `$useSoftDeletes`_ value is true, this will update the row to set ``deleted_at`` to the current date and -time. You can force a permanent delete by setting the second parameter as true. - -An array of primary keys can be passed in as the first parameter to delete multiple records at once: - -.. literalinclude:: model/024.php - -If no parameters are passed in, it will act like the Query Builder's delete method, requiring a prior where call: - -.. literalinclude:: model/025.php - -purgeDeleted() --------------- - -Cleans out the database table by permanently removing all rows that have 'deleted_at IS NOT NULL'. - -.. literalinclude:: model/026.php - -.. _in-model-validation: - -In-Model Validation -=================== - -.. warning:: In-Model validation is performed just before data is stored in the database. Prior to that point, the data - has not yet been validated. Processing user-input data prior to validation may introduce vulnerabilities. - -Validating Data ---------------- - -The Model class provides a way to automatically have all data validated prior to saving to the database with the -``insert()``, ``update()``, or ``save()`` methods. - -.. important:: When you update data, by default, the validation in the model class only validates provided fields. This - is to avoid validation errors when updating only some fields. - - However, this means that not all validation rules you set will be checked during updates. Thus, incomplete data may - pass the validation. - - For example, ``required*`` rules or the ``is_unique`` rule, which require the values of other fields, may not work - as expected. - - To avoid such glitches, this behavior can be changed by configuration. See :ref:`clean-validation-rules` for - details. - -.. _model-setting-validation-rules: - -Setting Validation Rules ------------------------- - -The first step is to fill out the `$validationRules`_ class property with the fields and rules that should be applied. - -.. note:: You can see the list of built-in Validation rules in :ref:`validation-available-rules`. - -If you have custom error messages that you want to use, place them in the `$validationMessages`_ array: - -.. literalinclude:: model/027.php - -If you'd rather organize your rules and error messages within the -:ref:`Validation Config File `, you can do that and simply set -`$validationRules`_ to the name of the validation rule group you created: - -.. literalinclude:: model/034.php - -The other way to set the validation rules for fields is by using functions: - -.. php:namespace:: CodeIgniter - -.. php:class:: Model - -.. php:method:: setValidationRule($field, $fieldRules) - - :param string $field: - :param array $fieldRules: - - This function will set the field validation rules. - - Usage example: - - .. literalinclude:: model/028.php - -.. php:method:: setValidationRules($validationRules) - - :param array $validationRules: - - This function will set the validation rules. - - Usage example: - - .. literalinclude:: model/029.php - -The other way to set the validation messages for fields is by using functions: - -.. php:method:: setValidationMessage($field, $fieldMessages) - - :param string $field: - :param array $fieldMessages: - - This function will set the field-wise error messages. - - Usage example: - - .. literalinclude:: model/030.php - -.. php:method:: setValidationMessages($validationMessages) - - :param array $validationMessages: - - This function will set the field messages. - - Usage example: - - .. literalinclude:: model/031.php - -Getting Validation Result -------------------------- - -Now, whenever you call the ``insert()``, ``update()``, or ``save()`` methods, the data will be validated. If it fails, -the model will return boolean **false**. - -.. _model-getting-validation-errors: - -Getting Validation Errors -------------------------- - -You can use the ``errors()`` method to retrieve the validation errors: - -.. literalinclude:: model/032.php - -This returns an array with the field names and their associated errors that can be used to either show all of the errors -at the top of the form, or to display them individually: - -.. literalinclude:: model/033.php - -Retrieving Validation Rules ---------------------------- - -You can retrieve a model's validation rules by accessing its ``validationRules`` property: - -.. literalinclude:: model/035.php - -You can also retrieve just a subset of those rules by calling the accessor method directly, with options: - -.. literalinclude:: model/036.php - -The ``$options`` parameter is an associative array with one element, whose key is either ``'except'`` or ``'only'``, and -which has as its value an array of field names of interest: - -.. literalinclude:: model/037.php - -Validation Placeholders ------------------------ - -The model provides a simple method to replace parts of your rules based on data that's being passed into it. This sounds -fairly obscure but can be especially handy with the ``is_unique`` validation rule. Placeholders are simply the name of -the field (or array key) that was passed in as ``$data`` surrounded by curly brackets. It will be replaced by the -**value** of the matched incoming field. An example should clarify this: - -.. literalinclude:: model/038.php - -.. note:: Since v4.3.5, you must set the validation rules for the placeholder field (``id``). - -This set of rules states that the email address should be unique in the database, except for the row that has an id -matching the placeholder's value. Assuming that the form POST data had the following: - -.. literalinclude:: model/039.php - -then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule: - -.. literalinclude:: model/040.php - -So it will ignore the row in the database that has ``id=4`` when it verifies the email is unique. - -.. note:: Since v4.3.5, if the placeholder (``id``) value does not pass the validation, the placeholder will not be - replaced. - -This can also be used to create more dynamic rules at runtime, as long as you take care that any dynamic keys passed in -don't conflict with your form data. - -Protecting Fields -================= - -To help protect against Mass Assignment Attacks, the Model class **requires** that you list all of the field names that -can be changed during inserts, updates, and replacements in the `$allowedFields`_ class property. Any data provided in -addition to these will be removed prior to hitting the database. This limits which fields can be assigned through model -methods. - -For ``replace()``, a supplied `$primaryKey`_ is retained to identify the record to replace. - -.. literalinclude:: model/041.php - -Occasionally, you will find times where you need to be able to change these elements. This is often during testing, -migrations, or seeds. In these cases, you can turn the protection on or off: - -.. literalinclude:: model/042.php - -Runtime Return Type Changes -=========================== - -You can specify the format that data should be returned as when using the **find*()** methods as the class property, -`$returnType`_. There may be times that you would like the data back in a different format, though. The Model provides -methods that allow you to do just that. - -.. note:: These methods only change the return type for the next **find*()** method call. After that, it is reset to its - default value. - -asArray() ---------- - -Returns data from the next **find*()** method as associative arrays: - -.. literalinclude:: model/047.php - -asObject() ----------- - -Returns data from the next **find*()** method as standard objects or custom class instances: - -.. literalinclude:: model/048.php - -Processing Large Amounts of Data -================================ - -Sometimes, you need to process large amounts of data and would run the risk of running out of memory. To make this -simpler, you may use the ``chunk()`` method to get smaller chunks of data that you can then do your work on. The first -parameter is the number of rows to retrieve in a single chunk. The second parameter is a Closure that will be called for -each row of data. - -This is best used during cron jobs, data exports, or other large tasks. - -.. literalinclude:: model/049.php - -Working with Query Builder -************************** - -Getting Query Builder for the Model's Table -=========================================== - -CodeIgniter Model has one instance of the Query Builder for that model's database connection. You can get access to the -**shared** instance of the Query Builder any time you need it: - -.. literalinclude:: model/043.php - -This builder is already set up with the model's `$table`_. - -.. note:: Once you get the Query Builder instance, you can call methods of the - :doc:`Query Builder <../database/query_builder>`. However, since Query Builder is not a Model, you cannot call - methods of the Model. - -Getting Query Builder for Another Table -======================================= - -If you need access to another table, you can get another instance of the Query Builder. Pass the table name in as a -parameter, but be aware that this will **not** return a shared instance: - -.. literalinclude:: model/044.php - -Mixing Methods of Query Builder and Model -========================================= - -You can also use Query Builder methods and the Model's CRUD methods in the same chained call, allowing for very elegant -use: - -.. literalinclude:: model/045.php - -In this case, it operates on the shared instance of the Query Builder held by the model. - -.. important:: The Model does not provide a perfect interface to the Query Builder. The Model and the Query Builder are - separate classes with different purposes. They should not be expected to return the same data. - -If the Query Builder returns a result, it is returned as is. In that case, the result may be different from the one -returned by the model's method and may not be what was expected. The model's events are not triggered. - -To prevent unexpected behavior, do not use Query Builder methods that return results and specify the model's method at -the end of the method chaining. - -.. note:: You can also access the model's database connection seamlessly: - - .. literalinclude:: model/046.php - -.. _model-events: - -.. _model-events-callbacks: - -Model Events -************ - -There are several points within the model's execution at which you can specify multiple callback methods to run. These -methods can be used to normalize data, hash passwords, save related entities, and much more. - -The following points in the model's execution can be affected, each through a class property: - -- `$beforeInsert`_, `$afterInsert`_ -- `$beforeUpdate`_, `$afterUpdate`_ -- `$beforeFind`_, `$afterFind`_ -- `$beforeDelete`_, `$afterDelete`_ -- `$beforeInsertBatch`_, `$afterInsertBatch`_ -- `$beforeUpdateBatch`_, `$afterUpdateBatch`_ - -.. note:: ``$beforeInsertBatch``, ``$afterInsertBatch``, ``$beforeUpdateBatch`` and ``$afterUpdateBatch`` can be used - since v4.3.0. - -Defining Callbacks -================== - -You specify the callbacks by first creating a new class method in your model to use. - -This class method will always receive a ``$data`` array as its only parameter. - -The exact contents of the ``$data`` array will vary between events, but will always contain a key named ``data`` that -contains the primary data passed to the original method. In the case of the **insert*()** or **update*()** methods, that -will be the key/value pairs that are being inserted into the database. The main ``$data`` array will also contain the -other values passed to the method, as detailed in `Event Parameters`_. - -The callback method must return the original ``$data`` array so other callbacks have the full information. - -.. literalinclude:: model/050.php - -Specifying Callbacks To Run -=========================== - -You specify when to run the callbacks by adding the method name to the appropriate class property (`$beforeInsert`_, -`$afterUpdate`_, etc.). Multiple callbacks can be added to a single event, and they will be processed one after the -other. You can use the same callback in multiple events: - -.. literalinclude:: model/051.php - -Additionally, each model may allow (default) or deny callbacks class-wide by setting its `$allowCallbacks`_ property: - -.. literalinclude:: model/052.php - -You may also change this setting temporarily for a single model call using the ``allowCallbacks()`` method: - -.. literalinclude:: model/053.php - -Event Parameters -================ - -Since the exact data passed to each callback varies a bit, here are the details on what is in the ``$data`` parameter -passed to each event: - -================= ========================================================================================================= -Event $data contents -================= ========================================================================================================= -beforeInsert **data** = the key/value pairs that are being inserted. If an object or Entity class is passed to the - ``insert()`` method, it is first converted to an array. -afterInsert **id** = the primary key of the new row, or 0 on failure. - **data** = the key/value pairs being inserted. - **result** = the results of the ``insert()`` method used through the Query Builder. -beforeUpdate **id** = the array of primary keys of the rows being passed to the ``update()`` method. - **data** = the key/value pairs that are being updated. If an object or Entity class is passed to the - ``update()`` method, it is first converted to an array. -afterUpdate **id** = the array of primary keys of the rows being passed to the ``update()`` method. - **data** = the key/value pairs being updated. - **result** = the results of the ``update()`` method used through the Query Builder. -beforeFind The name of the calling **method**, whether a **singleton** was requested, and these additional fields: - none for ``first()``, **id** = the primary key of the row being searched for, for ``find()``, - and **limit** = the number of rows to find, and **offset** = the number of rows to skip during - the search, for ``findAll()``. -afterFind Same as **beforeFind** but including the resulting row(s) of data, or null if no result found. -beforeDelete **id** = an array of primary key rows being passed to the ``delete()`` method. - **purge** = boolean whether soft-deleted rows should be hard deleted. -afterDelete **id** = an array of primary key rows being passed to the ``delete()`` method. - **purge** = boolean whether soft-deleted rows should be hard deleted. - **result** = the result of the ``delete()`` call on the Query Builder. - **data** = unused. -beforeInsertBatch **data** = associative array of values that are being inserted. If an object or Entity class is passed to the - ``insertBatch()`` method, it is first converted to an array. -afterInsertBatch **data** = the associative array of values being inserted. - **result** = the results of the ``insertBatch()`` method used through the Query Builder. -beforeUpdateBatch **data** = associative array of values that are being updated. If an object or Entity class is passed to the - ``updateBatch()`` method, it is first converted to an array. -afterUpdateBatch **data** = the key/value pairs being updated. - **result** = the results of the ``updateBatch()`` method used through the Query Builder. -================= ========================================================================================================= - -.. note:: When using the ``paginate()`` method in combination with the ``beforeFind`` event to modify the query, the - results may not behave as expected. - - This is because the ``beforeFind`` event only affects the actual retrieval of the results (``findAll()``), but - **not** the query used to count the total number of rows for pagination. - - As a result, the total row count used for generating pagination links may not reflect the modified query conditions, - leading to inconsistencies in pagination. - -Modifying Find* Data -==================== - -The ``beforeFind`` and ``afterFind`` methods can both return a modified set of data to override the normal response from -the model. For ``afterFind``, any changes made to ``data`` in the return array will automatically be passed back to the -calling context. In order for ``beforeFind`` to intercept the find workflow, it must also return an additional boolean, -``returnData``: - -.. literalinclude:: model/054.php - -Manual Model Creation -********************* - -You do not need to extend any special class to create a model for your application. All you need is to get an instance -of the database connection and you're good to go. This allows you to bypass the features CodeIgniter's Model gives you -out of the box, and create a fully custom experience. - -.. literalinclude:: model/055.php diff --git a/user_guide_src/source/models/model/001.php b/user_guide_src/source/models/model/001.php deleted file mode 100644 index a02d46890a74..000000000000 --- a/user_guide_src/source/models/model/001.php +++ /dev/null @@ -1,18 +0,0 @@ -allowedFields[] = 'middlename'; - } -} diff --git a/user_guide_src/source/models/model/004.php b/user_guide_src/source/models/model/004.php deleted file mode 100644 index 1005e6f7f2e7..000000000000 --- a/user_guide_src/source/models/model/004.php +++ /dev/null @@ -1,12 +0,0 @@ -find($userId); diff --git a/user_guide_src/source/models/model/007.php b/user_guide_src/source/models/model/007.php deleted file mode 100644 index 312575c09578..000000000000 --- a/user_guide_src/source/models/model/007.php +++ /dev/null @@ -1,3 +0,0 @@ -find([1, 2, 3]); diff --git a/user_guide_src/source/models/model/008.php b/user_guide_src/source/models/model/008.php deleted file mode 100644 index 1b7b52fe25ff..000000000000 --- a/user_guide_src/source/models/model/008.php +++ /dev/null @@ -1,3 +0,0 @@ -findColumn($columnName); diff --git a/user_guide_src/source/models/model/009.php b/user_guide_src/source/models/model/009.php deleted file mode 100644 index 881962a52c3b..000000000000 --- a/user_guide_src/source/models/model/009.php +++ /dev/null @@ -1,3 +0,0 @@ -findAll(); diff --git a/user_guide_src/source/models/model/010.php b/user_guide_src/source/models/model/010.php deleted file mode 100644 index 84b3b6e76910..000000000000 --- a/user_guide_src/source/models/model/010.php +++ /dev/null @@ -1,3 +0,0 @@ -where('active', 1)->findAll(); diff --git a/user_guide_src/source/models/model/011.php b/user_guide_src/source/models/model/011.php deleted file mode 100644 index a906bda6142e..000000000000 --- a/user_guide_src/source/models/model/011.php +++ /dev/null @@ -1,3 +0,0 @@ -findAll($limit, $offset); diff --git a/user_guide_src/source/models/model/012.php b/user_guide_src/source/models/model/012.php deleted file mode 100644 index 0f48babbab4a..000000000000 --- a/user_guide_src/source/models/model/012.php +++ /dev/null @@ -1,3 +0,0 @@ -where('deleted', 0)->first(); diff --git a/user_guide_src/source/models/model/013.php b/user_guide_src/source/models/model/013.php deleted file mode 100644 index 1abc1e3be49b..000000000000 --- a/user_guide_src/source/models/model/013.php +++ /dev/null @@ -1,7 +0,0 @@ -findAll(); - -// Gets all rows -$allUsers = $userModel->withDeleted()->findAll(); diff --git a/user_guide_src/source/models/model/014.php b/user_guide_src/source/models/model/014.php deleted file mode 100644 index f12fc5e0cb6a..000000000000 --- a/user_guide_src/source/models/model/014.php +++ /dev/null @@ -1,3 +0,0 @@ -onlyDeleted()->findAll(); diff --git a/user_guide_src/source/models/model/015.php b/user_guide_src/source/models/model/015.php deleted file mode 100644 index a1b013fff974..000000000000 --- a/user_guide_src/source/models/model/015.php +++ /dev/null @@ -1,15 +0,0 @@ - 'darth', - 'email' => 'd.vader@theempire.com', -]; - -// Inserts data and returns inserted row's primary key -$userModel->insert($data); - -// Inserts data and returns true on success and false on failure -$userModel->insert($data, false); - -// Returns inserted row's primary key -$userModel->getInsertID(); diff --git a/user_guide_src/source/models/model/016.php b/user_guide_src/source/models/model/016.php deleted file mode 100644 index efecefe6ba81..000000000000 --- a/user_guide_src/source/models/model/016.php +++ /dev/null @@ -1,8 +0,0 @@ - 'darth', - 'email' => 'd.vader@theempire.com', -]; - -$userModel->update($id, $data); diff --git a/user_guide_src/source/models/model/017.php b/user_guide_src/source/models/model/017.php deleted file mode 100644 index 5032c34a4613..000000000000 --- a/user_guide_src/source/models/model/017.php +++ /dev/null @@ -1,7 +0,0 @@ - 1, -]; - -$userModel->update([1, 2, 3], $data); diff --git a/user_guide_src/source/models/model/018.php b/user_guide_src/source/models/model/018.php deleted file mode 100644 index a5f03a2118dc..000000000000 --- a/user_guide_src/source/models/model/018.php +++ /dev/null @@ -1,6 +0,0 @@ -whereIn('id', [1, 2, 3]) - ->set(['active' => 1]) - ->update(); diff --git a/user_guide_src/source/models/model/019.php b/user_guide_src/source/models/model/019.php deleted file mode 100644 index 789218001968..000000000000 --- a/user_guide_src/source/models/model/019.php +++ /dev/null @@ -1,20 +0,0 @@ - 'darth', - 'email' => 'd.vader@theempire.com', -]; - -$userModel->save($data); - -// Performs an update, since the primary key, 'id', is found. -$data = [ - 'id' => 3, - 'username' => 'darth', - 'email' => 'd.vader@theempire.com', -]; -$userModel->save($data); diff --git a/user_guide_src/source/models/model/020.php b/user_guide_src/source/models/model/020.php deleted file mode 100644 index 7d659c7fcd36..000000000000 --- a/user_guide_src/source/models/model/020.php +++ /dev/null @@ -1,24 +0,0 @@ -{$key}; - } - } - - public function __set($key, $value) - { - if (property_exists($this, $key)) { - $this->{$key} = $value; - } - } -} diff --git a/user_guide_src/source/models/model/021.php b/user_guide_src/source/models/model/021.php deleted file mode 100644 index 155938ea61be..000000000000 --- a/user_guide_src/source/models/model/021.php +++ /dev/null @@ -1,14 +0,0 @@ -find(15); - -// Make some changes -$job->name = 'Foobar'; - -// Save the changes -$model->save($job); diff --git a/user_guide_src/source/models/model/023.php b/user_guide_src/source/models/model/023.php deleted file mode 100644 index c1045eecbbb2..000000000000 --- a/user_guide_src/source/models/model/023.php +++ /dev/null @@ -1,3 +0,0 @@ -delete(12); diff --git a/user_guide_src/source/models/model/024.php b/user_guide_src/source/models/model/024.php deleted file mode 100644 index cdac096377b2..000000000000 --- a/user_guide_src/source/models/model/024.php +++ /dev/null @@ -1,3 +0,0 @@ -delete([1, 2, 3]); diff --git a/user_guide_src/source/models/model/025.php b/user_guide_src/source/models/model/025.php deleted file mode 100644 index dc520c882d8e..000000000000 --- a/user_guide_src/source/models/model/025.php +++ /dev/null @@ -1,3 +0,0 @@ -where('id', 12)->delete(); diff --git a/user_guide_src/source/models/model/026.php b/user_guide_src/source/models/model/026.php deleted file mode 100644 index c06642313a0c..000000000000 --- a/user_guide_src/source/models/model/026.php +++ /dev/null @@ -1,3 +0,0 @@ -purgeDeleted(); diff --git a/user_guide_src/source/models/model/027.php b/user_guide_src/source/models/model/027.php deleted file mode 100644 index 86a5a5f4c71a..000000000000 --- a/user_guide_src/source/models/model/027.php +++ /dev/null @@ -1,22 +0,0 @@ - 'required|max_length[30]|alpha_numeric_space|min_length[3]', - 'email' => 'required|max_length[254]|valid_email|is_unique[users.email]', - 'password' => 'required|max_length[255]|min_length[8]', - 'pass_confirm' => 'required_with[password]|max_length[255]|matches[password]', - ]; - protected $validationMessages = [ - 'email' => [ - 'is_unique' => 'Sorry. That email has already been taken. Please choose another.', - ], - ]; -} diff --git a/user_guide_src/source/models/model/028.php b/user_guide_src/source/models/model/028.php deleted file mode 100644 index 9cea0eb31226..000000000000 --- a/user_guide_src/source/models/model/028.php +++ /dev/null @@ -1,6 +0,0 @@ -setValidationRule($fieldName, $fieldRules); diff --git a/user_guide_src/source/models/model/029.php b/user_guide_src/source/models/model/029.php deleted file mode 100644 index 93ba8ae51ffc..000000000000 --- a/user_guide_src/source/models/model/029.php +++ /dev/null @@ -1,12 +0,0 @@ - 'required|max_length[30]|alpha_numeric_space|min_length[3]', - 'email' => [ - 'rules' => 'required|max_length[254]|valid_email|is_unique[users.email]', - 'errors' => [ - 'required' => 'We really need your email.', - ], - ], -]; -$model->setValidationRules($validationRules); diff --git a/user_guide_src/source/models/model/030.php b/user_guide_src/source/models/model/030.php deleted file mode 100644 index 251f9bade2cd..000000000000 --- a/user_guide_src/source/models/model/030.php +++ /dev/null @@ -1,7 +0,0 @@ - 'Your name is required here', -]; -$model->setValidationMessage($fieldName, $fieldValidationMessage); diff --git a/user_guide_src/source/models/model/031.php b/user_guide_src/source/models/model/031.php deleted file mode 100644 index 902cea408f1f..000000000000 --- a/user_guide_src/source/models/model/031.php +++ /dev/null @@ -1,9 +0,0 @@ - [ - 'required' => 'Your baby name is missing.', - 'min_length' => 'Too short, man!', - ], -]; -$model->setValidationMessages($fieldValidationMessage); diff --git a/user_guide_src/source/models/model/032.php b/user_guide_src/source/models/model/032.php deleted file mode 100644 index 0e93993557b4..000000000000 --- a/user_guide_src/source/models/model/032.php +++ /dev/null @@ -1,5 +0,0 @@ -save($data) === false) { - return view('updateUser', ['errors' => $model->errors()]); -} diff --git a/user_guide_src/source/models/model/033.php b/user_guide_src/source/models/model/033.php deleted file mode 100644 index f0e48d26de73..000000000000 --- a/user_guide_src/source/models/model/033.php +++ /dev/null @@ -1,7 +0,0 @@ - -
    - $error): ?> -

    - -
    - diff --git a/user_guide_src/source/models/model/034.php b/user_guide_src/source/models/model/034.php deleted file mode 100644 index ac8989263ee2..000000000000 --- a/user_guide_src/source/models/model/034.php +++ /dev/null @@ -1,12 +0,0 @@ -validationRules; diff --git a/user_guide_src/source/models/model/036.php b/user_guide_src/source/models/model/036.php deleted file mode 100644 index af5a3eef010e..000000000000 --- a/user_guide_src/source/models/model/036.php +++ /dev/null @@ -1,3 +0,0 @@ -getValidationRules($options); diff --git a/user_guide_src/source/models/model/037.php b/user_guide_src/source/models/model/037.php deleted file mode 100644 index ff15de70d9c5..000000000000 --- a/user_guide_src/source/models/model/037.php +++ /dev/null @@ -1,6 +0,0 @@ -getValidationRules(['except' => ['username']]); -// get the rules for only the "city" and "state" fields -$rules = $model->getValidationRules(['only' => ['city', 'state']]); diff --git a/user_guide_src/source/models/model/038.php b/user_guide_src/source/models/model/038.php deleted file mode 100644 index 2e61e1fc94f8..000000000000 --- a/user_guide_src/source/models/model/038.php +++ /dev/null @@ -1,15 +0,0 @@ - 'max_length[19]|is_natural_no_zero', - 'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,{id}]', - ]; -} diff --git a/user_guide_src/source/models/model/039.php b/user_guide_src/source/models/model/039.php deleted file mode 100644 index fa1b37d0f839..000000000000 --- a/user_guide_src/source/models/model/039.php +++ /dev/null @@ -1,6 +0,0 @@ - 4, - 'email' => 'foo@example.com', -]; diff --git a/user_guide_src/source/models/model/040.php b/user_guide_src/source/models/model/040.php deleted file mode 100644 index 94de0d042171..000000000000 --- a/user_guide_src/source/models/model/040.php +++ /dev/null @@ -1,15 +0,0 @@ - 'max_length[19]|is_natural_no_zero', - 'email' => 'required|max_length[254]|valid_email|is_unique[users.email,id,4]', - ]; -} diff --git a/user_guide_src/source/models/model/041.php b/user_guide_src/source/models/model/041.php deleted file mode 100644 index d5b73ec3869e..000000000000 --- a/user_guide_src/source/models/model/041.php +++ /dev/null @@ -1,12 +0,0 @@ -protect(false) - ->insert($data) - ->protect(true); diff --git a/user_guide_src/source/models/model/043.php b/user_guide_src/source/models/model/043.php deleted file mode 100644 index 44a962a082f8..000000000000 --- a/user_guide_src/source/models/model/043.php +++ /dev/null @@ -1,3 +0,0 @@ -builder(); diff --git a/user_guide_src/source/models/model/044.php b/user_guide_src/source/models/model/044.php deleted file mode 100644 index 229af898adcb..000000000000 --- a/user_guide_src/source/models/model/044.php +++ /dev/null @@ -1,3 +0,0 @@ -builder('groups'); diff --git a/user_guide_src/source/models/model/045.php b/user_guide_src/source/models/model/045.php deleted file mode 100644 index e4d005fb3acc..000000000000 --- a/user_guide_src/source/models/model/045.php +++ /dev/null @@ -1,5 +0,0 @@ -where('status', 'active') - ->orderBy('last_login', 'asc') - ->findAll(); diff --git a/user_guide_src/source/models/model/046.php b/user_guide_src/source/models/model/046.php deleted file mode 100644 index 909db8e9594d..000000000000 --- a/user_guide_src/source/models/model/046.php +++ /dev/null @@ -1,3 +0,0 @@ -escape($name); diff --git a/user_guide_src/source/models/model/047.php b/user_guide_src/source/models/model/047.php deleted file mode 100644 index ab2dfdecc85b..000000000000 --- a/user_guide_src/source/models/model/047.php +++ /dev/null @@ -1,3 +0,0 @@ -asArray()->where('status', 'active')->findAll(); diff --git a/user_guide_src/source/models/model/048.php b/user_guide_src/source/models/model/048.php deleted file mode 100644 index 799e88726d93..000000000000 --- a/user_guide_src/source/models/model/048.php +++ /dev/null @@ -1,7 +0,0 @@ -asObject()->where('status', 'active')->findAll(); - -// Return as custom class instances -$users = $userModel->asObject('User')->where('status', 'active')->findAll(); diff --git a/user_guide_src/source/models/model/049.php b/user_guide_src/source/models/model/049.php deleted file mode 100644 index 92493d8e47d5..000000000000 --- a/user_guide_src/source/models/model/049.php +++ /dev/null @@ -1,6 +0,0 @@ -chunk(100, static function ($data) { - // do something. - // $data is a single row of data. -}); diff --git a/user_guide_src/source/models/model/050.php b/user_guide_src/source/models/model/050.php deleted file mode 100644 index 5f5a4fdb7278..000000000000 --- a/user_guide_src/source/models/model/050.php +++ /dev/null @@ -1,22 +0,0 @@ -allowCallbacks(false)->find(1); // No callbacks triggered -$model->find(1); // Callbacks subject to original property value diff --git a/user_guide_src/source/models/model/054.php b/user_guide_src/source/models/model/054.php deleted file mode 100644 index c67b4828acfd..000000000000 --- a/user_guide_src/source/models/model/054.php +++ /dev/null @@ -1,27 +0,0 @@ -getCachedItem($data['id'])) { - $data['data'] = $item; - $data['returnData'] = true; - - return $data; - } - - // ... - } -} diff --git a/user_guide_src/source/models/model/055.php b/user_guide_src/source/models/model/055.php deleted file mode 100644 index 537199753d49..000000000000 --- a/user_guide_src/source/models/model/055.php +++ /dev/null @@ -1,15 +0,0 @@ -db = $db; - } -} diff --git a/user_guide_src/source/models/model/056.php b/user_guide_src/source/models/model/056.php deleted file mode 100644 index 9635a1c1d095..000000000000 --- a/user_guide_src/source/models/model/056.php +++ /dev/null @@ -1,3 +0,0 @@ -allowEmptyInserts()->insert([]); diff --git a/user_guide_src/source/models/model/057.php b/user_guide_src/source/models/model/057.php deleted file mode 100644 index 8184fd352b9d..000000000000 --- a/user_guide_src/source/models/model/057.php +++ /dev/null @@ -1,17 +0,0 @@ - 'int', - 'birthdate' => '?datetime', - 'hobbies' => 'json-array', - 'active' => 'int-bool', - ]; - // ... -} diff --git a/user_guide_src/source/models/model/058.php b/user_guide_src/source/models/model/058.php deleted file mode 100644 index b30d216fc688..000000000000 --- a/user_guide_src/source/models/model/058.php +++ /dev/null @@ -1,40 +0,0 @@ - 'base64', - ]; - - // Bind the type to the handler - protected array $castHandlers = [ - 'base64' => CastBase64::class, - ]; - - // ... -} diff --git a/user_guide_src/source/models/model/060.php b/user_guide_src/source/models/model/060.php deleted file mode 100644 index b0c9107d7930..000000000000 --- a/user_guide_src/source/models/model/060.php +++ /dev/null @@ -1,27 +0,0 @@ - 'class[App\SomeClass, param2, param3]', - ]; - - // Bind the type to the handler - protected array $castHandlers = [ - 'class' => SomeHandler::class, - ]; - - // ... -} diff --git a/user_guide_src/source/models/model/062.php b/user_guide_src/source/models/model/062.php deleted file mode 100644 index 5a3496b6aae3..000000000000 --- a/user_guide_src/source/models/model/062.php +++ /dev/null @@ -1,27 +0,0 @@ - - * string(13) "App\SomeClass" - * [1]=> - * string(6) "param2" - * [2]=> - * string(6) "param3" - * } - */ - } -} diff --git a/user_guide_src/source/models/model/063.php b/user_guide_src/source/models/model/063.php deleted file mode 100644 index cc75d0648421..000000000000 --- a/user_guide_src/source/models/model/063.php +++ /dev/null @@ -1,13 +0,0 @@ -where('my_dt_field', $now->format('Y-m-d H:i:s.u'))->findAll(); -// Generates: SELECT * FROM `my_table` WHERE `my_dt_field` = '2024-07-28 18:57:58.900326' - -// But the following code loses the microseconds. -$model->where('my_dt_field', $now)->findAll(); -// Generates: SELECT * FROM `my_table` WHERE `my_dt_field` = '2024-07-28 18:57:58' diff --git a/user_guide_src/source/outgoing/alternative_php.rst b/user_guide_src/source/outgoing/alternative_php.rst deleted file mode 100644 index 9b2660b988ee..000000000000 --- a/user_guide_src/source/outgoing/alternative_php.rst +++ /dev/null @@ -1,37 +0,0 @@ -################################### -Alternate PHP Syntax for View Files -################################### - -If you do not utilize a templating engine to simplify output, you'll be using pure PHP in your View files. To minimize -the PHP code in these files, and to make it easier to identify the code blocks, it is recommended that you use PHP's -alternative syntax for control structures and short tag echo statements. If you are not familiar with this syntax, it -allows you to eliminate the braces from your code, and eliminate "echo" statements. - -Alternative Echoes -================== - -Normally, to echo or print out a variable, you would do this:: - - - -With the alternative syntax, you can instead do it this way:: - - - -Alternative Control Structures -============================== - -Control structures, like if, for, foreach, and while can be written in a simplified format as well. Here is an example -using ``foreach``: - -.. literalinclude:: alternative_php/001.php - -Notice that there are no braces. Instead, the end brace is replaced with ``endforeach``. Each of the control structures -listed above has a similar closing syntax: ``endif``, ``endfor``, ``endforeach``, and ``endwhile``. - -Also notice that instead of using a semicolon after each structure (except the last one), there is a colon. This is -important! - -Here is another example, using ``if``/``elseif``/``else``. Notice the colons: - -.. literalinclude:: alternative_php/002.php diff --git a/user_guide_src/source/outgoing/alternative_php/001.php b/user_guide_src/source/outgoing/alternative_php/001.php deleted file mode 100644 index b9c543ef4211..000000000000 --- a/user_guide_src/source/outgoing/alternative_php/001.php +++ /dev/null @@ -1,9 +0,0 @@ -
      - - - -
    • - - - -
    diff --git a/user_guide_src/source/outgoing/alternative_php/002.php b/user_guide_src/source/outgoing/alternative_php/002.php deleted file mode 100644 index 47c5afcfb95a..000000000000 --- a/user_guide_src/source/outgoing/alternative_php/002.php +++ /dev/null @@ -1,13 +0,0 @@ - - -

    Hi Sally

    - - - -

    Hi Joe

    - - - -

    Hi unknown user

    - - diff --git a/user_guide_src/source/outgoing/api_responses.rst b/user_guide_src/source/outgoing/api_responses.rst deleted file mode 100644 index 7c429b6504d4..000000000000 --- a/user_guide_src/source/outgoing/api_responses.rst +++ /dev/null @@ -1,333 +0,0 @@ -############# -API Responses -############# - -Much of modern PHP development requires building APIs, whether simply to provide data for a JavaScript-heavy single-page -application, or as a standalone product. CodeIgniter provides a couple of traits that can be used with any controller to -make common response types simple, with no need to remember which HTTP status code should be returned for which response -types. - -.. contents:: - :local: - :depth: 2 - -***************** -Response Examples -***************** - -The following example shows a common usage pattern within your controllers. - -.. literalinclude:: api_responses/001.php - -In this example, an HTTP status code of 201 is returned, with the generic status message, 'Created'. Methods exist for -the most common use cases: - -.. literalinclude:: api_responses/002.php - -.. _api-response-trait-handling-response-types: - -*********************** -Handling Response Types -*********************** - -When you pass your data to any of these methods, they will determine the data type to format the results as based on the -following criteria: - -* The format is determined according to the controller's ``$this->format`` value. If that is ``null``, it will try to - negotiate the content type with what the client asked for, defaulting to the first element (JSON by default) in the - ``$supportedResponseFormats`` property within **app/Config/Format.php**. -* The data will be formatted according to the format. If the format is not JSON and data is a string, it will be treated - as HTML to send back to the client. - -.. note:: Prior to v4.5.0, due to a bug, if data is a string, it will be treated as HTML even if the format is JSON. - -To define the formatter that is used, edit **app/Config/Format.php**. The ``$supportedResponseFormats`` property -contains a list of MIME types that your application can automatically format the response for. By default, the system -knows how to format both XML and JSON responses: - -.. literalinclude:: api_responses/003.php - -.. note:: Since ``v4.7.0``, you can change the default JSON encoding depth by editing the **app/Config/Format.php** - file. The ``$jsonEncodeDepth`` value defines the maximum depth, with a default of ``512``. - -This is the array that is used during :doc:`Content Negotiation ` to determine which type -of response to return. If no matches are found between what the client requested and what you support, the first format -in this array is what will be returned. - -Next, you need to define the class that is used to format the array of data. This must be a fully qualified class name, -and the class must implement ``CodeIgniter\Format\FormatterInterface``. Formatters come out of the box that support both -JSON and XML: - -.. literalinclude:: api_responses/004.php - -So, if your request asks for JSON formatted data in an **Accept** header, the data array you pass to any of the -``respond*`` or ``fail*`` methods will be formatted by the ``CodeIgniter\Format\JSONFormatter`` class. The resulting -JSON data will be sent back to the client. - -*************** -Class Reference -*************** - -.. php:method:: setResponseFormat($format) - - :param string $format: The type of response to return, either ``json`` or ``xml`` - - This defines the format to be used when formatting arrays in responses. If you provide a ``null`` value for - ``$format``, it will be automatically determined through content negotiation. - - .. literalinclude:: api_responses/005.php - -.. php:method:: respond($data[, $statusCode = 200[, $message = '']]) - - :param mixed $data: The data to return to the client. Either string or array. - :param int $statusCode: The HTTP status code to return. Defaults to 200 - :param string $message: A custom "reason" message to return. - - This is the method used by all other methods in this trait to return a response to the client. - - The ``$data`` element can be either a string or an array. By default, a string will be returned as HTML, while an - array will be run through json_encode and returned as JSON, unless - :doc:`Content Negotiation ` determines it should be returned in a different format. - - If a ``$message`` string is passed, it will be used in place of the standard IANA reason codes for the response - status. Not every client will respect the custom codes, though, and will use the IANA standards that match the - status code. - - .. note:: Since it sets the status code and body on the active Response instance, this should always be the final - method in the script execution. - -.. php:method:: fail($messages[, int $status = 400[, string $code = null[, string $message = '']]]) - - :param mixed $messages: A string or array of strings that contain error messages encountered. - :param int $status: The HTTP status code to return. Defaults to 400. - :param string $code: A custom, API-specific, error code. - :param string $message: A custom "reason" message to return. - :returns: A multi-part response in the client's preferred format. - - This is the generic method used to represent a failed response, and is used by all of the other "fail" methods. - - The ``$messages`` element can be either a string or an array of strings. - - The ``$status`` parameter is the HTTP status code that should be returned. - - Since many APIs are better served using custom error codes, a custom error code can be passed in the third - parameter. If no value is present, it will be the same as ``$status``. - - If a ``$message`` string is passed, it will be used in place of the standard IANA reason codes for the response - status. Not every client will respect the custom codes, though, and will use the IANA standards that match the - status code. - - The response is an array with three elements: ``status``, ``code``, and ``messages``. - - - The ``status`` element contains the status code of the error. - - The ``code`` element contains a custom, API-specific error code. - - The ``messages`` element contains an array of error messages. - - Depending on the number of error messages, the response would look something like: - - .. literalinclude:: api_responses/006.php - -.. php:method:: respondCreated($data = null[, string $message = '']) - - :param mixed $data: The data to return to the client. Either string or array. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when a new resource was created, typically 201: - - .. literalinclude:: api_responses/007.php - -.. php:method:: respondDeleted($data = null[, string $message = '']) - - :param mixed $data: The data to return to the client. Either string or array. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when a resource was deleted as the result of this API call, typically 200. - - .. literalinclude:: api_responses/008.php - -.. php:method:: respondNoContent(string $message = 'No Content') - - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when a command was successfully executed by the server but there is no - meaningful reply to send back to the client, typically 204. - - .. literalinclude:: api_responses/009.php - -.. php:method:: failUnauthorized(string $description = 'Unauthorized'[, string $code = null[, string $message = '']]) - - :param string $description: The error message to show the user. - :param string $code: A custom, API-specific, error code. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when the user either has not been authorized, or has incorrect - authorization. Status code is 401. - - .. literalinclude:: api_responses/010.php - -.. php:method:: failForbidden(string $description = 'Forbidden'[, string $code=null[, string $message = '']]) - - :param string $description: The error message to show the user. - :param string $code: A custom, API-specific, error code. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Unlike ``failUnauthorized()``, this method should be used when the requested API endpoint is never allowed. - Unauthorized implies the client is encouraged to try again with different credentials. Forbidden means the client - should not try again because it won't help. Status code is 403. - - .. literalinclude:: api_responses/011.php - -.. php:method:: failNotFound(string $description = 'Not Found'[, string $code=null[, string $message = '']]) - - :param string $description: The error message to show the user. - :param string $code: A custom, API-specific, error code. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when the requested resource cannot be found. Status code is 404. - - .. literalinclude:: api_responses/012.php - -.. php:method:: failValidationErrors($errors[, string $code=null[, string $message = '']]) - - :param mixed $errors: The error message or array of messages to show the user. - :param string $code: A custom, API-specific, error code. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when data the client sent did not pass validation rules. Status code is - typically 400. - - .. literalinclude:: api_responses/013.php - -.. php:method:: failResourceExists(string $description = 'Conflict'[, string $code=null[, string $message = '']]) - - :param string $description: The error message to show the user. - :param string $code: A custom, API-specific, error code. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when the resource the client is trying to create already exists. Status code - is typically 409. - - .. literalinclude:: api_responses/014.php - -.. php:method:: failResourceGone(string $description = 'Gone'[, string $code=null[, string $message = '']]) - - :param string $description: The error message to show the user. - :param string $code: A custom, API-specific, error code. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when the requested resource was previously deleted and is no longer - available. Status code is typically 410. - - .. literalinclude:: api_responses/015.php - -.. php:method:: failTooManyRequests(string $description = 'Too Many Requests'[, string $code=null[, string $message = '']]) - - :param string $description: The error message to show the user. - :param string $code: A custom, API-specific, error code. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when the client has called an API endpoint too many times. This might be due - to some form of throttling or rate limiting. Status code is typically 429. - - .. literalinclude:: api_responses/016.php - -.. php:method:: failServerError(string $description = 'Internal Server Error'[, string $code = null[, string $message = '']]) - - :param string $description: The error message to show the user. - :param string $code: A custom, API-specific, error code. - :param string $message: A custom "reason" message to return. - :returns: The value of the Response object's ``send()`` method. - - Sets the appropriate status code to use when there is a server error. - - .. literalinclude:: api_responses/017.php - -.. _api_response_trait_paginate: - -******************** -Pagination Responses -******************** - -When returning paginated results from an API endpoint, you can use the ``paginate()`` method to return the results along -with the pagination information. This helps to keep consistent responses across your API, while providing all of the -information that clients will need to properly page through the results. - -------------- -Example Usage -------------- - -.. literalinclude:: api_responses/018.php - -A typical response might look like: - -.. code-block:: json - - { - "data": [ - { - "id": 1, - "username": "admin", - "email": "admin@example.com" - }, - { - "id": 2, - "username": "user", - "email": "user@example.com" - } - ], - "meta": { - "page": 1, - "perPage": 20, - "total": 2, - "totalPages": 1 - }, - "links": { - "self": "http://example.com/users?page=1", - "first": "http://example.com/users?page=1", - "last": "http://example.com/users?page=1", - "next": null, - "prev": null - } - } - -The ``paginate()`` method will always wrap the results in a ``data`` element, and will also include ``meta`` and -``links`` elements to help the client page through the results. If there are no results, the ``data`` element will be an -empty array, and the ``meta`` and ``links`` elements will still be present, but with values that indicate no results. - -You can also pass it a Builder instance instead of a Model, as long as the Builder is properly configured with the table -name and any necessary joins or where clauses. - -.. literalinclude:: api_responses/019.php - -*************** -Class Reference -*************** - -.. php:method:: paginate(Model|BaseBuilder $resource, int $perPage = 20, ?string $transformWith = null) - - :param Model|BaseBuilder $resource: The resource to paginate, either a Model or a Builder instance. - :param int $perPage: The number of items to return per page. - :param string|null $transformWith: Optional transformer class name to transform the results. - - Generates a paginated response from the given resource. The resource can be either a Model or a Builder instance. - The method will automatically determine the current page from the request's query parameters. The response will - include the paginated data, along with metadata about the pagination state and links to navigate through the pages. - - If you provide a ``$transformWith`` parameter with a transformer class name, each item in the paginated results will - be transformed using that transformer before being returned. This is useful for controlling the structure and - content of your API responses. See :ref:`API Transformers ` for more information on creating and - using transformers. - - Example with transformer: - - .. literalinclude:: api_responses/020.php diff --git a/user_guide_src/source/outgoing/api_responses/001.php b/user_guide_src/source/outgoing/api_responses/001.php deleted file mode 100644 index 930ad3f0c23a..000000000000 --- a/user_guide_src/source/outgoing/api_responses/001.php +++ /dev/null @@ -1,20 +0,0 @@ -save($this->request->getPost()); - - // Respond with 201 status code - return $this->respondCreated(); - } -} diff --git a/user_guide_src/source/outgoing/api_responses/002.php b/user_guide_src/source/outgoing/api_responses/002.php deleted file mode 100644 index 5484a5a3f581..000000000000 --- a/user_guide_src/source/outgoing/api_responses/002.php +++ /dev/null @@ -1,37 +0,0 @@ -respond($data, 200); - -// Generic failure response -$this->fail($errors, 400); - -// Item created response -$this->respondCreated($data); - -// Item successfully deleted -$this->respondDeleted($data); - -// Command executed by no response required -$this->respondNoContent($message); - -// Client isn't authorized -$this->failUnauthorized($description); - -// Forbidden action -$this->failForbidden($description); - -// Resource Not Found -$this->failNotFound($description); - -// Data was not validated -$this->failValidationErrors($errors); - -// Resource already exists -$this->failResourceExists($description); - -// Resource previously deleted -$this->failResourceGone($description); - -// Client made too many requests -$this->failTooManyRequests($description); diff --git a/user_guide_src/source/outgoing/api_responses/003.php b/user_guide_src/source/outgoing/api_responses/003.php deleted file mode 100644 index 6e99762ccaed..000000000000 --- a/user_guide_src/source/outgoing/api_responses/003.php +++ /dev/null @@ -1,15 +0,0 @@ - \CodeIgniter\Format\JSONFormatter::class, - 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, - ]; - - // ... -} diff --git a/user_guide_src/source/outgoing/api_responses/005.php b/user_guide_src/source/outgoing/api_responses/005.php deleted file mode 100644 index dbe887df0b63..000000000000 --- a/user_guide_src/source/outgoing/api_responses/005.php +++ /dev/null @@ -1,3 +0,0 @@ -setResponseFormat('json')->respond(['error' => false]); diff --git a/user_guide_src/source/outgoing/api_responses/006.php b/user_guide_src/source/outgoing/api_responses/006.php deleted file mode 100644 index 854473a9657d..000000000000 --- a/user_guide_src/source/outgoing/api_responses/006.php +++ /dev/null @@ -1,20 +0,0 @@ - 400, - 'code' => '321', - 'messages' => [ - 'error' => 'An error occurred', - ], -]; - -// Example response with multiple error messages per field -$response = [ - 'status' => 400, - 'code' => '321a', - 'messages' => [ - 'foo' => 'Error message 1', - 'bar' => 'Error message 2', - ], -]; diff --git a/user_guide_src/source/outgoing/api_responses/007.php b/user_guide_src/source/outgoing/api_responses/007.php deleted file mode 100644 index 4e30f3e6b6ac..000000000000 --- a/user_guide_src/source/outgoing/api_responses/007.php +++ /dev/null @@ -1,5 +0,0 @@ -insert($data); - -return $this->respondCreated($user); diff --git a/user_guide_src/source/outgoing/api_responses/008.php b/user_guide_src/source/outgoing/api_responses/008.php deleted file mode 100644 index abbd2322bcda..000000000000 --- a/user_guide_src/source/outgoing/api_responses/008.php +++ /dev/null @@ -1,5 +0,0 @@ -delete($id); - -return $this->respondDeleted(['id' => $id]); diff --git a/user_guide_src/source/outgoing/api_responses/009.php b/user_guide_src/source/outgoing/api_responses/009.php deleted file mode 100644 index 8eea1b15dfaf..000000000000 --- a/user_guide_src/source/outgoing/api_responses/009.php +++ /dev/null @@ -1,5 +0,0 @@ -respondNoContent(); diff --git a/user_guide_src/source/outgoing/api_responses/010.php b/user_guide_src/source/outgoing/api_responses/010.php deleted file mode 100644 index 3de055d94cba..000000000000 --- a/user_guide_src/source/outgoing/api_responses/010.php +++ /dev/null @@ -1,3 +0,0 @@ -failUnauthorized('Invalid Auth token'); diff --git a/user_guide_src/source/outgoing/api_responses/011.php b/user_guide_src/source/outgoing/api_responses/011.php deleted file mode 100644 index 44f3c4eeb23e..000000000000 --- a/user_guide_src/source/outgoing/api_responses/011.php +++ /dev/null @@ -1,3 +0,0 @@ -failForbidden('Invalid API endpoint.'); diff --git a/user_guide_src/source/outgoing/api_responses/012.php b/user_guide_src/source/outgoing/api_responses/012.php deleted file mode 100644 index 2c8d8b29175a..000000000000 --- a/user_guide_src/source/outgoing/api_responses/012.php +++ /dev/null @@ -1,3 +0,0 @@ -failNotFound('User 13 cannot be found.'); diff --git a/user_guide_src/source/outgoing/api_responses/013.php b/user_guide_src/source/outgoing/api_responses/013.php deleted file mode 100644 index d470b1079d3b..000000000000 --- a/user_guide_src/source/outgoing/api_responses/013.php +++ /dev/null @@ -1,3 +0,0 @@ -failValidationErrors($validation->getErrors()); diff --git a/user_guide_src/source/outgoing/api_responses/014.php b/user_guide_src/source/outgoing/api_responses/014.php deleted file mode 100644 index d0772239c43e..000000000000 --- a/user_guide_src/source/outgoing/api_responses/014.php +++ /dev/null @@ -1,3 +0,0 @@ -failResourceExists('A user already exists with that email.'); diff --git a/user_guide_src/source/outgoing/api_responses/015.php b/user_guide_src/source/outgoing/api_responses/015.php deleted file mode 100644 index a8ce10dc9ff6..000000000000 --- a/user_guide_src/source/outgoing/api_responses/015.php +++ /dev/null @@ -1,3 +0,0 @@ -failResourceGone('That user has been previously deleted.'); diff --git a/user_guide_src/source/outgoing/api_responses/016.php b/user_guide_src/source/outgoing/api_responses/016.php deleted file mode 100644 index 197376fe271f..000000000000 --- a/user_guide_src/source/outgoing/api_responses/016.php +++ /dev/null @@ -1,3 +0,0 @@ -failTooManyRequests('You must wait 15 seconds before making another request.'); diff --git a/user_guide_src/source/outgoing/api_responses/017.php b/user_guide_src/source/outgoing/api_responses/017.php deleted file mode 100644 index 5bb665f3dd60..000000000000 --- a/user_guide_src/source/outgoing/api_responses/017.php +++ /dev/null @@ -1,3 +0,0 @@ -failServerError('Server error.'); diff --git a/user_guide_src/source/outgoing/api_responses/018.php b/user_guide_src/source/outgoing/api_responses/018.php deleted file mode 100644 index efacd81ac89b..000000000000 --- a/user_guide_src/source/outgoing/api_responses/018.php +++ /dev/null @@ -1,18 +0,0 @@ -where('active', 1); - - return $this->paginate($model, 20); - } -} diff --git a/user_guide_src/source/outgoing/api_responses/019.php b/user_guide_src/source/outgoing/api_responses/019.php deleted file mode 100644 index 63f249085c8a..000000000000 --- a/user_guide_src/source/outgoing/api_responses/019.php +++ /dev/null @@ -1,18 +0,0 @@ -table('users') - ->where('active', 1); - - return $this->paginate(resource: $builder, perPage: 20); - } -} diff --git a/user_guide_src/source/outgoing/api_responses/020.php b/user_guide_src/source/outgoing/api_responses/020.php deleted file mode 100644 index e54e8cc69fff..000000000000 --- a/user_guide_src/source/outgoing/api_responses/020.php +++ /dev/null @@ -1,18 +0,0 @@ -paginate(resource: $model, perPage: 20, transformWith: UserTransformer::class); - } -} diff --git a/user_guide_src/source/outgoing/api_transformers.rst b/user_guide_src/source/outgoing/api_transformers.rst deleted file mode 100644 index 4355235e845e..000000000000 --- a/user_guide_src/source/outgoing/api_transformers.rst +++ /dev/null @@ -1,366 +0,0 @@ -.. _api_transformers: - -############# -API Resources -############# - -When building APIs, you often need to transform your data models into a consistent format before sending them to the -client. API Resources, implemented through transformers, provide a clean way to convert your entities, arrays, or -objects into structured API responses. They help separate your internal data structure from what you expose through your -API, making it easier to maintain and evolve your API over time. - -.. contents:: - :local: - :depth: 2 - -************* -Quick Example -************* - -The following example shows a common usage pattern for transformers in your application. - -.. literalinclude:: api_transformers/001.php - -In this example, the ``UserTransformer`` defines which fields from a user entity should be included in the API response. -The ``transform()`` method converts a single resource, while ``transformMany()`` handles collections of resources. - -********************** -Creating a Transformer -********************** - -To create a transformer, extend the ``BaseTransformer`` class and implement the ``toArray()`` method to define your API -resource structure. The ``toArray()`` method receives the resource being transformed as a parameter, allowing you to -access and transform its data. - -Basic Transformer -================= - -.. literalinclude:: api_transformers/002.php - -The ``toArray()`` method receives the resource (entity, array, or object) as its parameter and defines the structure of -your API response. You can include any fields you want from the resource, and you can also rename or transform values as -needed. - -Generating Transformer Files -============================ - -CodeIgniter provides a CLI command to quickly generate transformer skeleton files: - -.. code-block:: console - - php spark make:transformer User - -This creates a new transformer file at **app/Transformers/User.php** with the basic structure already in place. - -Command Options ---------------- - -The ``make:transformer`` command supports several options: - -**--suffix** - Appends "Transformer" to the class name: - - .. code-block:: console - - php spark make:transformer User --suffix - - Creates **app/Transformers/UserTransformer.php** - -**--namespace** - Specifies a custom root namespace: - - .. code-block:: console - - php spark make:transformer User --namespace MyCompany\API - -**--force** - Forces overwriting an existing file: - - .. code-block:: console - - php spark make:transformer User --force - -Subdirectories --------------- - -You can organize transformers into subdirectories by including the path in the name: - -.. code-block:: console - - php spark make:transformer api/v1/User - -This creates **app/Transformers/Api/V1/User.php** with the appropriate namespace ``App\Transformers\Api\V1``. - -Using Transformers in Controllers -================================= - -Once you've created a transformer, you can use it in your controllers to transform data before returning it to the -client. - -.. literalinclude:: api_transformers/003.php - -*************** -Field Filtering -*************** - -The transformer automatically supports field filtering through the ``fields`` query parameter of the current URL. This -allows API clients to request only the specific fields they need, reducing bandwidth and improving performance. - -.. literalinclude:: api_transformers/007.php - -A request to ``/users/1?fields=id,name`` would return only: - -.. code-block:: json - - { - "id": 1, - "name": "John Doe" - } - -Restricting Available Fields -============================ - -By default, clients can request any field defined in your ``toArray()`` method. You can restrict which fields are -allowed by overriding the ``getAllowedFields()`` method: - -.. literalinclude:: api_transformers/008.php - -Now, even if a client requests ``/users/1?fields=email``, an ``ApiException`` will be thrown because ``email`` is not in -the allowed fields list. - -*************************** -Including Related Resources -*************************** - -Transformers support loading related resources through the ``include`` query parameter. This follows a common API -pattern where clients can specify which relationships they want included. While relationships are the most frequent use -case, you can include any additional data you want by defining custom include methods. - -Defining Include Methods -======================== - -To support including related resources, create methods prefixed with ``include`` followed by the resource name. Inside -these methods, you can access the current resource being transformed via ``$this->resource``: - -.. literalinclude:: api_transformers/009.php - -Note how the include methods use ``$this->resource['id']`` to access the ID of the user being transformed. The -``$this->resource`` property is automatically set by the transformer when ``transform()`` is called. - -Clients can now request: ``/users/1?include=posts,comments`` - -The response would include: - -.. code-block:: json - - { - "id": 1, - "name": "John Doe", - "email": "john@example.com", - "posts": [ - { - "id": 1, - "title": "First Post" - } - ], - "comments": [ - { - "id": 1, - "content": "Great article!" - } - ] - } - -.. note:: The ``fields`` and ``include`` query parameters describe the **root** resource only. Transformers instantiated - inside an ``include*()`` method (such as ``PostTransformer`` above) are treated as nested resources: when created - **without an explicit request** they do **not** inherit the root request's ``fields``/``include`` state. This - prevents the parent's query parameters from leaking into related resources, which could otherwise cause incorrect - field filtering or unexpected/recursive includes. If you deliberately pass a request to a nested transformer, that - request's scope is honored. - -Restricting Available Includes -============================== - -Similar to field filtering, you can restrict which relationships can be included by overriding the -``getAllowedIncludes()`` method: - -.. literalinclude:: api_transformers/010.php - -If you want to disable all includes, return an empty array: - -.. literalinclude:: api_transformers/011.php - -Include Validation -================== - -The transformer automatically validates that any requested includes have corresponding ``include*()`` methods defined in -your transformer class. If a client requests an include that doesn't exist, an ``ApiException`` will be thrown. - -For example, if a client requests:: - - GET /api/users?include=invalid - -And your transformer doesn't have an ``includeInvalid()`` method, an exception will be thrown with the message: "Missing -include method for: invalid". - -This helps catch typos and prevents unexpected behavior. - -************************ -Transforming Collections -************************ - -The ``transformMany()`` method makes it easy to transform arrays of resources: - -.. literalinclude:: api_transformers/012.php - -The ``transformMany()`` method applies the same transformation logic to each item in the collection, including any field -filtering or includes specified in the request. - -********************************* -Working with Different Data Types -********************************* - -Transformers can handle various data types, not just entities. - -Transforming Entities -===================== - -When you pass an ``Entity`` instance to ``transform()``, it automatically calls the entity's ``toArray()`` method to get -the data: - -.. literalinclude:: api_transformers/013.php - -Transforming Arrays -=================== - -You can transform plain arrays as well: - -.. literalinclude:: api_transformers/014.php - -Transforming Objects -==================== - -Any object can be cast to an array and transformed: - -.. literalinclude:: api_transformers/015.php - -Using toArray() Only -==================== - -If you don't pass a resource to ``transform()``, it will use the data from your ``toArray()`` method: - -.. literalinclude:: api_transformers/016.php - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\API - -.. php:class:: BaseTransformer - - .. php:method:: __construct(?IncomingRequest $request = null) - - :param IncomingRequest|null $request: Optional request instance. If not provided, the global request will be used. - - Initializes the transformer and extracts the ``fields`` and ``include`` query parameters from the request. - - .. note:: When no request is explicitly passed, the global request's ``fields`` and ``include`` are read - **only for the root transformer**. A transformer constructed during a nested transformation (i.e. inside an - ``include*()`` method) without an explicit request still uses the global request object, but does not read - ``fields``/``include`` from it, to avoid leaking the root's scope. Passing an explicit request always - applies that request's scope, regardless of nesting. - - .. php:method:: toArray(mixed $resource) - - :param mixed $resource: The resource being transformed (Entity, array, object, or null) - :returns: The array representation of the resource - :rtype: array - - This abstract method must be implemented by child classes to define the structure of the API resource. The - resource parameter contains the data being transformed. Return an array with the fields you want to include in - the API response, accessing data from the ``$resource`` parameter. - - .. literalinclude:: api_transformers/017.php - - .. php:method:: transform($resource = null) - - :param mixed $resource: The resource to transform (Entity, array, object, or null) - :returns: The transformed array - :rtype: array - - Transforms the given resource into an array by calling ``toArray()`` with the resource data. If ``$resource`` is - ``null``, passes ``null`` to ``toArray()``. If it's an Entity, extracts its array representation first. - Otherwise, casts it to an array. - - The resource is also stored in ``$this->resource`` so include methods can access it. - - The method automatically applies field filtering and includes based on query parameters. - - .. literalinclude:: api_transformers/018.php - - .. php:method:: transformMany(array $resources) - - :param array $resources: The array of resources to transform - :returns: Array of transformed resources - :rtype: array - - Transforms a collection of resources by calling ``transform()`` on each item. Field filtering and includes are - applied consistently to all items. - - .. literalinclude:: api_transformers/019.php - - .. php:method:: getAllowedFields() - - :returns: Array of allowed field names, or ``null`` to allow all fields - :rtype: array|null - - Override this method to restrict which fields can be requested via the ``fields`` query parameter. Return - ``null`` (the default) to allow all fields from ``toArray()``. Return an array of field names to create a - whitelist of allowed fields. - - .. literalinclude:: api_transformers/022.php - - .. php:method:: getAllowedIncludes() - - :returns: Array of allowed include names, or ``null`` to allow all includes - :rtype: array|null - - Override this method to restrict which related resources can be included via the ``include`` query parameter. - Return ``null`` (the default) to allow all includes that have corresponding methods. Return an array of include - names to create a whitelist. Return an empty array to disable all includes. - - .. literalinclude:: api_transformers/023.php - -******************* -Exception Reference -******************* - -.. php:class:: ApiException - - .. php:staticmethod:: forInvalidFields(string $field) - - :param string $field: The invalid field name(s) - :returns: ApiException instance - :rtype: ApiException - - Thrown when a client requests a field via the ``fields`` query parameter that is not in the allowed fields list. - - .. php:staticmethod:: forInvalidIncludes(string $include) - - :param string $include: The invalid include name(s) - :returns: ApiException instance - :rtype: ApiException - - Thrown when a client requests an include via the ``include`` query parameter that is not in the allowed includes - list. - - .. php:staticmethod:: forMissingInclude(string $include) - - :param string $include: The missing include method name - :returns: ApiException instance - :rtype: ApiException - - Thrown when a client requests an include via the ``include`` query parameter, but the corresponding - ``include*()`` method does not exist in the transformer class. This validation ensures that all requested - includes have proper handler methods defined. diff --git a/user_guide_src/source/outgoing/api_transformers/001.php b/user_guide_src/source/outgoing/api_transformers/001.php deleted file mode 100644 index b3a7bb0ad9bf..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/001.php +++ /dev/null @@ -1,24 +0,0 @@ - $resource['id'], - 'name' => $resource['name'], - 'email' => $resource['email'], - 'created_at' => $resource['created_at'], - ]; - } -} - -// In your controller -$user = model('UserModel')->find(1); -$transformer = new UserTransformer(); - -return $this->respond($transformer->transform($user)); diff --git a/user_guide_src/source/outgoing/api_transformers/002.php b/user_guide_src/source/outgoing/api_transformers/002.php deleted file mode 100644 index 1980e4951ca3..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/002.php +++ /dev/null @@ -1,18 +0,0 @@ - $resource['id'], - 'username' => $resource['name'], // Renaming the field - 'email' => $resource['email'], - 'member_since' => date('Y-m-d', strtotime($resource['created_at'])), // Formatting - ]; - } -} diff --git a/user_guide_src/source/outgoing/api_transformers/003.php b/user_guide_src/source/outgoing/api_transformers/003.php deleted file mode 100644 index 8f4616091c64..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/003.php +++ /dev/null @@ -1,33 +0,0 @@ -find($id); - - if (! $user) { - return $this->failNotFound('User not found'); - } - - $transformer = new UserTransformer(); - - return $this->respond($transformer->transform($user)); - } - - public function index() - { - $users = model('UserModel')->findAll(); - - $transformer = new UserTransformer(); - - return $this->respond($transformer->transformMany($users)); - } -} diff --git a/user_guide_src/source/outgoing/api_transformers/007.php b/user_guide_src/source/outgoing/api_transformers/007.php deleted file mode 100644 index 9a2f436d7c41..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/007.php +++ /dev/null @@ -1,22 +0,0 @@ - $resource['id'], - 'name' => $resource['name'], - 'email' => $resource['email'], - 'created_at' => $resource['created_at'], - 'updated_at' => $resource['updated_at'], - ]; - } -} - -// Request: GET /users/1?fields=id,name -// Response: {"id": 1, "name": "John Doe"} diff --git a/user_guide_src/source/outgoing/api_transformers/008.php b/user_guide_src/source/outgoing/api_transformers/008.php deleted file mode 100644 index 776a090d3ce3..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/008.php +++ /dev/null @@ -1,25 +0,0 @@ - $resource['id'], - 'name' => $resource['name'], - 'email' => $resource['email'], - 'created_at' => $resource['created_at'], - 'updated_at' => $resource['updated_at'], - ]; - } - - protected function getAllowedFields(): ?array - { - // Only these fields can be requested - return ['id', 'name', 'created_at']; - } -} diff --git a/user_guide_src/source/outgoing/api_transformers/009.php b/user_guide_src/source/outgoing/api_transformers/009.php deleted file mode 100644 index f1aa4624ad87..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/009.php +++ /dev/null @@ -1,32 +0,0 @@ - $resource['id'], - 'name' => $resource['name'], - 'email' => $resource['email'], - ]; - } - - protected function includePosts(): array - { - // Use $this->resource to access the current resource being transformed - $posts = model('PostModel')->where('user_id', $this->resource['id'])->findAll(); - - return (new PostTransformer())->transformMany($posts); - } - - protected function includeComments(): array - { - $comments = model('CommentModel')->where('user_id', $this->resource['id'])->findAll(); - - return (new CommentTransformer())->transformMany($comments); - } -} diff --git a/user_guide_src/source/outgoing/api_transformers/010.php b/user_guide_src/source/outgoing/api_transformers/010.php deleted file mode 100644 index 4a5538088fd9..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/010.php +++ /dev/null @@ -1,48 +0,0 @@ - $resource['id'], - 'name' => $resource['name'], - 'email' => $resource['email'], - ]; - } - - protected function getAllowedIncludes(): ?array - { - // Only these relationships can be included - return ['posts', 'comments']; - } - - protected function includePosts(): array - { - $posts = model('PostModel')->where('user_id', $this->resource['id'])->findAll(); - - return (new PostTransformer())->transformMany($posts); - } - - protected function includeComments(): array - { - $comments = model('CommentModel')->where('user_id', $this->resource['id'])->findAll(); - - return (new CommentTransformer())->transformMany($comments); - } - - protected function includeOrders(): array - { - // This method exists but won't be callable from the API - // because 'orders' is not in getAllowedIncludes() - $orders = model('OrderModel')->where('user_id', $this->resource['id'])->findAll(); - - return (new OrderTransformer())->transformMany($orders); - } -} diff --git a/user_guide_src/source/outgoing/api_transformers/011.php b/user_guide_src/source/outgoing/api_transformers/011.php deleted file mode 100644 index 7d4d53ea2b30..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/011.php +++ /dev/null @@ -1,23 +0,0 @@ - $resource['id'], - 'name' => $resource['name'], - 'email' => $resource['email'], - ]; - } - - protected function getAllowedIncludes(): ?array - { - // Return empty array to disable all includes - return []; - } -} diff --git a/user_guide_src/source/outgoing/api_transformers/012.php b/user_guide_src/source/outgoing/api_transformers/012.php deleted file mode 100644 index f3f3313c9cd1..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/012.php +++ /dev/null @@ -1,21 +0,0 @@ -findAll(); - - $transformer = new UserTransformer(); - $data = $transformer->transformMany($users); - - return $this->respond($data); - } -} diff --git a/user_guide_src/source/outgoing/api_transformers/013.php b/user_guide_src/source/outgoing/api_transformers/013.php deleted file mode 100644 index b54fc29fd156..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/013.php +++ /dev/null @@ -1,13 +0,0 @@ - 1, - 'name' => 'John Doe', - 'email' => 'john@example.com', -]); - -$transformer = new UserTransformer(); -$result = $transformer->transform($user); diff --git a/user_guide_src/source/outgoing/api_transformers/014.php b/user_guide_src/source/outgoing/api_transformers/014.php deleted file mode 100644 index f47e9056d753..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/014.php +++ /dev/null @@ -1,12 +0,0 @@ - 1, - 'name' => 'John Doe', - 'email' => 'john@example.com', -]; - -$transformer = new UserTransformer(); -$result = $transformer->transform($userData); diff --git a/user_guide_src/source/outgoing/api_transformers/015.php b/user_guide_src/source/outgoing/api_transformers/015.php deleted file mode 100644 index 0c0df79ad350..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/015.php +++ /dev/null @@ -1,11 +0,0 @@ -id = 1; -$user->name = 'John Doe'; -$user->email = 'john@example.com'; - -$transformer = new UserTransformer(); -$result = $transformer->transform($user); diff --git a/user_guide_src/source/outgoing/api_transformers/016.php b/user_guide_src/source/outgoing/api_transformers/016.php deleted file mode 100644 index 2436acc7d5de..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/016.php +++ /dev/null @@ -1,21 +0,0 @@ - '1.0', - 'status' => 'active', - 'message' => 'API is running', - ]; - } -} - -// Usage -$transformer = new StaticDataTransformer(); -$result = $transformer->transform(null); // No resource passed diff --git a/user_guide_src/source/outgoing/api_transformers/017.php b/user_guide_src/source/outgoing/api_transformers/017.php deleted file mode 100644 index 4e856838feec..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/017.php +++ /dev/null @@ -1,19 +0,0 @@ - $resource['id'], - 'name' => $resource['name'], - 'price' => $resource['price'], - 'in_stock' => $resource['stock_quantity'] > 0, - 'description' => $resource['description'], - ]; - } -} diff --git a/user_guide_src/source/outgoing/api_transformers/018.php b/user_guide_src/source/outgoing/api_transformers/018.php deleted file mode 100644 index a8580b7dbe0a..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/018.php +++ /dev/null @@ -1,17 +0,0 @@ -find(1); - -$transformer = new UserTransformer(); - -// Transform an entity -$result = $transformer->transform($user); - -// Transform an array -$userData = ['id' => 1, 'name' => 'John Doe']; -$result = $transformer->transform($userData); - -// Use toArray() data -$result = $transformer->transform(); diff --git a/user_guide_src/source/outgoing/api_transformers/019.php b/user_guide_src/source/outgoing/api_transformers/019.php deleted file mode 100644 index bb847b852397..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/019.php +++ /dev/null @@ -1,13 +0,0 @@ -findAll(); - -$transformer = new UserTransformer(); -$results = $transformer->transformMany($users); - -// $results is an array of transformed user arrays -foreach ($results as $user) { - // Each $user is the result of calling transform() on an individual user -} diff --git a/user_guide_src/source/outgoing/api_transformers/022.php b/user_guide_src/source/outgoing/api_transformers/022.php deleted file mode 100644 index f22631c56d70..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/022.php +++ /dev/null @@ -1,25 +0,0 @@ - $resource['id'], - 'name' => $resource['name'], - 'email' => $resource['email'], - 'created_at' => $resource['created_at'], - ]; - } - - protected function getAllowedFields(): ?array - { - // Clients can only request id, name, and created_at - // Attempting to request 'email' will throw an ApiException - return ['id', 'name', 'created_at']; - } -} diff --git a/user_guide_src/source/outgoing/api_transformers/023.php b/user_guide_src/source/outgoing/api_transformers/023.php deleted file mode 100644 index 8b0cb071a924..000000000000 --- a/user_guide_src/source/outgoing/api_transformers/023.php +++ /dev/null @@ -1,39 +0,0 @@ - $resource['id'], - 'name' => $resource['name'], - 'email' => $resource['email'], - ]; - } - - protected function getAllowedIncludes(): ?array - { - // Only 'posts' can be included via ?include=posts - // Attempting to include 'orders' will throw an ApiException - return ['posts']; - } - - protected function includePosts(): array - { - $posts = model('PostModel')->where('user_id', $this->resource['id'])->findAll(); - - return (new PostTransformer())->transformMany($posts); - } - - protected function includeOrders(): array - { - // This method exists but cannot be called via the API - $orders = model('OrderModel')->where('user_id', $this->resource['id'])->findAll(); - - return (new OrderTransformer())->transformMany($orders); - } -} diff --git a/user_guide_src/source/outgoing/csp.rst b/user_guide_src/source/outgoing/csp.rst deleted file mode 100644 index a9cdc73073fe..000000000000 --- a/user_guide_src/source/outgoing/csp.rst +++ /dev/null @@ -1,167 +0,0 @@ -.. _content-security-policy: - -####################### -Content Security Policy -####################### - -.. contents:: - :local: - :depth: 2 - -******************************** -What is Content Security Policy? -******************************** - -One of the best protections you have against XSS attacks is to implement a Content Security Policy (CSP) on the site. -This requires you to specify and authorize each source of content that is included in your site's HTML, including -images, stylesheets, JavaScript files, and so on. The browser will reject content from sources that are not explicitly -approved. This authorization is defined within the response's ``Content-Security-Policy`` header and offers various -configuration options. - -This sounds complex, and on some sites can definitely be challenging. For many simple sites, though, where all content -is served by the same domain (e.g., **http://example.com**), it is very simple to integrate. - -As this is a complex subject, this user guide will not go over all of the details. For more information, you should -visit the following sites: - -* `Content Security Policy main site `_ -* `W3C Specification `_ -* `Introduction at HTML5Rocks `_ -* `Article at SitePoint `_ - -************** -Turning CSP On -************** - -.. important:: The :ref:`Debug Toolbar ` may use Kint, which outputs inline scripts. Therefore, when - CSP is turned on, a CSP nonce is automatically output for the Debug Toolbar. However, if you are not using CSP - nonces, this will change the CSP header to something you do not intend, and it will behave differently than in - production; if you want to verify CSP behavior, turn off the Debug Toolbar. - -By default, support for this is off. To enable support in your application, edit the ``CSPEnabled`` value in -**app/Config/App.php**: - -.. literalinclude:: csp/011.php - -When enabled, the response object will contain an instance of ``CodeIgniter\HTTP\ContentSecurityPolicy``. The values set -in **app/Config/ContentSecurityPolicy.php** are applied to that instance, and if no changes are needed during runtime, -then the correctly formatted header is sent and you're all done. - -With CSP enabled, two header lines are added to the HTTP response: a **Content-Security-Policy** header, with policies -identifying content types or origins that are explicitly allowed for different contexts, and a -**Content-Security-Policy-Report-Only** header, which identifies content types or origins that will be allowed but which -will also be reported to the destination of your choice. - -Our implementation provides for a default treatment, changeable through the ``reportOnly()`` method. When an additional -entry is added to a CSP directive, as shown below, it will be added to the CSP header appropriate for blocking or -preventing. That can be overridden on a per-call basis, by providing an optional second parameter to the adding method -call. - -********************* -Runtime Configuration -********************* - -If your application needs to make changes at run-time, you can access the instance at ``$this->response->getCSP()`` in -your controllers. - -The class holds a number of methods that map pretty clearly to the appropriate header value that you need to set. -Examples are shown below, with different combinations of parameters, though all accept either a directive name or an -array of them: - -.. literalinclude:: csp/012.php - -The first parameter to each of the "add" methods is an appropriate string value, or an array of them. - -Report Only -=========== - -The ``reportOnly()`` method allows you to specify the default reporting treatment for subsequent sources, unless -overridden. - -For instance, you could specify that youtube.com was allowed, and then provide several allowed but reported sources: - -.. literalinclude:: csp/013.php - -Reporting Directives -==================== - -To specify the URL you want the reports to be sent to, you can use the ``setReportURI()`` method. - -.. versionadded:: 4.7.0 - -CSP Level 3 deprecates the ``report-uri`` directive in favor of ``report-to``. Therefore, you can use the -``setReportToEndpoint()`` method to set the reporting endpoint for CSP reports. Before adding this directive, make sure -the reporting endpoints are already defined using the ``addReportingEndpoints()`` method. - -.. literalinclude:: csp/015.php - -For backward compatibility with browsers that do not support the ``report-to`` directive, CodeIgniter4 will also set the -``report-uri`` directive when you use the ``setReportToEndpoint()`` method. - -.. _csp-clear-directives: - -Clear Directives -================ - -If you want to clear existing CSP directives, you can use the ``clearDirective()`` method: - -.. literalinclude:: csp/014.php - -************** -Inline Content -************** - -Inline scripts and styles can be injected through user-generated content. To allow only trusted inline content, CSP lets -you add a nonce to trusted `` - -.. warning:: If an attacker injects a string like `` - - // Becomes - - - // OR - diff --git a/user_guide_src/source/outgoing/csp/011.php b/user_guide_src/source/outgoing/csp/011.php deleted file mode 100644 index 193105592586..000000000000 --- a/user_guide_src/source/outgoing/csp/011.php +++ /dev/null @@ -1,12 +0,0 @@ -response->getCSP(); - -// specify the default directive treatment -$csp->reportOnly(false); - -// specify the origin to use if none provided for a directive -$csp->setDefaultSrc('cdn.example.com'); - -// specify the URL that "report-only" reports get sent to -$csp->setReportURI('http://example.com/csp/reports'); - -// specify that HTTP requests be upgraded to HTTPS -$csp->upgradeInsecureRequests(true); - -// add types or origins to CSP directives -// assuming that the default treatment is to block rather than just report -$csp->addBaseURI('example.com', true); // report only -$csp->addChildSrc('https://youtube.com'); // blocked -$csp->addConnectSrc('https://*.facebook.com', false); // blocked -$csp->addFontSrc('fonts.example.com'); -$csp->addFormAction('self'); -$csp->addFrameAncestor('none', true); // report this one -$csp->addImageSrc('cdn.example.com'); -$csp->addMediaSrc('cdn.example.com'); -$csp->addManifestSrc('cdn.example.com'); -$csp->addObjectSrc('cdn.example.com', false); // reject from here -$csp->addPluginType('application/pdf', false); // reject this media type -$csp->addScriptSrc('scripts.example.com', true); // allow but report requests from here -$csp->addStyleSrc('css.example.com'); -$csp->addSandbox(['allow-forms', 'allow-scripts']); - -// the following CSP3 directives are available in v4.7.0 and later -$csp->addScriptSrcAttr('trusted.com'); -$csp->addScriptSrcElem('trusted.com'); -$csp->addStyleSrcAttr('trusted.com'); -$csp->addStyleSrcElem('trusted.com'); -$csp->addWorkerSrc('workers.example.com'); diff --git a/user_guide_src/source/outgoing/csp/013.php b/user_guide_src/source/outgoing/csp/013.php deleted file mode 100644 index a34b34607f26..000000000000 --- a/user_guide_src/source/outgoing/csp/013.php +++ /dev/null @@ -1,9 +0,0 @@ -response->getCSP(); - -$csp->addChildSrc('https://youtube.com'); // allowed -$csp->reportOnly(true); -$csp->addChildSrc('https://metube.com'); // allowed but reported -$csp->addChildSrc('https://ourtube.com', false); // allowed diff --git a/user_guide_src/source/outgoing/csp/014.php b/user_guide_src/source/outgoing/csp/014.php deleted file mode 100644 index ced4a9307537..000000000000 --- a/user_guide_src/source/outgoing/csp/014.php +++ /dev/null @@ -1,6 +0,0 @@ -response->getCSP(); - -$csp->clearDirective('style-src'); diff --git a/user_guide_src/source/outgoing/csp/015.php b/user_guide_src/source/outgoing/csp/015.php deleted file mode 100644 index 979c72f3d16c..000000000000 --- a/user_guide_src/source/outgoing/csp/015.php +++ /dev/null @@ -1,14 +0,0 @@ -response->getCSP(); - -$csp->setReportURI('https://example.com/csp-reports'); - -// Starting in v4.7.0, you can use the setReportToEndpoint() method -// to set the reporting endpoint for CSP reports -$csp->addReportingEndpoints([ - 'default' => 'https://example.com/csp-reports', - 'reports' => 'https://example.com/other-csp-reports', -]); -$csp->setReportToEndpoint('default'); diff --git a/user_guide_src/source/outgoing/index.rst b/user_guide_src/source/outgoing/index.rst deleted file mode 100644 index 3468043f229d..000000000000 --- a/user_guide_src/source/outgoing/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -################## -Building Responses -################## - -View components are used to build what is returned to the user. - -.. toctree:: - :titlesonly: - - views - view_renderer - view_layouts - view_cells - view_parser - view_decorators - table - response - api_responses - api_transformers - csp - localization - alternative_php diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst deleted file mode 100644 index 1d51539b7a33..000000000000 --- a/user_guide_src/source/outgoing/localization.rst +++ /dev/null @@ -1,391 +0,0 @@ -############ -Localization -############ - -.. contents:: - :local: - :depth: 3 - -******************** -Working with Locales -******************** - -CodeIgniter provides several tools to help you localize your application for different languages. While full -localization of an application is a complex subject, it's simple to swap out strings in your application with different -supported languages. - -Configuring the Locale -====================== - -.. _setting-the-default-locale: - -Setting the Default Locale --------------------------- - -Every site will have a default language/locale it operates in. This can be set in **app/Config/App.php**: - -.. literalinclude:: localization/001.php - -The value can be any string that your application uses to manage text strings and other formats. It is recommended that -a `BCP 47 `_ language code is used. This results in language codes like -en-US for American English, or fr-FR for French/France. A more readable introduction to this can be found on the -`W3C's site `_. - -The system is smart enough to fall back to more generic language codes if an exact match cannot be found. If the locale -code was set to ``en-US`` and we only have language files set up for ``en``, then those will be used since nothing -exists for the more specific ``en-US``. If, however, a language directory existed at **app/Language/en-US**, then that -would be used first. - -Locale Detection -================ - -.. important:: Locale detection only works for web-based requests that use the IncomingRequest class. Command-line - requests will not have these features. - -There are two methods supported to detect the correct locale during the request. - -1. `Content Negotiation`_: The first is a "set and forget" method that will automatically perform - :doc:`content negotiation ` for you to determine the correct locale to use. -2. `In Routes`_: The second method allows you to specify a segment in your routes that will be used to set the locale. - -Should you ever need to set the locale directly, see `Setting the Current Locale`_. - -Since v4.4.0, ``IncomingRequest::setValidLocales()`` has been added to set (and reset) valid locales that are set from -``Config\App::$supportedLocales`` setting. - -Content Negotiation -------------------- - -You can set up content negotiation to happen automatically by setting two additional settings in **app/Config/App.php**. -The first value tells the Request class that we do want to negotiate a locale, so simply set it to true: - -.. literalinclude:: localization/002.php - -Once this is enabled, the system will automatically negotiate the correct language based upon an array of locales that -you have defined in ``$supportedLocales``. If no match is found between the languages that you support and the requested -language, the first item in ``$supportedLocales`` will be used. In the following example, the ``en`` locale would be -used if no match is found: - -.. literalinclude:: localization/003.php - -.. _localization-in-routes: - -In Routes ---------- - -The second method uses a custom placeholder to detect the desired locale and set it on the Request. The placeholder -``{locale}`` can be placed as a segment in your route. If present, the contents of the matching segment will be your -locale: - -.. literalinclude:: localization/004.php - :lines: 2- - -In this example, if the user tried to visit **http://example.com/fr/books**, then the locale would be set to ``fr``, -assuming it was configured as a valid locale. - -If the value doesn't match a valid locale as defined in ``$supportedLocales`` in **app/Config/App.php**, the default -locale will be used in its place, unless you choose to use only the supported locales defined in the App configuration -file: - -.. literalinclude:: localization/018.php - :lines: 2- - -.. note:: The ``useSupportedLocalesOnly()`` method can be used since v4.3.0. - -Setting the Current Locale -========================== - -IncomingRequest Locale ----------------------- - -If you want to set the locale directly, you may use the ``setLocale()`` method in the -:doc:`../incoming/incomingrequest`: - -.. literalinclude:: localization/020.php - :lines: 2- - -Before setting the locale, you must set valid locales, because any attempt to set a locale that is not valid will result -in the :ref:`default locale ` being set. - -By default, the valid locales are defined in ``Config\App::$supportedLocales`` in **app/Config/App.php**: - -.. literalinclude:: localization/003.php - -.. note:: Since v4.4.0, ``IncomingRequest::setValidLocales()`` has been added to set (and reset) valid locales. Use it - if you want to change the valid locales dynamically. - -Language Locale ---------------- - -The ``Language`` class used in the :php:func:`lang()` function also has the current locale. This is set to the -``IncomingRequest`` locale during instantiation. - -If you want to change the locale after instantiating the language class, use the ``Language::setLocale()`` method. - -.. literalinclude:: localization/021.php - :lines: 2- - -Retrieving the Current Locale -============================= - -The current locale can always be retrieved from the IncomingRequest object, through the ``getLocale()`` method. If your -controller is extending ``CodeIgniter\Controller``, this will be available through ``$this->request``: - -.. literalinclude:: localization/005.php - -Alternatively, you can use the :doc:`Services class ` to retrieve the current request: - -.. literalinclude:: localization/006.php - :lines: 2- - -.. _language-localization: - -********************* -Language Localization -********************* - -Creating Language Files -======================= - -Language strings are stored in the **app/Language** directory, with a sub-directory for each supported language -(locale):: - - app/ - Language/ - en/ - App.php - fr/ - App.php - -.. note:: The Language Files do not have namespaces. - -Languages do not have any specific naming convention that is required. The file should be named logically to describe -the type of content it holds. For example, let's say you want to create a file containing error messages. You might name -it simply: **Errors.php**. - -Within the file, you would return an array, where each element in the array has a language key and can have a string to -return: - -.. literalinclude:: localization/007.php - -.. note:: You cannot use dots (``.``) at the beginning and end of language keys. - -It also supports nested definitions: - -.. literalinclude:: localization/008.php - -.. literalinclude:: localization/009.php - -Basic Usage -=========== - -You can use the :php:func:`lang()` helper function to retrieve text from any of the language files, by passing the -filename and the language key as the first parameter, separated by a period (``.``). - -For example, to load the ``errorEmailMissing`` string from the **Errors.php** language file, you would do the following: - -.. literalinclude:: localization/010.php - :lines: 2- - -For nested definitions, you would do the following: - -.. literalinclude:: localization/011.php - :lines: 2- - -If the requested language key doesn't exist in the file for the current locale (after `Language Fallback`_), the string -will be passed back, unchanged. In this example, it would return ``Errors.errorEmailMissing`` or -``Errors.nested.error.message`` if it didn't exist. - -Replacing Parameters --------------------- - -.. note:: The following functions all require the `intl `_ extension to be - loaded on your system in order to work. If the extension is not loaded, no replacement will be attempted. A great - overview can be found over at - `Sitepoint `_. - -You can pass an array of values to replace placeholders in the language string as the second parameter to the ``lang()`` -function. This allows for very simple number translations and formatting: - -.. literalinclude:: localization/012.php - -The first item in the placeholder corresponds to the index of the item in the array, if it's numerical: - -.. literalinclude:: localization/013.php - :lines: 2- - -You can also use named keys to make it easier to keep things straight, if you'd like: - -.. literalinclude:: localization/014.php - :lines: 2- - -Obviously, you can do more than just number replacement. According to the -`official ICU docs `_ for -the underlying library, the following types of data can be replaced: - -* numbers - integer, currency, percent -* dates - short, medium, long, full -* time - short, medium, long, full -* spellout - spells out numbers (i.e., 34 becomes thirty-four) -* ordinal -* duration - -Here are a few examples: - -.. literalinclude:: localization/015.php - -You should be sure to read up on the MessageFormatter class and the underlying ICU formatting to get a better idea of -what capabilities it has, like performing conditional replacement, pluralization, and more. Both of the links provided -earlier will give you an excellent idea as to the options available. - -Specifying Locale ------------------ - -To specify a different locale to be used when replacing parameters, you can pass the locale in as the third parameter to -the :php:func:`lang()` function. - -.. literalinclude:: localization/016.php - -If you want to change the current locale, see `Language Locale`_. - -Nested Arrays -------------- - -Language files also allow nested arrays to make working with lists, etc. easier. - -.. literalinclude:: localization/017.php - -Language Fallback -================= - -If you have a set of messages for a given locale, for instance **Language/en/App.php**, you can add language variants -for that locale, each in its own folder, for instance **Language/en-US/App.php**. - -You only need to provide values for those messages that would be localized differently for that locale variant. Any -missing message definitions will be automatically pulled from the main locale settings. - -It gets better - the localization can fall all the way back to English (**en**), in case new messages are added to the -framework and you haven't had a chance to translate them yet for your locale. - -So, if you are using the locale ``fr-CA``, then a localized message will first be sought in the **Language/fr-CA** -directory, then in the **Language/fr** directory, and finally in the **Language/en** directory. - -System Message Translations -=========================== - -We have an "official" set of the system message translations in their -`own repository `_. - -You could download that repository, and copy its **Language** folder into your **app** folder. The incorporated -translations will be automatically picked up because the ``App`` namespace is mapped to your **app** folder. - -Alternatively, a better practice would be to run the following command inside your project: - -.. code-block:: console - - composer require codeigniter4/translations - -The translated messages will be automatically picked up because the translations folders get mapped appropriately. - -Overriding System Message Translations -====================================== - -The framework provides `System Message Translations`_, and packages that you installed may also provide the message -translations. - -If you want to override some language messages, create language files in the **app/Language** directory. Then, return -only the array you want to override in the file. - -.. _generating-translation-files-via-command: - -Generating Translation Files via Command -======================================== - -.. versionadded:: 4.5.0 - -You can automatically generate and update translation files in your **app** folder. The command will search for uses of -the ``lang()`` function and combine them with the current translation keys in **app/Language**, using the -``defaultLocale`` locale from ``Config\App``. After the operation, you need to translate the language keys yourself. The -command can recognize nested keys such as ``File.array.nested.text``. Previously saved keys do not change. - -.. note:: Keys that ``lang()`` can already resolve (for example ``Errors.*`` from **system/Language**) are treated as - already translated, so they are neither listed by ``--show-new`` nor written into **app/Language**. - -.. code-block:: console - - php spark lang:find - -.. literalinclude:: localization/019.php - -.. note:: When the command scans folders, **app/Language** will be skipped. - -The language files generated will most likely not conform to your coding standards. It is recommended to format them. -For example, run ``vendor/bin/php-cs-fixer fix ./app/Language`` if ``php-cs-fixer`` is installed. - -Before updating, it is possible to preview the translations found by the command: - -.. code-block:: console - - php spark lang:find --verbose --show-new - -The detailed output of ``--verbose`` also shows a list of invalid keys. For example: - -.. code-block:: console - - ... - - Files found: 10 - New translates found: 30 - Bad translates found: 5 - +------------------------+---------------------------------+ - | Bad Key | Filepath | - +------------------------+---------------------------------+ - | ..invalid_nested_key.. | app/Controllers/Translation.php | - | .invalid_key | app/Controllers/Translation.php | - | TranslationBad | app/Controllers/Translation.php | - | TranslationBad. | app/Controllers/Translation.php | - | TranslationBad... | app/Controllers/Translation.php | - +------------------------+---------------------------------+ - - All operations done! - -For a more accurate search, specify the desired locale or directory to scan. - -.. code-block:: console - - php spark lang:find --dir Controllers/Translation --locale en --show-new - -Detailed information can be found by running the command: - -.. code-block:: console - - php spark lang:find --help - -.. _sync-translations-command: - -Synchronizing Translation Files via Command -------------------------------------------- - -.. versionadded:: 4.6.0 - -You may need to create files for another language when you've finished translating for the current language. You can use -the spark ``lang:find`` command to help with this. However, it might not detect all translations, particularly those -with dynamically set parameters like ``lang('App.status.' . $key, ['payload' => 'John'], 'en')``. - -To ensure no translations are missed, it's best to copy the completed language files and translate them manually. This -approach preserves any unique keys the command might have overlooked. - -All you need to do is execute: - -.. code-block:: console - - // Specify the locale for new/updated translations - php spark lang:sync --target ru - - // or set the original locale - php spark lang:sync --locale en --target ru - -As a result, you will receive files with the translation keys. If there were duplicate keys in the target locale, they -are saved. - -.. warning:: Non-matching keys in new translations are deleted! diff --git a/user_guide_src/source/outgoing/localization/001.php b/user_guide_src/source/outgoing/localization/001.php deleted file mode 100644 index 4b0a000e3e44..000000000000 --- a/user_guide_src/source/outgoing/localization/001.php +++ /dev/null @@ -1,14 +0,0 @@ -get('{locale}/books', 'App\Books::index'); diff --git a/user_guide_src/source/outgoing/localization/005.php b/user_guide_src/source/outgoing/localization/005.php deleted file mode 100644 index fa115d6cf3db..000000000000 --- a/user_guide_src/source/outgoing/localization/005.php +++ /dev/null @@ -1,11 +0,0 @@ -request->getLocale(); - } -} diff --git a/user_guide_src/source/outgoing/localization/006.php b/user_guide_src/source/outgoing/localization/006.php deleted file mode 100644 index 06eee03102b5..000000000000 --- a/user_guide_src/source/outgoing/localization/006.php +++ /dev/null @@ -1,3 +0,0 @@ -getLocale(); diff --git a/user_guide_src/source/outgoing/localization/007.php b/user_guide_src/source/outgoing/localization/007.php deleted file mode 100644 index 035d13bcfb64..000000000000 --- a/user_guide_src/source/outgoing/localization/007.php +++ /dev/null @@ -1,5 +0,0 @@ - 'The actual message to be shown.', -]; diff --git a/user_guide_src/source/outgoing/localization/008.php b/user_guide_src/source/outgoing/localization/008.php deleted file mode 100644 index 319fa750429b..000000000000 --- a/user_guide_src/source/outgoing/localization/008.php +++ /dev/null @@ -1,9 +0,0 @@ - [ - 'nested' => [ - 'key' => 'The actual message to be shown.', - ], - ], -]; diff --git a/user_guide_src/source/outgoing/localization/009.php b/user_guide_src/source/outgoing/localization/009.php deleted file mode 100644 index 07e6924dcdab..000000000000 --- a/user_guide_src/source/outgoing/localization/009.php +++ /dev/null @@ -1,12 +0,0 @@ - 'You must submit an email address', - 'errorURLMissing' => 'You must submit a URL', - 'errorUsernameMissing' => 'You must submit a username', - 'nested' => [ - 'error' => [ - 'message' => 'A specific error message', - ], - ], -]; diff --git a/user_guide_src/source/outgoing/localization/010.php b/user_guide_src/source/outgoing/localization/010.php deleted file mode 100644 index 7631da71f069..000000000000 --- a/user_guide_src/source/outgoing/localization/010.php +++ /dev/null @@ -1,3 +0,0 @@ - 'I have {0, number} apples.', - 'men' => 'The top {1, number} men out-performed the remaining {0, number}', - 'namedApples' => 'I have {number_apples, number, integer} apples.', -]; - -// Displays "I have 3 apples." -echo lang('Tests.apples', [3]); diff --git a/user_guide_src/source/outgoing/localization/013.php b/user_guide_src/source/outgoing/localization/013.php deleted file mode 100644 index c74a8f868f6e..000000000000 --- a/user_guide_src/source/outgoing/localization/013.php +++ /dev/null @@ -1,4 +0,0 @@ - 3]); diff --git a/user_guide_src/source/outgoing/localization/015.php b/user_guide_src/source/outgoing/localization/015.php deleted file mode 100644 index 04e15f558f69..000000000000 --- a/user_guide_src/source/outgoing/localization/015.php +++ /dev/null @@ -1,40 +0,0 @@ - 'The time is now {0, time, short}.', - 'mediumTime' => 'The time is now {0, time, medium}.', - 'longTime' => 'The time is now {0, time, long}.', - 'fullTime' => 'The time is now {0, time, full}.', - 'shortDate' => 'The date is now {0, date, short}.', - 'mediumDate' => 'The date is now {0, date, medium}.', - 'longDate' => 'The date is now {0, date, long}.', - 'fullDate' => 'The date is now {0, date, full}.', - 'spelledOut' => '34 is {0, spellout}', - 'ordinal' => 'The ordinal is {0, ordinal}', - 'duration' => 'It has been {0, duration}', -]; - -// Displays "The time is now 11:18 PM" -echo lang('Tests.shortTime', [time()]); -// Displays "The time is now 11:18:50 PM" -echo lang('Tests.mediumTime', [time()]); -// Displays "The time is now 11:19:09 PM CDT" -echo lang('Tests.longTime', [time()]); -// Displays "The time is now 11:19:26 PM Central Daylight Time" -echo lang('Tests.fullTime', [time()]); - -// Displays "The date is now 8/14/16" -echo lang('Tests.shortDate', [time()]); -// Displays "The date is now Aug 14, 2016" -echo lang('Tests.mediumDate', [time()]); -// Displays "The date is now August 14, 2016" -echo lang('Tests.longDate', [time()]); -// Displays "The date is now Sunday, August 14, 2016" -echo lang('Tests.fullDate', [time()]); - -// Displays "34 is thirty-four" -echo lang('Tests.spelledOut', [34]); - -// Displays "It has been 408,676:24:35" -echo lang('Tests.ordinal', [time()]); diff --git a/user_guide_src/source/outgoing/localization/016.php b/user_guide_src/source/outgoing/localization/016.php deleted file mode 100644 index 93b709a73e99..000000000000 --- a/user_guide_src/source/outgoing/localization/016.php +++ /dev/null @@ -1,9 +0,0 @@ - 7.41], 'en-GB'); -// Displays "$7.41" -echo lang('{price, number, currency}', ['price' => 7.41], 'en-US'); diff --git a/user_guide_src/source/outgoing/localization/017.php b/user_guide_src/source/outgoing/localization/017.php deleted file mode 100644 index bd6218e927b5..000000000000 --- a/user_guide_src/source/outgoing/localization/017.php +++ /dev/null @@ -1,17 +0,0 @@ - [ - 'Apples', - 'Bananas', - 'Grapes', - 'Lemons', - 'Oranges', - 'Strawberries', - ], -]; - -// Displays "Apples, Bananas, Grapes, Lemons, Oranges, Strawberries" -echo implode(', ', lang('Fruit.list')); diff --git a/user_guide_src/source/outgoing/localization/018.php b/user_guide_src/source/outgoing/localization/018.php deleted file mode 100644 index 107d2a157881..000000000000 --- a/user_guide_src/source/outgoing/localization/018.php +++ /dev/null @@ -1,3 +0,0 @@ -useSupportedLocalesOnly(true); diff --git a/user_guide_src/source/outgoing/localization/019.php b/user_guide_src/source/outgoing/localization/019.php deleted file mode 100644 index 5de7d9a80731..000000000000 --- a/user_guide_src/source/outgoing/localization/019.php +++ /dev/null @@ -1,13 +0,0 @@ - [ - 'success' => 'Text.info.success', - ], - 'paragraph' => 'Text.paragraph', -]; diff --git a/user_guide_src/source/outgoing/localization/020.php b/user_guide_src/source/outgoing/localization/020.php deleted file mode 100644 index 3116bd0dedb7..000000000000 --- a/user_guide_src/source/outgoing/localization/020.php +++ /dev/null @@ -1,4 +0,0 @@ -setLocale('ja'); diff --git a/user_guide_src/source/outgoing/localization/021.php b/user_guide_src/source/outgoing/localization/021.php deleted file mode 100644 index 9dbc8d1f0fe4..000000000000 --- a/user_guide_src/source/outgoing/localization/021.php +++ /dev/null @@ -1,5 +0,0 @@ -setLocale('ja'); diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst deleted file mode 100644 index feffc967a988..000000000000 --- a/user_guide_src/source/outgoing/response.rst +++ /dev/null @@ -1,495 +0,0 @@ -============== -HTTP Responses -============== - -The Response class extends the :doc:`HTTP Message Class ` with methods appropriate only for a server -responding to the client that called it. - -.. contents:: - :local: - :depth: 2 - -Working with the Response -========================= - -A Response class is instantiated for you and passed into your controllers. It can be accessed through -``$this->response``. It is the same instance that ``Services::response()`` returns. We call it the global response -instance. - -Many times you will not need to touch the class directly, since CodeIgniter takes care of sending the headers and the -body for you. This is great if the page successfully created the content it was asked to. When things go wrong, or you -need to send very specific status codes back, or even take advantage of the powerful HTTP caching, it's there for you. - -Setting the Output ------------------- - -When you need to set the output of the script directly, and not rely on CodeIgniter to automatically get it, you do it -manually with the ``setBody`` method. This is usually used in conjunction with setting the status code of the response: - -.. literalinclude:: response/001.php - -The reason phrase ('OK', 'Created', 'Moved Permanently') will be automatically added, but you can add custom reasons as -the second parameter of the ``setStatusCode()`` method: - -.. literalinclude:: response/002.php - -You can format an array into either JSON or XML and set the content type header to the appropriate MIME type with the -``setJSON()`` and ``setXML()`` methods. Typically, you will send an array of data to be converted: - -.. literalinclude:: response/003.php - -Setting Headers ---------------- - -setHeader() -^^^^^^^^^^^ - -Often, you will need to set headers for the response. The Response class makes this very simple to do, with the -``setHeader()`` method. - -The first parameter is the name of the header. The second parameter is the value, which can be either a string or an -array of values that will be combined correctly when sent to the client. - -.. literalinclude:: response/004.php - -Using these methods instead of the native PHP functions ensures that no headers are sent prematurely, causing errors, -and makes testing possible. - -.. important:: Since v4.6.0, if you set a header using PHP's native ``header()`` function and then use the ``Response`` - class to set the same header, the previous one will be overwritten. - -.. note:: This method just sets headers on the response instance. So, if you create and return another response instance - (e.g., if you call :php:func:`redirect()`), the headers set here will not be sent automatically. - -appendHeader() -^^^^^^^^^^^^^^ - -If the header exists and can have more than one value, you may use the ``appendHeader()`` and ``prependHeader()`` -methods to add the value to the end or beginning of the values list, respectively. The first parameter is the name of -the header, while the second is the value to append or prepend. - -.. literalinclude:: response/005.php - -removeHeader() -^^^^^^^^^^^^^^ - -Headers can be removed from the response with the ``removeHeader()`` method, which takes the header name as the only -parameter. This is not case-sensitive. - -.. literalinclude:: response/006.php - -.. _response-redirect: - -Redirect -======== - -If you want to create a redirect, use the :php:func:`redirect()` function. - -It returns a ``RedirectResponse`` instance. It is a different instance from the global response instance that -``Services::response()`` returns. - -.. warning:: If you set Cookies or Response Headers before you call ``redirect()``, they are set on the global response - instance, and they are not automatically copied to the ``RedirectResponse`` instance. To send them, you need to call - the ``withCookies()`` or ``withHeaders()`` method manually. - -.. important:: If you want to redirect, an instance of ``RedirectResponse`` must be returned in a method of the - :doc:`Controller <../incoming/controllers>` or the :doc:`Controller Filter <../incoming/filters>`. Note that the - ``__construct()`` or the ``initController()`` method cannot return any value. If you forget to return - ``RedirectResponse``, no redirection will occur. - -Redirect to a URI path ----------------------- - -When you want to pass a URI path (relative to baseURL), use ``redirect()->to()``: - -.. literalinclude:: ./response/028.php - :lines: 2- - -.. note:: If there is a fragment in your URL that you want to remove, you can use the refresh parameter in the method. - For example, ``return redirect()->to('admin/home', null, 'refresh');``. - -Redirect to a Defined Route ---------------------------- - -When you want to pass a :ref:`route name ` or ``Controller::method`` for -:ref:`reverse routing `, use ``redirect()->route()``: - -.. literalinclude:: ./response/029.php - :lines: 2- - -An argument passed into the function is treated as a route name or ``Controller::method`` for reverse routing, not a -relative/full URI, the same as when using ``redirect()->route()``: - -.. literalinclude:: ./response/030.php - :lines: 2- - -Redirect Back -------------- - -When you want to redirect back, use ``redirect()->back()``: - -.. literalinclude:: ./response/031.php - :lines: 2- - -.. note:: ``redirect()->back()`` is not the same as the browser "back" button. It takes a visitor to "the last page - viewed during the Session" when the Session is available. If the Session hasn't been loaded, or is otherwise - unavailable, then a sanitized version of HTTP_REFERER will be used. - -Redirect with Cookies ---------------------- - -If you set Cookies before you call ``redirect()``, they are set on the global response instance, and they are not -automatically copied to the ``RedirectResponse`` instance. - -To send the Cookies, you need to call the ``withCookies()`` method manually. - -.. literalinclude:: ./response/034.php - :lines: 2- - -Redirect with Headers ---------------------- - -If you set Response Headers before you call ``redirect()``, they are set on the global response instance, and they are -not automatically copied to the ``RedirectResponse`` instance. - -To send the Headers, you need to call the ``withHeaders()`` method manually. - -.. literalinclude:: ./response/035.php - :lines: 2- - -.. _response-redirect-status-code: - -Redirect Status Code --------------------- - -The default HTTP status code for GET requests is 302. However, when using HTTP/1.1 or later, 303 is used for -POST/PUT/DELETE requests and 307 for all other requests. - -You can specify the status code: - -.. literalinclude:: ./response/032.php - :lines: 2- - -.. note:: Due to a bug, in v4.3.3 or previous versions, the status code of the actual redirect response might be changed - even if a status code was specified. See :ref:`ChangeLog v4.3.4 `. - -If you don't know the HTTP status codes for redirection, it is recommended to read -`Redirections in HTTP `_. - -.. _force-file-download: - -Force File Download -=================== - -The Response class provides a simple way to send a file to the client, prompting the browser to download the data to -your computer. This sets the appropriate headers to make it happen. - -The first parameter is the **name you want to give the downloaded file**, and the second parameter is the file data. - -If you set the second parameter to null and ``$filename`` is an existing, readable file path, then its content will be -read instead. - -If you set the third parameter to boolean true, then the actual file MIME type (based on the filename extension) will be -sent, so that if your browser has a handler for that type, it can use it. - -Example: - -.. literalinclude:: response/007.php - -If you want to download an existing file from your server, you'll need to pass ``null`` explicitly for the second -parameter: - -.. literalinclude:: response/008.php - -Use the optional ``setFileName()`` method to change the filename as it is sent to the client's browser: - -.. literalinclude:: response/009.php - -.. note:: The response object MUST be returned for the download to be sent to the client. This allows the response to be - passed through all **after** filters before being sent to the client. - -.. _open-file-in-browser: - -Open File in Browser --------------------- - -Some browsers can display files such as PDF. To tell the browser to display the file instead of saving it, call the -``DownloadResponse::inline()`` method. - -.. literalinclude:: response/033.php - -HTTP Caching -============ - -Built into the HTTP specification are tools that help the client (often the web browser) cache the results. Used -correctly, this can lead to a huge performance boost to your application because it will tell the client that they don't -need to contact the server at all since nothing has changed. And you can't get faster than that. - -This is handled through the ``Cache-Control`` and ``ETag`` headers. This guide is not the proper place for a thorough -introduction to the power of all the cache headers, but you can get a good understanding over at -`Google Developers `_. - -By default, all response objects sent through CodeIgniter have HTTP caching turned off. The options and exact -circumstances are too varied for us to be able to create a good default other than turning it off. It's simple to set -the Cache values to what you need, through the ``setCache()`` method: - -.. literalinclude:: response/010.php - -The ``$options`` array simply takes an array of key/value pairs that are, with a couple of exceptions, assigned to the -``Cache-Control`` header. You are free to set all of the options exactly as you need for your specific situation. While -most of the options are applied to the ``Cache-Control`` header, it intelligently applies the ``etag`` and -``last-modified`` options to their appropriate headers. - -Class Reference -=============== - -.. note:: In addition to the methods listed here, this class inherits the methods from the - :doc:`Message Class `. - -The methods inherited from the Message Class are: - -* :meth:`CodeIgniter\\HTTP\\Message::getBody` -* :meth:`CodeIgniter\\HTTP\\Message::setBody` -* :meth:`CodeIgniter\\HTTP\\Message::populateHeaders` -* :meth:`CodeIgniter\\HTTP\\Message::headers` -* :meth:`CodeIgniter\\HTTP\\Message::header` -* :meth:`CodeIgniter\\HTTP\\Message::getHeaderLine` -* :meth:`CodeIgniter\\HTTP\\Message::setHeader` -* :meth:`CodeIgniter\\HTTP\\Message::removeHeader` -* :meth:`CodeIgniter\\HTTP\\Message::appendHeader` -* :meth:`CodeIgniter\\HTTP\\Message::getProtocolVersion` -* :meth:`CodeIgniter\\HTTP\\Message::setProtocolVersion` - -.. php:namespace:: CodeIgniter\HTTP - -.. php:class:: Response - - .. php:method:: getStatusCode() - - :returns: The current HTTP status code for this response - :rtype: int - - Returns the current status code for this response. If no status code has been set, an ``HTTPException`` will be - thrown: - - .. literalinclude:: response/014.php - - .. php:method:: setStatusCode($code[, $reason='']) - - :param int $code: The HTTP status code - :param string $reason: An optional reason phrase. - :returns: The current Response instance - :rtype: ``CodeIgniter\HTTP\Response`` - - Sets the HTTP status code that should be sent with this response: - - .. literalinclude:: response/015.php - - The reason phrase will be automatically generated based upon the official lists. If you need to set your own for - a custom status code, you can pass the reason phrase as the second parameter: - - .. literalinclude:: response/016.php - - .. php:method:: getReasonPhrase() - - :returns: The current reason phrase. - :rtype: string - - Returns the current reason phrase for this response. If no status has been set, it will return an empty string: - - .. literalinclude:: response/017.php - - .. php:method:: setDate($date) - - :param DateTime $date: A DateTime instance with the time to set for this response. - :returns: The current response instance. - :rtype: ``CodeIgniter\HTTP\Response`` - - Sets the date used for this response. The ``$date`` argument must be an instance of ``DateTime``. - - .. php:method:: setContentType($mime[, $charset='UTF-8']) - - :param string $mime: The content type this response represents. - :param string $charset: The character set this response uses. - :returns: The current response instance. - :rtype: ``CodeIgniter\HTTP\Response`` - - Sets the content type this response represents: - - .. literalinclude:: response/019.php - - By default, the method sets the character set to ``UTF-8``. If you need to change this, you can pass the - character set as the second parameter: - - .. literalinclude:: response/020.php - - .. php:method:: noCache() - - :returns: The current response instance. - :rtype: ``CodeIgniter\HTTP\Response`` - - Sets the ``Cache-Control`` header to turn off all HTTP caching. This is the default setting of all response - messages: - - .. literalinclude:: response/021.php - - .. php:method:: setCache($options) - - :param array $options: An array of key/value cache control settings - :returns: The current response instance. - :rtype: ``CodeIgniter\HTTP\Response`` - - Sets the ``Cache-Control`` headers, including ``ETags`` and ``Last-Modified``. Typical keys are: - - * etag - * last-modified - * max-age - * s-maxage - * private - * public - * must-revalidate - * proxy-revalidate - * no-transform - - When passing the last-modified option, it can be either a date string or a DateTime object. - - .. php:method:: setLastModified($date) - - :param string|DateTime $date: The date to set the Last-Modified header to - :returns: The current response instance. - :rtype: ``CodeIgniter\HTTP\Response`` - - Sets the ``Last-Modified`` header. The ``$date`` argument can be either a string or a ``DateTime`` instance: - - .. literalinclude:: response/022.php - - .. php:method:: send(): Response - - :returns: The current response instance. - :rtype: ``CodeIgniter\HTTP\Response`` - - Tells the response to send everything back to the client. This will first send the headers, followed by the - response body. For the main application response, you do not need to call this as it is handled automatically by - CodeIgniter. - - .. php:method:: setCookie($name = ''[, $value = ''[, $expire = 0[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = null[, $httponly = null[, $samesite = null]]]]]]]]) - - :param array|Cookie|string $name: Cookie name *or* associative array of all of the parameters available to this method *or* an instance of ``CodeIgniter\Cookie\Cookie`` - :param string $value: Cookie value - :param int $expire: Cookie expiration time in seconds. If set to ``0`` the cookie will only last as long as the browser is open - :param string $domain: Cookie domain - :param string $path: Cookie path - :param string $prefix: Cookie name prefix. If set to ``''``, the default value from **app/Config/Cookie.php** will be used - :param bool|null $secure: Whether to only transfer the cookie through HTTPS. If set to ``null``, the default value from **app/Config/Cookie.php** will be used - :param bool|null $httponly: Whether to only make the cookie accessible for HTTP requests (no JavaScript). If set to ``null``, the default value from **app/Config/Cookie.php** will be used - :param string|null $samesite: The value for the SameSite cookie parameter. If set to ``''`` or ``null``, the default value from **app/Config/Cookie.php** will be used - :rtype: void - - .. note:: Prior to v4.2.7, the default values of ``$secure`` and ``$httponly`` were ``false`` due to a bug, and - these values from **app/Config/Cookie.php** were never used. - - Sets a cookie containing the values you specify to the Response instance. - - There are two ways to pass information to this method so that a cookie can be set: Array Method, and Discrete - Parameters: - - **Array Method** - - Using this method, an associative array is passed as the first parameter: - - .. literalinclude:: response/023.php - - Only the ``name`` and ``value`` are required. To delete a cookie, set it with the ``value`` blank. - - The ``expire`` is set in **seconds**, which will be added to the current time. Do not include the time, but - rather only the number of seconds from *now* that you wish the cookie to be valid. If the ``expire`` is set to - zero, the cookie will only last as long as the browser is open. - - .. note:: However, if the ``value`` is set to an empty string and the ``expire`` is set to ``0``, the cookie - will be deleted. - - For site-wide cookies regardless of how your site is requested, add your URL to the ``domain`` starting with a - period, like this: ``.your-domain.com``. - - The ``path`` is usually not needed since the method sets a root path. - - The ``prefix`` is only needed if you need to avoid name collisions with other identically named cookies for your - server. - - The ``secure`` flag is only needed if you want to make it a secure cookie by setting it to ``true``. - - The ``samesite`` value controls how cookies are shared between domains and sub-domains. Allowed values are - ``'None'``, ``'Lax'``, ``'Strict'`` or a blank string ``''``. If set to a blank string, the default SameSite - attribute will be set. - - **Discrete Parameters** - - If you prefer, you can set the cookie by passing data using individual parameters: - - .. literalinclude:: response/024.php - - .. php:method:: deleteCookie($name = ''[, $domain = ''[, $path = '/'[, $prefix = '']]]) - - :param mixed $name: Cookie name or an array of parameters - :param string $domain: Cookie domain - :param string $path: Cookie path - :param string $prefix: Cookie name prefix - :rtype: void - - Deletes an existing cookie. - - .. note:: This also just sets a browser cookie for deleting the cookie. - - Only the ``name`` is required. - - The ``prefix`` is only needed if you need to avoid name collisions with other identically named cookies for your - server. - - Provide a ``prefix`` if cookies should only be deleted for that subset. Provide a ``domain`` name if cookies - should only be deleted for that domain. Provide a ``path`` name if cookies should only be deleted for that path. - - If any of the optional parameters are empty, then the same-named cookie will be deleted across all that apply. - - Example: - - .. literalinclude:: response/025.php - - .. php:method:: hasCookie($name = ''[, $value = null[, $prefix = '']]) - - :param mixed $name: Cookie name or an array of parameters - :param string $value: Cookie value - :param string $prefix: Cookie name prefix - :rtype: bool - - Checks to see if the Response has a specified cookie or not. - - **Notes** - - Only the ``name`` is required. If a ``prefix`` is specified, it will be prepended to the cookie name. - - If no ``value`` is given, the method just checks for the existence of the named cookie. If a ``value`` is given, - then the method checks that the cookie exists, and that it has the prescribed value. - - Example: - - .. literalinclude:: response/026.php - - .. php:method:: getCookie($name = ''[, $prefix = '']) - - :param string $name: Cookie name - :param string $prefix: Cookie name prefix - :rtype: ``Cookie|Cookie[]|null`` - - Returns the named cookie, if found, or ``null``. If no ``name`` is given, returns the array of ``Cookie`` - objects. - - Example: - - .. literalinclude:: response/027.php - - .. php:method:: getCookies() - - :rtype: ``Cookie[]`` - - Returns all cookies currently set within the Response instance. These are any cookies that you have specifically - set during the current request only. diff --git a/user_guide_src/source/outgoing/response/001.php b/user_guide_src/source/outgoing/response/001.php deleted file mode 100644 index 9815f6f1475d..000000000000 --- a/user_guide_src/source/outgoing/response/001.php +++ /dev/null @@ -1,3 +0,0 @@ -response->setStatusCode(404)->setBody($body); diff --git a/user_guide_src/source/outgoing/response/002.php b/user_guide_src/source/outgoing/response/002.php deleted file mode 100644 index d5ed0fd87d96..000000000000 --- a/user_guide_src/source/outgoing/response/002.php +++ /dev/null @@ -1,3 +0,0 @@ -response->setStatusCode(404, 'Nope. Not here.'); diff --git a/user_guide_src/source/outgoing/response/003.php b/user_guide_src/source/outgoing/response/003.php deleted file mode 100644 index da5819d98860..000000000000 --- a/user_guide_src/source/outgoing/response/003.php +++ /dev/null @@ -1,11 +0,0 @@ - true, - 'id' => 123, -]; - -return $this->response->setJSON($data); - -// or -return $this->response->setXML($data); diff --git a/user_guide_src/source/outgoing/response/004.php b/user_guide_src/source/outgoing/response/004.php deleted file mode 100644 index 0ddaf8d93d5e..000000000000 --- a/user_guide_src/source/outgoing/response/004.php +++ /dev/null @@ -1,4 +0,0 @@ -response->setHeader('Location', 'http://example.com') - ->setHeader('WWW-Authenticate', 'Negotiate'); diff --git a/user_guide_src/source/outgoing/response/005.php b/user_guide_src/source/outgoing/response/005.php deleted file mode 100644 index 1ee29e5d3c05..000000000000 --- a/user_guide_src/source/outgoing/response/005.php +++ /dev/null @@ -1,4 +0,0 @@ -response->setHeader('Cache-Control', 'no-cache') - ->appendHeader('Cache-Control', 'must-revalidate'); diff --git a/user_guide_src/source/outgoing/response/006.php b/user_guide_src/source/outgoing/response/006.php deleted file mode 100644 index c1c5b5ae4e66..000000000000 --- a/user_guide_src/source/outgoing/response/006.php +++ /dev/null @@ -1,3 +0,0 @@ -response->removeHeader('Location'); diff --git a/user_guide_src/source/outgoing/response/007.php b/user_guide_src/source/outgoing/response/007.php deleted file mode 100644 index f36109c28be1..000000000000 --- a/user_guide_src/source/outgoing/response/007.php +++ /dev/null @@ -1,6 +0,0 @@ -response->download($name, $data); diff --git a/user_guide_src/source/outgoing/response/008.php b/user_guide_src/source/outgoing/response/008.php deleted file mode 100644 index f8c521bcd3f6..000000000000 --- a/user_guide_src/source/outgoing/response/008.php +++ /dev/null @@ -1,4 +0,0 @@ -response->download('/path/to/photo.jpg', null); diff --git a/user_guide_src/source/outgoing/response/009.php b/user_guide_src/source/outgoing/response/009.php deleted file mode 100644 index ab01add9bf1b..000000000000 --- a/user_guide_src/source/outgoing/response/009.php +++ /dev/null @@ -1,3 +0,0 @@ -response->download('awkwardEncryptedFileName.fakeExt', null)->setFileName('expenses.csv'); diff --git a/user_guide_src/source/outgoing/response/010.php b/user_guide_src/source/outgoing/response/010.php deleted file mode 100644 index 93acf62e99fa..000000000000 --- a/user_guide_src/source/outgoing/response/010.php +++ /dev/null @@ -1,8 +0,0 @@ - 300, - 's-maxage' => 900, - 'etag' => 'abcde', -]; -$this->response->setCache($options); diff --git a/user_guide_src/source/outgoing/response/014.php b/user_guide_src/source/outgoing/response/014.php deleted file mode 100644 index c05ef6fbe606..000000000000 --- a/user_guide_src/source/outgoing/response/014.php +++ /dev/null @@ -1,3 +0,0 @@ -getStatusCode(); diff --git a/user_guide_src/source/outgoing/response/015.php b/user_guide_src/source/outgoing/response/015.php deleted file mode 100644 index 3fbc71bc6371..000000000000 --- a/user_guide_src/source/outgoing/response/015.php +++ /dev/null @@ -1,3 +0,0 @@ -setStatusCode(404); diff --git a/user_guide_src/source/outgoing/response/016.php b/user_guide_src/source/outgoing/response/016.php deleted file mode 100644 index 31a4990eb9ee..000000000000 --- a/user_guide_src/source/outgoing/response/016.php +++ /dev/null @@ -1,3 +0,0 @@ -setStatusCode(230, 'Tardis initiated'); diff --git a/user_guide_src/source/outgoing/response/017.php b/user_guide_src/source/outgoing/response/017.php deleted file mode 100644 index 78ce30be95bb..000000000000 --- a/user_guide_src/source/outgoing/response/017.php +++ /dev/null @@ -1,3 +0,0 @@ -getReasonPhrase(); diff --git a/user_guide_src/source/outgoing/response/019.php b/user_guide_src/source/outgoing/response/019.php deleted file mode 100644 index f74953ae772d..000000000000 --- a/user_guide_src/source/outgoing/response/019.php +++ /dev/null @@ -1,5 +0,0 @@ -setContentType('text/plain'); -$response->setContentType('text/html'); -$response->setContentType('application/json'); diff --git a/user_guide_src/source/outgoing/response/020.php b/user_guide_src/source/outgoing/response/020.php deleted file mode 100644 index fdbc546b6fad..000000000000 --- a/user_guide_src/source/outgoing/response/020.php +++ /dev/null @@ -1,3 +0,0 @@ -setContentType('text/plain', 'x-pig-latin'); diff --git a/user_guide_src/source/outgoing/response/021.php b/user_guide_src/source/outgoing/response/021.php deleted file mode 100644 index d5275cfb734e..000000000000 --- a/user_guide_src/source/outgoing/response/021.php +++ /dev/null @@ -1,7 +0,0 @@ -noCache(); -/* - * Sets the following header: - * Cache-Control: no-store, max-age=0, no-cache - */ diff --git a/user_guide_src/source/outgoing/response/022.php b/user_guide_src/source/outgoing/response/022.php deleted file mode 100644 index 85f2b3d62986..000000000000 --- a/user_guide_src/source/outgoing/response/022.php +++ /dev/null @@ -1,4 +0,0 @@ -setLastModified(date('D, d M Y H:i:s')); -$response->setLastModified(\DateTime::createFromFormat('!U', $timestamp)); diff --git a/user_guide_src/source/outgoing/response/023.php b/user_guide_src/source/outgoing/response/023.php deleted file mode 100644 index dd3d905add0e..000000000000 --- a/user_guide_src/source/outgoing/response/023.php +++ /dev/null @@ -1,15 +0,0 @@ - 'The Cookie Name', - 'value' => 'The Value', - 'expire' => 86500, - 'domain' => '.some-domain.com', - 'path' => '/', - 'prefix' => 'myprefix_', - 'secure' => true, - 'httponly' => false, - 'samesite' => 'Lax', -]; - -$response->setCookie($cookie); diff --git a/user_guide_src/source/outgoing/response/024.php b/user_guide_src/source/outgoing/response/024.php deleted file mode 100644 index 3b75c4004362..000000000000 --- a/user_guide_src/source/outgoing/response/024.php +++ /dev/null @@ -1,3 +0,0 @@ -setCookie($name, $value, $expire, $domain, $path, $prefix, $secure, $httponly, $samesite); diff --git a/user_guide_src/source/outgoing/response/025.php b/user_guide_src/source/outgoing/response/025.php deleted file mode 100644 index a2343928babe..000000000000 --- a/user_guide_src/source/outgoing/response/025.php +++ /dev/null @@ -1,3 +0,0 @@ -deleteCookie($name); diff --git a/user_guide_src/source/outgoing/response/026.php b/user_guide_src/source/outgoing/response/026.php deleted file mode 100644 index ee92fa38c094..000000000000 --- a/user_guide_src/source/outgoing/response/026.php +++ /dev/null @@ -1,5 +0,0 @@ -hasCookie($name)) { - // ... -} diff --git a/user_guide_src/source/outgoing/response/027.php b/user_guide_src/source/outgoing/response/027.php deleted file mode 100644 index 1d76679940c8..000000000000 --- a/user_guide_src/source/outgoing/response/027.php +++ /dev/null @@ -1,3 +0,0 @@ -getCookie($name); diff --git a/user_guide_src/source/outgoing/response/028.php b/user_guide_src/source/outgoing/response/028.php deleted file mode 100644 index 6f6f6286dbad..000000000000 --- a/user_guide_src/source/outgoing/response/028.php +++ /dev/null @@ -1,4 +0,0 @@ -to('admin/home'); diff --git a/user_guide_src/source/outgoing/response/029.php b/user_guide_src/source/outgoing/response/029.php deleted file mode 100644 index 6fe1122b6407..000000000000 --- a/user_guide_src/source/outgoing/response/029.php +++ /dev/null @@ -1,4 +0,0 @@ -route('user_gallery'); diff --git a/user_guide_src/source/outgoing/response/030.php b/user_guide_src/source/outgoing/response/030.php deleted file mode 100644 index f605edb4855a..000000000000 --- a/user_guide_src/source/outgoing/response/030.php +++ /dev/null @@ -1,4 +0,0 @@ -back(); - -// Keep the old input values upon redirect so they can be used by the `old()` function. -return redirect()->back()->withInput(); - -// Set a flash message. -return redirect()->back()->with('foo', 'message'); diff --git a/user_guide_src/source/outgoing/response/032.php b/user_guide_src/source/outgoing/response/032.php deleted file mode 100644 index c2cfa3d62acd..000000000000 --- a/user_guide_src/source/outgoing/response/032.php +++ /dev/null @@ -1,10 +0,0 @@ -to('admin/home', 301); - -// Redirect to a route with status code 308. -return redirect()->route('user_gallery', [], 308); - -// Redirect back with status code 302. -return redirect()->back(302); diff --git a/user_guide_src/source/outgoing/response/033.php b/user_guide_src/source/outgoing/response/033.php deleted file mode 100644 index 8afaf84960ab..000000000000 --- a/user_guide_src/source/outgoing/response/033.php +++ /dev/null @@ -1,6 +0,0 @@ -response->download($name, $data)->inline(); diff --git a/user_guide_src/source/outgoing/response/034.php b/user_guide_src/source/outgoing/response/034.php deleted file mode 100644 index 32c56afe6da6..000000000000 --- a/user_guide_src/source/outgoing/response/034.php +++ /dev/null @@ -1,4 +0,0 @@ -back()->withCookies(); diff --git a/user_guide_src/source/outgoing/response/035.php b/user_guide_src/source/outgoing/response/035.php deleted file mode 100644 index 3ac3578d21f0..000000000000 --- a/user_guide_src/source/outgoing/response/035.php +++ /dev/null @@ -1,4 +0,0 @@ -back()->withHeaders(); diff --git a/user_guide_src/source/outgoing/table.rst b/user_guide_src/source/outgoing/table.rst deleted file mode 100644 index 065d9c994ffa..000000000000 --- a/user_guide_src/source/outgoing/table.rst +++ /dev/null @@ -1,215 +0,0 @@ -################ -HTML Table Class -################ - -The Table Class provides methods that enable you to auto-generate HTML tables from arrays or database result sets. - -.. contents:: - :local: - :depth: 2 - -********************* -Using the Table Class -********************* - -Initializing the Class -====================== - -The Table class is not provided as a service, and should be instantiated "normally", for instance: - -.. literalinclude:: table/001.php - -Examples -======== - -Here is an example showing how you can create a table from a multi-dimensional array. Note that the first array index -will become the table heading (or you can set your own headings using the ``setHeading()`` method described in the -function reference below). - -.. literalinclude:: table/002.php - -Here is an example of a table created from a database query result. The table class will automatically generate the -headings based on the field names (or you can set your own headings using the ``setHeading()`` method described in the -class reference below). - -.. literalinclude:: table/003.php - -Here is an example showing how you might create a table using discrete parameters: - -.. literalinclude:: table/004.php - -Here is the same example, except instead of individual parameters, arrays are used: - -.. literalinclude:: table/005.php - -Changing the Look of Your Table -=============================== - -The Table Class permits you to set a table template with which you can specify the design of your layout. Here is the -template prototype: - -.. literalinclude:: table/006.php - -.. note:: You'll notice there are two sets of "row" blocks in the template. These permit you to create alternating row - colors or design elements that alternate with each iteration of the row data. - -You are NOT required to submit a complete template. If you only need to change parts of the layout, you can simply -submit those elements. In this example, only the table opening tag is being changed: - -.. literalinclude:: table/007.php - -You can also set defaults for these by passing an array of template settings to the Table constructor: - -.. literalinclude:: table/008.php - -.. _table-sync-rows-with-headings: - -Synchronizing Rows with Headings -================================ - -.. versionadded:: 4.4.0 - -The ``setSyncRowsWithHeading(true)`` method ensures that each data value is placed in the same column as defined in -``setHeading()`` if an associative array was used as a parameter. This is especially useful when dealing with data -loaded via REST API where the order is not to your liking, or if the API returned too much data. - -If a data row contains a key that is not present in the heading, its value is filtered out. Conversely, if a data row -does not have a key listed in the heading, an empty cell will be placed in its place. - -.. literalinclude:: table/019.php - -.. important:: You must call ``setSyncRowsWithHeading(true)`` and ``setHeading([...])`` before adding any rows via - ``addRow([...])`` where the rearrangement of columns takes place. - -Using an array as input to ``generate()`` produces the same result: - -.. literalinclude:: table/020.php - - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\View - -.. php:class:: Table - - .. attribute:: $function = null - - Allows you to specify a native PHP function or a valid function array object to be applied to all cell data. - - .. literalinclude:: table/009.php - - In the above example, all cell data would be run through PHP's :php:func:`htmlspecialchars()` function, - resulting in:: - - Fred<strong>Blue</strong>Small - - .. php:method:: generate([$tableData = null]) - - :param mixed $tableData: Data to populate the table rows with - :returns: HTML table - :rtype: string - - Returns a string containing the generated table. Accepts an optional parameter which can be an array or a - database result object. - - .. php:method:: setCaption($caption) - - :param string $caption: Table caption - :returns: Table instance (method chaining) - :rtype: Table - - Permits you to add a caption to the table. - - .. literalinclude:: table/010.php - - .. php:method:: setHeading([$args = [] [, ...]]) - - :param mixed $args: An array or multiple strings containing the table column titles - :returns: Table instance (method chaining) - :rtype: Table - - Permits you to set the table heading. You can submit an array or discrete params: - - .. literalinclude:: table/011.php - - .. php:method:: setFooting([$args = [] [, ...]]) - - :param mixed $args: An array or multiple strings containing the table footing values - :returns: Table instance (method chaining) - :rtype: Table - - Permits you to set the table footing. You can submit an array or discrete params: - - .. literalinclude:: table/012.php - - .. php:method:: addRow([$args = [] [, ...]]) - - :param mixed $args: An array or multiple strings containing the row values - :returns: Table instance (method chaining) - :rtype: Table - - Permits you to add a row to your table. You can submit an array or discrete params: - - .. literalinclude:: table/013.php - - If you would like to set an individual cell's tag attributes, you can use an associative array for that cell. - The associative key **data** defines the cell's data. Any other key => val pairs are added as key='val' - attributes to the tag: - - .. literalinclude:: table/014.php - - .. php:method:: makeColumns([$array = [] [, $columnLimit = 0]]) - - :param array $array: An array containing multiple rows' data - :param int $columnLimit: Count of columns in the table - :returns: An array of HTML table columns - :rtype: array - - This method takes a one-dimensional array as input and creates a multi-dimensional array with a depth equal to - the number of columns desired. This allows a single array with many elements to be displayed in a table that has - a fixed column count. Consider this example: - - .. literalinclude:: table/015.php - - .. php:method:: setTemplate($template) - - :param array $template: An associative array containing template values - :returns: true on success, false on failure - :rtype: bool - - Permits you to set your template. You can submit a full or partial template. - - .. literalinclude:: table/016.php - - .. php:method:: setEmpty($value) - - :param mixed $value: Value to put in empty cells - :returns: Table instance (method chaining) - :rtype: Table - - Lets you set a default value for use in any table cells that are empty. You might, for example, set a - non-breaking space: - - .. literalinclude:: table/017.php - - .. php:method:: clear() - - :returns: Table instance (method chaining) - :rtype: Table - - Lets you clear the table heading, row data and caption. If you need to show multiple tables with different data - you should call this method after each table has been generated to clear the previous table information. - - Example: - - .. literalinclude:: table/018.php - - .. php:method:: setSyncRowsWithHeading(bool $orderByKey) - - :returns: Table instance (method chaining) - :rtype: Table - - Enables each row data key to be ordered by heading keys. This gives more control over data being displayed in - the correct column. Make sure to set this value before calling the first ``addRow()`` method. diff --git a/user_guide_src/source/outgoing/table/001.php b/user_guide_src/source/outgoing/table/001.php deleted file mode 100644 index dbd5ba323335..000000000000 --- a/user_guide_src/source/outgoing/table/001.php +++ /dev/null @@ -1,3 +0,0 @@ -generate($data); diff --git a/user_guide_src/source/outgoing/table/003.php b/user_guide_src/source/outgoing/table/003.php deleted file mode 100644 index 91218de3f143..000000000000 --- a/user_guide_src/source/outgoing/table/003.php +++ /dev/null @@ -1,7 +0,0 @@ -query('SELECT * FROM my_table'); - -echo $table->generate($query); diff --git a/user_guide_src/source/outgoing/table/004.php b/user_guide_src/source/outgoing/table/004.php deleted file mode 100644 index 0d0679305409..000000000000 --- a/user_guide_src/source/outgoing/table/004.php +++ /dev/null @@ -1,11 +0,0 @@ -setHeading('Name', 'Color', 'Size'); - -$table->addRow('Fred', 'Blue', 'Small'); -$table->addRow('Mary', 'Red', 'Large'); -$table->addRow('John', 'Green', 'Medium'); - -echo $table->generate(); diff --git a/user_guide_src/source/outgoing/table/005.php b/user_guide_src/source/outgoing/table/005.php deleted file mode 100644 index 08d6dabb1850..000000000000 --- a/user_guide_src/source/outgoing/table/005.php +++ /dev/null @@ -1,11 +0,0 @@ -setHeading(['Name', 'Color', 'Size']); - -$table->addRow(['Fred', 'Blue', 'Small']); -$table->addRow(['Mary', 'Red', 'Large']); -$table->addRow(['John', 'Green', 'Medium']); - -echo $table->generate(); diff --git a/user_guide_src/source/outgoing/table/006.php b/user_guide_src/source/outgoing/table/006.php deleted file mode 100644 index a5955aa5704b..000000000000 --- a/user_guide_src/source/outgoing/table/006.php +++ /dev/null @@ -1,38 +0,0 @@ - '', - - 'thead_open' => '', - 'thead_close' => '', - - 'heading_row_start' => '', - 'heading_row_end' => '', - 'heading_cell_start' => '', - - 'tfoot_open' => '', - 'tfoot_close' => '', - - 'footing_row_start' => '', - 'footing_row_end' => '', - 'footing_cell_start' => '', - - 'tbody_open' => '', - 'tbody_close' => '', - - 'row_start' => '', - 'row_end' => '', - 'cell_start' => '', - - 'row_alt_start' => '', - 'row_alt_end' => '', - 'cell_alt_start' => '', - - 'table_close' => '
    ', - 'heading_cell_end' => '
    ', - 'footing_cell_end' => '
    ', - 'cell_end' => '
    ', - 'cell_alt_end' => '
    ', -]; - -$table->setTemplate($template); diff --git a/user_guide_src/source/outgoing/table/007.php b/user_guide_src/source/outgoing/table/007.php deleted file mode 100644 index 022abfc296ad..000000000000 --- a/user_guide_src/source/outgoing/table/007.php +++ /dev/null @@ -1,7 +0,0 @@ - '', -]; - -$table->setTemplate($template); diff --git a/user_guide_src/source/outgoing/table/008.php b/user_guide_src/source/outgoing/table/008.php deleted file mode 100644 index 99f12f2b2fcd..000000000000 --- a/user_guide_src/source/outgoing/table/008.php +++ /dev/null @@ -1,7 +0,0 @@ - '
    ', -]; - -$table = new \CodeIgniter\View\Table($customSettings); diff --git a/user_guide_src/source/outgoing/table/009.php b/user_guide_src/source/outgoing/table/009.php deleted file mode 100644 index c08af5b1fa9a..000000000000 --- a/user_guide_src/source/outgoing/table/009.php +++ /dev/null @@ -1,9 +0,0 @@ -setHeading('Name', 'Color', 'Size'); -$table->addRow('Fred', 'Blue', 'Small'); - -$table->function = 'htmlspecialchars'; -echo $table->generate(); diff --git a/user_guide_src/source/outgoing/table/010.php b/user_guide_src/source/outgoing/table/010.php deleted file mode 100644 index 0c6a74ea5b35..000000000000 --- a/user_guide_src/source/outgoing/table/010.php +++ /dev/null @@ -1,3 +0,0 @@ -setCaption('Colors'); diff --git a/user_guide_src/source/outgoing/table/011.php b/user_guide_src/source/outgoing/table/011.php deleted file mode 100644 index a6657c8690e4..000000000000 --- a/user_guide_src/source/outgoing/table/011.php +++ /dev/null @@ -1,5 +0,0 @@ -setHeading('Name', 'Color', 'Size'); // or - -$table->setHeading(['Name', 'Color', 'Size']); diff --git a/user_guide_src/source/outgoing/table/012.php b/user_guide_src/source/outgoing/table/012.php deleted file mode 100644 index 01a26b237908..000000000000 --- a/user_guide_src/source/outgoing/table/012.php +++ /dev/null @@ -1,5 +0,0 @@ -setFooting('Subtotal', $subtotal, $notes); // or - -$table->setFooting(['Subtotal', $subtotal, $notes]); diff --git a/user_guide_src/source/outgoing/table/013.php b/user_guide_src/source/outgoing/table/013.php deleted file mode 100644 index 1229bd01d7cd..000000000000 --- a/user_guide_src/source/outgoing/table/013.php +++ /dev/null @@ -1,5 +0,0 @@ -addRow('Blue', 'Red', 'Green'); // or - -$table->addRow(['Blue', 'Red', 'Green']); diff --git a/user_guide_src/source/outgoing/table/014.php b/user_guide_src/source/outgoing/table/014.php deleted file mode 100644 index d19424fc9fe4..000000000000 --- a/user_guide_src/source/outgoing/table/014.php +++ /dev/null @@ -1,9 +0,0 @@ - 'Blue', 'class' => 'highlight', 'colspan' => 2]; -$table->addRow($cell, 'Red', 'Green'); - -?> - - - diff --git a/user_guide_src/source/outgoing/table/015.php b/user_guide_src/source/outgoing/table/015.php deleted file mode 100644 index 5bc5a7029ed3..000000000000 --- a/user_guide_src/source/outgoing/table/015.php +++ /dev/null @@ -1,33 +0,0 @@ -makeColumns($list, 3); - -$table->generate($newList); - -?> - - -
    BlueRedGreen
    - - - - - - - - - - - - - - - - - - - - -
    onetwothree
    fourfivesix
    seveneightnine
    teneleventwelve
    diff --git a/user_guide_src/source/outgoing/table/016.php b/user_guide_src/source/outgoing/table/016.php deleted file mode 100644 index 022abfc296ad..000000000000 --- a/user_guide_src/source/outgoing/table/016.php +++ /dev/null @@ -1,7 +0,0 @@ - '', -]; - -$table->setTemplate($template); diff --git a/user_guide_src/source/outgoing/table/017.php b/user_guide_src/source/outgoing/table/017.php deleted file mode 100644 index 8f7b203a3344..000000000000 --- a/user_guide_src/source/outgoing/table/017.php +++ /dev/null @@ -1,3 +0,0 @@ -setEmpty(' '); diff --git a/user_guide_src/source/outgoing/table/018.php b/user_guide_src/source/outgoing/table/018.php deleted file mode 100644 index c67c746bde9b..000000000000 --- a/user_guide_src/source/outgoing/table/018.php +++ /dev/null @@ -1,21 +0,0 @@ -setCaption('Preferences') - ->setHeading('Name', 'Color', 'Size') - ->addRow('Fred', 'Blue', 'Small') - ->addRow('Mary', 'Red', 'Large') - ->addRow('John', 'Green', 'Medium'); - -echo $table->generate(); - -$table->clear(); - -$table->setCaption('Shipping') - ->setHeading('Name', 'Day', 'Delivery') - ->addRow('Fred', 'Wednesday', 'Express') - ->addRow('Mary', 'Monday', 'Air') - ->addRow('John', 'Saturday', 'Overnight'); - -echo $table->generate(); diff --git a/user_guide_src/source/outgoing/table/019.php b/user_guide_src/source/outgoing/table/019.php deleted file mode 100644 index 5478867fddfa..000000000000 --- a/user_guide_src/source/outgoing/table/019.php +++ /dev/null @@ -1,40 +0,0 @@ -setHeading(['name' => 'Name', 'color' => 'Color', 'size' => 'Size']) - ->setSyncRowsWithHeading(true) - ->addRow(['color' => 'Blue', 'name' => 'Fred', 'size' => 'Small']) - ->addRow(['size' => 'Large', 'age' => '24', 'name' => 'Mary']) - ->addRow(['color' => 'Green']); - -echo $table->generate(); -?> - - -
    - - - - - - - - - - - - - - - - - - - - - - - - -
    NameColorSize
    FredBlueSmall
    MaryLarge
    Green
    diff --git a/user_guide_src/source/outgoing/table/020.php b/user_guide_src/source/outgoing/table/020.php deleted file mode 100644 index 42bda4d2f3bc..000000000000 --- a/user_guide_src/source/outgoing/table/020.php +++ /dev/null @@ -1,24 +0,0 @@ - 'Blue', - 'name' => 'Fred', - 'size' => 'Small', - ], - [ - 'size' => 'Large', - 'age' => '24', - 'name' => 'Mary', - ], - [ - 'color' => 'Green', - ], -]; - -$table = new \CodeIgniter\View\Table(); - -$table->setHeading(['name' => 'Name', 'color' => 'Color', 'size' => 'Size']) - ->setSyncRowsWithHeading(true); - -echo $table->generate($data); diff --git a/user_guide_src/source/outgoing/view_cells.rst b/user_guide_src/source/outgoing/view_cells.rst deleted file mode 100644 index abf17129ef84..000000000000 --- a/user_guide_src/source/outgoing/view_cells.rst +++ /dev/null @@ -1,208 +0,0 @@ -########## -View Cells -########## - -Many applications have small view fragments that can be repeated from page to page, or in different places on the pages. -These are often help boxes, navigation controls, ads, login forms, etc. CodeIgniter lets you encapsulate the logic for -these presentation blocks within View Cells. They are basically mini-views that can be included in other views. They can -have logic built in to handle any cell-specific display logic. They can be used to make your views more readable and -maintainable by separating the logic for each cell into its own class. - -.. contents:: - :local: - :depth: 2 - -*************************** -Simple and Controlled Cells -*************************** - -CodeIgniter supports two types of View Cells: simple and controlled. - -**Simple View Cells** can be generated from any class and method of your choice and do not have to follow any rules, -except that they must return a string. - -**Controlled View Cells** must be generated from a class that extends the ``CodeIgniter\View\Cells\Cell`` class, which -provides additional capabilities that make your View Cells more flexible and faster to use. - -.. _app-cells: - -******************* -Calling a View Cell -******************* - -No matter which type of View Cell you are using, you can call it from any view by using the ``view_cell()`` helper -function. - -The first parameter is (1) *the name of the class and method* (Simple Cell) or (2) -*the name of the class and optional method* (Controlled Cell) to call, and the second parameter is an array or string of -parameters to pass to the method: - -.. literalinclude:: view_cells/001.php - -The string that the Cell returns will be inserted into the view where the ``view_cell()`` function was called. - -Namespace Omission -================== - -.. versionadded:: 4.3.0 - -If you do not include the full namespace for the class, it will assume it can be found in the ``App\Cells`` namespace. -So, the following example would attempt to find the ``MyClass`` class in **app/Cells/MyClass.php**. If it is not found -there, all namespaces will be scanned until it is found, searching within a **Cells** subdirectory of each namespace: - -.. literalinclude:: view_cells/002.php - -Passing Parameters as Key/Value String -====================================== - -You can also pass the parameters along as a key/value string: - -.. literalinclude:: view_cells/003.php - -************ -Simple Cells -************ - -Simple Cells are classes that return a string from the chosen method. An example of a simple Alert Message cell might -look like this: - -.. literalinclude:: view_cells/004.php - -You would call it from within a view like this: - -.. literalinclude:: view_cells/005.php - -Additionally, you can use parameter names that match the parameter variables in the method for better readability. When -you use it this way, all of the parameters must always be specified in the view cell call: - -.. literalinclude:: view_cells/006.php - -.. literalinclude:: view_cells/007.php - -.. _controlled-cells: - -**************** -Controlled Cells -**************** - -.. versionadded:: 4.3.0 - -Controlled cells have two primary goals: (1) to make it as fast as possible to build the cell, and (2) to provide -additional logic and flexibility to your views, if they need it. - -The class must extend ``CodeIgniter\View\Cells\Cell``. It should have a view file in the same folder. By convention, the -class name should be in PascalCase suffixed with ``Cell`` and the view should be the snake_cased version of the class -name, without the suffix. For example, if you have a ``MyCell`` class, the view file should be ``my.php``. - -.. note:: Prior to v4.3.5, the generated view file ended with ``_cell.php``. Though v4.3.5 and newer will generate view - files without the ``_cell`` suffix, existing view files will still be located and loaded. - -Creating a Controlled Cell -========================== - -At the most basic level, all you need to implement within the class are public properties. These properties will be made -available to the view file automatically. - -Implementing the AlertMessage from above as a Controlled Cell would look like this: - -.. literalinclude:: view_cells/008.php - -.. literalinclude:: view_cells/009.php - -.. literalinclude:: view_cells/010.php - -.. note:: If you use typed properties, you must set the initial values: - - .. literalinclude:: view_cells/023.php - -.. _generating-cell-via-command: - -Generating Cell via Command -=========================== - -You can also create a controlled cell via a built-in command from the CLI. The command is ``php spark make:cell``. It -takes one argument, the name of the cell to create. The name should be in PascalCase, and the class will be created in -the **app/Cells** directory. The view file will also be created in the **app/Cells** directory. - -.. code-block:: console - - php spark make:cell AlertMessageCell - -Using a Different View -====================== - -You can specify a custom view filepath by setting the ``view`` property in the class. The view will be located like any -view would be normally: - -.. literalinclude:: view_cells/011.php - -Customize the Rendering -======================= - -If you need more control over the rendering of the HTML, you can implement a ``render()`` method. This method allows you -to perform additional logic and pass extra data to the view, if needed. The ``render()`` method must return a string. - -To take advantage of the full features of controlled Cells, you should use ``$this->view()`` instead of the normal -``view()`` helper function: - -.. literalinclude:: view_cells/012.php - -Computed Properties -=================== - -If you need to perform additional logic for one or more properties, you can use computed properties. These require -setting the property to either ``protected`` or ``private`` and implementing a public method whose name consists of the -property name surrounded by ``get`` and ``Property``: - -.. literalinclude:: view_cells/013.php - -.. literalinclude:: view_cells/014.php - -.. literalinclude:: view_cells/015.php - -.. important:: You can't set properties that are declared as private during cell initialization. The - ``getDataProperty()`` and ``getViewProperty()`` methods are not available: they are used only for internal - processes. - -Presentation Methods -==================== - -Sometimes you need to perform additional logic for the view, but you don't want to pass it as a parameter. You can -implement a method that will be called from within the cell's view itself. This can help the readability of your views. -You may have noticed that not only method calls are allowed in the template: the entire Cell object with public -properties is available. - -.. literalinclude:: view_cells/016.php - -.. literalinclude:: view_cells/017.php - - -Performing Setup Logic -====================== - -If you need to perform additional logic before the view is rendered, you can implement a ``mount()`` method. This method -will be called just after the class is instantiated, and can be used to set additional properties or perform other -logic: - -.. literalinclude:: view_cells/018.php - -You can pass additional parameters to the ``mount()`` method by passing them as an array to the ``view_cell()`` helper -function. Any of the parameters sent that match a parameter name of the ``mount()`` method will be passed in: - -.. literalinclude:: view_cells/019.php - -.. literalinclude:: view_cells/020.php - -************ -Cell Caching -************ - -You can cache the results of the view cell call by passing the number of seconds to cache the data for as the third -parameter. This will use the currently configured cache engine: - -.. literalinclude:: view_cells/021.php - -You can provide a custom name to use instead of the auto-generated one if you like, by passing the new name as the -fourth parameter: - -.. literalinclude:: view_cells/022.php diff --git a/user_guide_src/source/outgoing/view_cells/001.php b/user_guide_src/source/outgoing/view_cells/001.php deleted file mode 100644 index 57a4fdc425dc..000000000000 --- a/user_guide_src/source/outgoing/view_cells/001.php +++ /dev/null @@ -1,7 +0,0 @@ -// In a View. - -// Simple Cell - 'value1', 'param2' => 'value2']) ?> - -// Controlled Cell - 'value1', 'param2' => 'value2']) ?> diff --git a/user_guide_src/source/outgoing/view_cells/002.php b/user_guide_src/source/outgoing/view_cells/002.php deleted file mode 100644 index 1dcea35569f2..000000000000 --- a/user_guide_src/source/outgoing/view_cells/002.php +++ /dev/null @@ -1,2 +0,0 @@ -// In a View. - 'value1', 'param2' => 'value2']) ?> diff --git a/user_guide_src/source/outgoing/view_cells/003.php b/user_guide_src/source/outgoing/view_cells/003.php deleted file mode 100644 index 93fa8eea5e19..000000000000 --- a/user_guide_src/source/outgoing/view_cells/003.php +++ /dev/null @@ -1,2 +0,0 @@ -// In a View. - diff --git a/user_guide_src/source/outgoing/view_cells/004.php b/user_guide_src/source/outgoing/view_cells/004.php deleted file mode 100644 index 26009d86a8eb..000000000000 --- a/user_guide_src/source/outgoing/view_cells/004.php +++ /dev/null @@ -1,11 +0,0 @@ -{$params['message']}
    "; - } -} diff --git a/user_guide_src/source/outgoing/view_cells/005.php b/user_guide_src/source/outgoing/view_cells/005.php deleted file mode 100644 index 776b26573251..000000000000 --- a/user_guide_src/source/outgoing/view_cells/005.php +++ /dev/null @@ -1,2 +0,0 @@ -// In a View. - 'success', 'message' => 'The user has been updated.']) ?> diff --git a/user_guide_src/source/outgoing/view_cells/006.php b/user_guide_src/source/outgoing/view_cells/006.php deleted file mode 100644 index 64157d309b12..000000000000 --- a/user_guide_src/source/outgoing/view_cells/006.php +++ /dev/null @@ -1,2 +0,0 @@ -// In a View. - diff --git a/user_guide_src/source/outgoing/view_cells/007.php b/user_guide_src/source/outgoing/view_cells/007.php deleted file mode 100644 index ab1e56b3c5e8..000000000000 --- a/user_guide_src/source/outgoing/view_cells/007.php +++ /dev/null @@ -1,20 +0,0 @@ -blogModel->where('category', $category) - ->orderBy('published_on', 'desc') - ->limit($limit) - ->get(); - - return view('recentPosts', ['posts' => $posts]); - } -} diff --git a/user_guide_src/source/outgoing/view_cells/008.php b/user_guide_src/source/outgoing/view_cells/008.php deleted file mode 100644 index f8b8c68ea8f2..000000000000 --- a/user_guide_src/source/outgoing/view_cells/008.php +++ /dev/null @@ -1,13 +0,0 @@ -"> - -
    diff --git a/user_guide_src/source/outgoing/view_cells/010.php b/user_guide_src/source/outgoing/view_cells/010.php deleted file mode 100644 index 3fdcbd9d18c1..000000000000 --- a/user_guide_src/source/outgoing/view_cells/010.php +++ /dev/null @@ -1,2 +0,0 @@ -// Called in main View: - diff --git a/user_guide_src/source/outgoing/view_cells/011.php b/user_guide_src/source/outgoing/view_cells/011.php deleted file mode 100644 index cddb2f7cc31e..000000000000 --- a/user_guide_src/source/outgoing/view_cells/011.php +++ /dev/null @@ -1,13 +0,0 @@ -view('my/custom/view', ['extra' => 'data']); - } -} diff --git a/user_guide_src/source/outgoing/view_cells/013.php b/user_guide_src/source/outgoing/view_cells/013.php deleted file mode 100644 index 32e02a03dce6..000000000000 --- a/user_guide_src/source/outgoing/view_cells/013.php +++ /dev/null @@ -1,2 +0,0 @@ -// In a View. Initialize the protected properties. - 'note', 'message' => 'test']) ?> diff --git a/user_guide_src/source/outgoing/view_cells/014.php b/user_guide_src/source/outgoing/view_cells/014.php deleted file mode 100644 index 7aa1ad4c9d8c..000000000000 --- a/user_guide_src/source/outgoing/view_cells/014.php +++ /dev/null @@ -1,34 +0,0 @@ -computed = sprintf('%s - %s', $this->type, $this->message); - } - - public function getComputedProperty(): string - { - return $this->computed; - } - - public function getTypeProperty(): string - { - return $this->type; - } - - public function getMessageProperty(): string - { - return $this->message; - } -} diff --git a/user_guide_src/source/outgoing/view_cells/015.php b/user_guide_src/source/outgoing/view_cells/015.php deleted file mode 100644 index 382152cfb105..000000000000 --- a/user_guide_src/source/outgoing/view_cells/015.php +++ /dev/null @@ -1,6 +0,0 @@ -// app/Cells/alert_message.php -
    -

    type -

    -

    message -

    -

    computed:

    -
    diff --git a/user_guide_src/source/outgoing/view_cells/016.php b/user_guide_src/source/outgoing/view_cells/016.php deleted file mode 100644 index 54d9d7d994a4..000000000000 --- a/user_guide_src/source/outgoing/view_cells/016.php +++ /dev/null @@ -1,17 +0,0 @@ -id, $post->title); - } -} diff --git a/user_guide_src/source/outgoing/view_cells/017.php b/user_guide_src/source/outgoing/view_cells/017.php deleted file mode 100644 index 359eb6fce035..000000000000 --- a/user_guide_src/source/outgoing/view_cells/017.php +++ /dev/null @@ -1,6 +0,0 @@ -// app/Cells/recent_posts.php -
      - -
    • linkPost($post) ?>
    • - -
    diff --git a/user_guide_src/source/outgoing/view_cells/018.php b/user_guide_src/source/outgoing/view_cells/018.php deleted file mode 100644 index 8767af1b40a2..000000000000 --- a/user_guide_src/source/outgoing/view_cells/018.php +++ /dev/null @@ -1,15 +0,0 @@ -posts = model('PostModel')->orderBy('created_at', 'DESC')->findAll(10); - } -} diff --git a/user_guide_src/source/outgoing/view_cells/019.php b/user_guide_src/source/outgoing/view_cells/019.php deleted file mode 100644 index cb7d231b5346..000000000000 --- a/user_guide_src/source/outgoing/view_cells/019.php +++ /dev/null @@ -1,23 +0,0 @@ -posts = model('PostModel') - ->when( - $categoryId, - static fn ($query, $categoryId) => $query->where('category_id', $categoryId), - ) - ->orderBy('created_at', 'DESC') - ->findAll(10); - } -} diff --git a/user_guide_src/source/outgoing/view_cells/020.php b/user_guide_src/source/outgoing/view_cells/020.php deleted file mode 100644 index 55d6788211d6..000000000000 --- a/user_guide_src/source/outgoing/view_cells/020.php +++ /dev/null @@ -1,2 +0,0 @@ -// Called in main View: - 5]) ?> diff --git a/user_guide_src/source/outgoing/view_cells/021.php b/user_guide_src/source/outgoing/view_cells/021.php deleted file mode 100644 index a6b814d1f9cb..000000000000 --- a/user_guide_src/source/outgoing/view_cells/021.php +++ /dev/null @@ -1,2 +0,0 @@ -// Cache the view for 5 minutes - diff --git a/user_guide_src/source/outgoing/view_cells/022.php b/user_guide_src/source/outgoing/view_cells/022.php deleted file mode 100644 index 8c588695719f..000000000000 --- a/user_guide_src/source/outgoing/view_cells/022.php +++ /dev/null @@ -1,2 +0,0 @@ -// Cache the view for 5 minutes - diff --git a/user_guide_src/source/outgoing/view_cells/023.php b/user_guide_src/source/outgoing/view_cells/023.php deleted file mode 100644 index c892fcd683a7..000000000000 --- a/user_guide_src/source/outgoing/view_cells/023.php +++ /dev/null @@ -1,13 +0,0 @@ - - - - My Layout - - - renderSection('content') ?> - - - -The ``renderSection()`` method has two arguments: ``$sectionName`` and ``$saveData``. ``$sectionName`` is the name of -the section used by any child view to name the content section. If the boolean argument ``$saveData`` is set to true, -the method saves data for subsequent calls. Otherwise, the method cleans the data after displaying the contents. - -E.g. **app/Views/welcome_message.php**:: - - - - - <?= $this->renderSection('page_title', true) ?> - - -

    renderSection('page_title') ?>

    -

    renderSection('content') ?>

    - - - -.. note:: ``$saveData`` can be used since v4.4.0. - -********************** -Using Layouts in Views -********************** - -Whenever a view wants to be inserted into a layout, it must use the ``extend()`` method at the top of the file:: - - extend('default') ?> - -The ``extend()`` method takes the name of any view file that you wish to use. Since they are standard views, they will -be located just like a view. By default, it will look in the application's View directory, but will also scan other -PSR-4 defined namespaces. You can include a namespace to locate the view in a particular namespace's View directory:: - - extend('Blog\default') ?> - -All content within a view that extends a layout must be included within ``section($name)`` and ``endSection()`` method -calls. Any content between these calls will be inserted into the layout wherever the ``renderSection($name)`` call that -matches the section name exists. - -E.g. **app/Views/some_view.php**:: - - extend('default') ?> - - section('content') ?> -

    Hello World!

    - endSection() ?> - -The ``endSection()`` does not need the section name. It automatically knows which one to close. - -Sections can contain nested sections:: - - extend('default') ?> - - section('content') ?> -

    Hello World!

    - section('javascript') ?> - let a = 'a'; - endSection() ?> - endSection() ?> - -****************** -Rendering the View -****************** - -Rendering the view and its layout is done exactly as any other view would be displayed within a controller: - -.. literalinclude:: view_layouts/001.php - -It renders the View **app/Views/some_view.php** and if it extends ``default``, the Layout **app/Views/default.php** is -also used automatically. The renderer is smart enough to detect whether the view should be rendered on its own, or if it -needs a layout. - -*********************** -Including View Partials -*********************** - -View partials are view files that do not extend any layout. They typically include content that can be reused from view -to view. When using view layouts, you must use ``$this->include()`` to include any view partials. - -:: - - extend('default') ?> - - section('content') ?> -

    Hello World!

    - - include('sidebar') ?> - endSection() ?> - -When calling the ``include()`` method, you can pass it all of the same options that you can when rendering a normal -view, including cache directives, etc. - -********************* -Assign Data to Layers -********************* - -You can pass additional variables to your templates, just like for ``view()``. If you don't use the ``saveData = false`` -flag anywhere in the templates, then the data will be inherited for each block. - -.. note:: When using a loop, passing new variables is required. - -.. literalinclude:: view_layouts/002.php - diff --git a/user_guide_src/source/outgoing/view_layouts/001.php b/user_guide_src/source/outgoing/view_layouts/001.php deleted file mode 100644 index f6105365fa47..000000000000 --- a/user_guide_src/source/outgoing/view_layouts/001.php +++ /dev/null @@ -1,11 +0,0 @@ -setVar('title', 'Homepage')->extend('default') ?> - -setVar('hideNavbar', true)->section('content') ?> -

    Items List

    - - setData(['item' => $item])->include('item_card') ?> - -endSection() ?> diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst deleted file mode 100644 index 242fc9e0aca3..000000000000 --- a/user_guide_src/source/outgoing/view_parser.rst +++ /dev/null @@ -1,709 +0,0 @@ -########### -View Parser -########### - -.. contents:: - :local: - :depth: 2 - -The View Parser can perform simple text substitution for pseudo-variables contained within your view files. It can parse -simple variables or variable tag pairs. - -Pseudo-variable names or control constructs are enclosed in braces, like this:: - - - - {blog_title} - - -

    {blog_heading}

    - - {blog_entries} -
    {title}
    -

    {body}

    - {/blog_entries} - - - - -These variables are not actual PHP variables, but rather plain text representations that allow you to eliminate PHP from -your templates (view files). - -.. note:: CodeIgniter does **not** require you to use this class since using pure PHP in your view pages (for instance - using the :doc:`View renderer `) lets them run a little faster. However, some developers - prefer to use some form of template engine if they work with designers who might find working with PHP confusing. - -*************************** -Using the View Parser Class -*************************** - -The simplest method to load the parser class is through its service: - -.. literalinclude:: view_parser/001.php - -Alternatively, if you are not using the ``Parser`` class as your default renderer, you can instantiate it directly: - -.. literalinclude:: view_parser/002.php - -Then you can use any of the three standard rendering methods that it provides: ``render()``, ``setVar()`` and -``setData()``. You will also be able to specify delimiters directly through the ``setDelimiters()`` method. - -.. important:: The ``Parser`` escapes literal PHP tags in view templates instead of executing them. However, expressions - in ``{if ...}`` and ``{elseif ...}`` tags are evaluated as PHP. Treat template source as trusted code, or - :ref:`restrict conditionals ` when less-trusted users can edit templates. - -What It Does -============ - -The ``Parser`` class processes templates stored in the application's view path. Literal PHP tags are not supported. - -Each view parameter (which we refer to as a pseudo-variable) triggers a substitution, based on the type of value you -provided for it. Pseudo-variables are not extracted into PHP variables; instead, their value is accessed through the -pseudo-variable syntax, where its name is referenced inside braces. - -The Parser class uses an associative array internally to accumulate pseudo-variable settings until you call its -``render()`` method. This means that your pseudo-variable names need to be unique, or a later parameter setting will -override an earlier one. - -This also impacts escaping parameter values for different contexts inside your script. You will have to give each -escaped value a unique parameter name. - -Parser Templates -================ - -You can use the ``render()`` method to parse (or render) simple templates, like this: - -.. literalinclude:: view_parser/003.php - -View parameters are passed to ``setData()`` as an associative array of data to be replaced in the template. - -In the above example, the template would contain two variables: ``{blog_title}`` and ``{blog_heading}``. - -The first parameter to ``render()`` contains the name of the template, where ``blog_template`` is the name of your view -template file. - -.. important:: If the file extension is omitted, then the views are expected to end with the .php extension. - -Parser Configuration Options -============================ - -Several options can be passed to the ``render()`` or ``renderString()`` methods. - -- ``cache`` - the time in seconds to save a view's results; ignored for ``renderString()`` -- ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath; ignored for - ``renderString()`` -- ``saveData`` - true if the view data parameters should be retained for subsequent calls; default is **true** -- ``cascadeData`` - true if pseudo-variable settings should be passed on to nested substitutions; default is **true** -- ``restrictConditionals`` - true to allow only simple expressions in conditionals; see - :ref:`parser-restricting-conditionals`. Defaults to the ``Config\View::$restrictParserConditionals`` value (**false**) - -.. literalinclude:: view_parser/004.php - -*********************** -Substitution Variations -*********************** - -There are three types of substitution supported: simple, looping, and nested. Substitutions are performed in the same -sequence that pseudo-variables were added. - -The **simple substitution** performed by the parser is a one-to-one replacement of pseudo-variables where the -corresponding data parameter has either a scalar or string value, as in this example: - -.. literalinclude:: view_parser/005.php - -Substitution values are treated as data, not as template code. Any Parser syntax within a value is rendered literally -and is not processed by later substitutions. This also applies to values used inside variable pairs - the pairs -themselves must be defined in the template. - -The ``Parser`` takes substitution a lot further with "variable pairs", used for nested substitutions or looping, and -with some advanced constructs for conditional substitution. - -When the parser executes, it will generally: - -- handle any conditional substitutions -- handle any nested/looping substitutions -- handle the remaining single substitutions - -Loop Substitutions -================== - -A loop substitution happens when the value for a pseudo-variable is a sequential array of arrays, like an array of row -settings. - -The above example code allows simple variables to be replaced. What if you would like an entire block of variables to be -repeated, with each iteration containing new values? Consider the template example we showed at the top of the page:: - - - - {blog_title} - - -

    {blog_heading}

    - - {blog_entries} -
    {title}
    -

    {body}

    - {/blog_entries} - - - - -In the above code you'll notice a pair of variables: ``{blog_entries}`` data... ``{/blog_entries}``. In a case like -this, the entire chunk of data between these pairs would be repeated multiple times, corresponding to the number of rows -in the "blog_entries" element of the parameters array. - -Parsing variable pairs is done using the identical code shown above to parse single variables, except that you will add -a multi-dimensional array corresponding to your variable pair data. Consider this example: - -.. literalinclude:: view_parser/006.php - -The value for the pseudo-variable ``blog_entries`` is a sequential array of associative arrays. The outer level does not -have keys associated with each of the nested "rows". - -If your "pair" data is coming from a database result, which is already a multi-dimensional array, you can simply use the -database ``getResultArray()`` method: - -.. literalinclude:: view_parser/007.php - -If the array you are trying to loop over contains objects instead of arrays, the parser will first look for a -``toArray()`` method on the object. If it exists, that method will be called and the resulting array is then looped over -just as described above. If no ``toArray()`` method exists, the object will be cast as an array. Public properties are -available by name, while non-public properties have visibility-specific prefixes in their array keys. - -This is especially useful with Entity classes, whose ``toArray()`` method returns their attributes with any configured -casts and data mappings applied. - -Nested Substitutions -==================== - -A nested substitution happens when the value for a pseudo-variable is an associative array of values, like a record from -a database: - -.. literalinclude:: view_parser/008.php - -The value for the pseudo-variable ``blog_entries`` is an associative array. The key/value pairs defined inside it will -be exposed inside the variable pair loop for that variable. - -A **blog_template.php** that might work for the above:: - -

    {blog_title} - {blog_heading}

    - {blog_entries} -
    -

    {title}

    -

    {body}

    -
    - {/blog_entries} - -If you would like the other pseudo-variables accessible inside the ``blog_entries`` scope, then make sure that the -``cascadeData`` option is set to true. - -Comments -======== - -You can place comments in your templates that will be ignored and removed during parsing by wrapping the comments in -``{# #}`` symbols. - -:: - - {# This comment is removed during parsing. #} - {blog_entry} -
    -

    {title}

    -

    {body}

    -
    - {/blog_entry} - -Cascading Data -============== - -With both a nested and a loop substitution, you have the option of cascading data pairs into the inner substitution. - -The following example is not impacted by cascading: - -.. literalinclude:: view_parser/009.php - -This example gives different results, depending on cascading: - -.. literalinclude:: view_parser/010.php - -Preventing Parsing -================== - -You can specify portions of the page to not be parsed with the ``{noparse}`` ``{/noparse}`` tag pair. Anything in this -section will stay exactly as it is, with no variable substitution, looping, etc., happening to the markup between the -brackets. - -:: - - {noparse} -

    Untouched Code

    - {/noparse} - -Conditional Logic -================= - -The Parser class supports some basic conditionals to handle ``if``, ``else``, and ``elseif`` syntax. All ``if`` blocks -must be closed with an ``endif`` tag:: - - {if $role=='admin'} -

    Welcome, Admin!

    - {endif} - -This simple block is converted to the following during parsing: - -.. literalinclude:: view_parser/011.php - -All variables used within if statements must have been previously set with the same name. Other than that, it is treated -exactly like a standard PHP conditional, and all standard PHP rules would apply here. You can use any of the comparison -operators you would normally, like ``==``, ``===``, ``!==``, ``<``, ``>``, etc. - -:: - - {if $role=='admin'} -

    Welcome, Admin

    - {elseif $role=='moderator'} -

    Welcome, Moderator

    - {else} -

    Welcome, User

    - {endif} - -Values passed through ``setData()`` can control a conditional in a trusted template: - -.. literalinclude:: view_parser/028.php - -The value of ``$role`` is checked by the condition; it is not parsed as PHP source. - -.. warning:: Conditionals are evaluated as PHP expressions using ``eval()``. Anyone who can edit template source can - execute PHP code through an ``{if ...}`` or ``{elseif ...}`` tag. Escaping literal PHP tags does not make an - untrusted template safe to render. If less-trusted users can edit templates, for example email templates composed in - your application, enable :ref:`restricted conditionals `. - -.. _parser-restricting-conditionals: - -Restricting Conditionals ------------------------- - -.. versionadded:: 4.7.5 - -Conditionals are not restricted by default. Enable restriction whenever less-trusted users can edit template source. -When restricted, a condition may only contain: - -- variables, except ``$this`` -- string and number literals, and ``true``, ``false`` and ``null`` -- the arithmetic operators ``+``, ``-``, ``*``, ``/``, ``%`` and ``**``, including unary ``+`` and ``-`` -- the comparison operators ``==``, ``!=``, ``<>``, ``===``, ``!==``, ``<``, ``>``, ``<=`` and ``>=`` -- the logical operators ``&&``, ``||``, ``and``, ``or`` and ``!`` -- parentheses for grouping - -For example, ``{if $vip}``, ``{if $role == 'admin'}`` and ``{if $total > 100 && ($country == 'GB' || !$guest)}`` are -allowed. Negative numbers and simple arithmetic, such as ``{if $balance < -10}`` or ``{if $total + 5 >= 100}``, are also -allowed. Anything else, such as function calls, constants, property or array access, assignment, concatenation and -string interpolation, throws a ``ViewException`` before the template is evaluated. - -To restrict conditionals for a single call, pass the ``restrictConditionals`` option: - -.. literalinclude:: view_parser/030.php - -To restrict conditionals by default, set ``$restrictParserConditionals`` to ``true`` in **app/Config/View.php**: - -.. literalinclude:: view_parser/031.php - -You can then allow full PHP conditionals for a trusted template: - -.. literalinclude:: view_parser/032.php - -When a plugin or filter renders another template using the same Parser instance, the nested render inherits any active -restriction. It cannot disable the outer render's restriction, even with ``restrictConditionals`` set to ``false``. The -restriction is restored to its previous state when the render finishes or throws an exception, so it does not affect -later independent renders. - -.. note:: Restricting conditionals only limits ``{if ...}`` and ``{elseif ...}`` tags. Pseudo-variables in less-trusted - templates can still reference any view data, and ``{! !}`` tags output data without escaping. Only pass data the - template author is allowed to see. - -Changing the Conditional Delimiters ------------------------------------ - -If you have JavaScript code like the following in your templates, the Parser raises a syntax error because there are -strings that can be interpreted as a conditional:: - - - -In that case, you can change the delimiters for conditionals with the ``setConditionalDelimiters()`` method to avoid -misinterpretations: - -.. literalinclude:: view_parser/027.php - -In this case, you will write the code in your template like this:: - - {% if $role=='admin' %} -

    Welcome, Admin

    - {% else %} -

    Welcome, User

    - {% endif %} - -Escaping Data -============= - -Variable substitutions without filters are escaped by default to help prevent XSS attacks on your pages. CodeIgniter's -``esc()`` method supports several contexts, such as ``html``, ``attr``, and ``css``. If no context is specified, the -Parser uses ``html``. You can specify the context with the ``esc`` filter:: - - { user_styles | esc(css) } - { title } - -When a substitution uses one or more filters, the Parser does not add an ``esc`` filter automatically. This also applies -when a context is specified with ``setData()`` or ``setVar()``. Add ``esc`` explicitly when filtering untrusted data. -Filters run from left to right, so its position matters:: - - { title|capitalize|esc } - { body|esc|nl2br } - -In the second example, ``esc`` escapes the input before ``nl2br`` adds HTML ``
    `` tags. Escaping after ``nl2br`` -would display those tags as text. Unknown filter names are ignored, but still prevent automatic escaping; check filter -names carefully. - -To disable automatic escaping for a substitution without filters, add exclamation marks to its delimiters:: - - {! unescaped_var !} - -Filters -======= - -Any single variable substitution can have one or more filters applied to it to modify the way it is presented. These are -not intended to drastically change the output, but to provide ways to reuse the same variable data with different -presentations. The ``esc`` filter discussed above is one example. Dates are another common use case, where you might -need to format the same data differently in several sections on the same page. - -Filters are commands that come after the pseudo-variable name, and are separated by the pipe symbol, ``|``:: - - // -55 is displayed as 55 - { value|abs } - -If the filter takes any arguments, they must be separated by commas and enclosed in parentheses:: - - { created_at|date(Y-m-d) } - -Multiple filters can be applied to the value by piping multiple ones together. They are processed in order, from left to -right:: - - { created_at|date_modify(+5 days)|date(Y-m-d) } - -Provided Filters ----------------- - -The following filters are available when using the parser: - -================ ================= =========================================================== ====================================== -Filter Arguments Description Example -================ ================= =========================================================== ====================================== -abs Displays the absolute value of a number. ``{ v|abs }`` - -capitalize Displays the string in sentence case: all lowercase ``{ v|capitalize }`` - with first letter capitalized. - -date format (Y-m-d) A PHP **date**-compatible formatting string. ``{ v|date(Y-m-d) }`` - -date_modify value to add A **strtotime** compatible string to modify the date, ``{ v|date_modify(+1 day) }`` - / subtract like ``+5 day`` or ``-1 week``. - -default default value Displays the default value if the variable is `empty()`_. ``{ v|default(just in case) }`` - -esc html, attr, Specifies the context to escape the data. ``{ v|esc(attr) }`` - css, js - -excerpt phrase, radius Returns the text within a radius of words from a given ``{ v|excerpt(green giant, 20) }`` - phrase. Same as **excerpt** helper function. - -highlight phrase Highlights a given phrase within the text using ``{ v|highlight(view parser) }`` - ```` tags. - -highlight_code Highlights code samples with HTML/CSS. ``{ v|highlight_code }`` - -limit_chars limit Limits the number of characters to $limit. ``{ v|limit_chars(100) }`` - -limit_words limit Limits the number of words to $limit. ``{ v|limit_words(20) }`` - -local_currency currency, Displays a localized version of a currency. "currency" ``{ v|local_currency(EUR,en_US) }`` - locale, value is any 3-letter ISO 4217 currency code. - fraction - -local_number type, precision, Displays a localized version of a number. "type" can be ``{ v|local_number(decimal,2,en_US) }`` - locale one of: decimal, currency, percent, scientific, spellout, - ordinal, duration. - -lower Converts a string to lowercase. ``{ v|lower }`` - -nl2br Replaces all newline characters (``\n``) with an HTML ``{ v|nl2br }`` - ``
    `` tag. - -number_format places Wraps PHP **number_format** function for use within the ``{ v|number_format(3) }`` - parser. - -prose Takes a body of text and uses the **auto_typography()** ``{ v|prose }`` - method to turn it into prettier, easier-to-read prose. - -round places, type Rounds a number to the specified places. Types of **ceil** ``{ v|round(3) }`` ``{ v|round(ceil) }`` - and **floor** can be passed to use those functions instead. - -strip_tags allowed chars Wraps PHP **strip_tags**. Can accept a string of allowed ``{ v|strip_tags(
    ) }`` - tags. - -title Displays a "title case" version of the string, with all ``{ v|title }`` - lowercase, and each word capitalized. - -upper Displays the string in all uppercase. ``{ v|upper }`` -================ ================= =========================================================== ====================================== - -.. _empty(): https://www.php.net/manual/en/function.empty.php - -See `PHP's NumberFormatter `_ for details relevant to the -"local_number" filter. - -Custom Filters --------------- - -You can easily create your own filters by editing **app/Config/View.php** and adding new entries to the ``$filters`` -array. Each key is the name by which the filter is called in the view, and its value is any valid PHP callable: - -.. literalinclude:: view_parser/012.php - -Closures are also supported. When configuring a closure in **app/Config/View.php**, assign it in the constructor. - -Parser Plugins -============== - -Plugins allow you to extend the parser, adding custom features for each project. They can be any PHP callable, making -them very simple to implement. Within templates, plugins are specified by ``{+ +}`` tags:: - - {+ foo +} inner content {+ /foo +} - -This example shows a plugin named **foo**. It can manipulate any of the content between its opening and closing tags. In -this example, it could work with the text " inner content ". Plugins are processed before any pseudo-variable -replacements happen. - -The output of built-in plugins is treated as rendered data. Parser syntax within that output is not processed by later -plugins or variable substitutions. Custom plugins can still return template code for further processing and must not -introduce untrusted data as Parser syntax. - -While plugins will often consist of tag pairs, as shown above, they can also be a single tag, with no closing tag:: - - {+ foo +} - -Opening tags can also contain parameters that can customize how the plugin works. The parameters are represented as -key/value pairs:: - - {+ foo bar=2 baz="x y" +} - -Parameters can also be single values:: - - {+ include somefile.php +} - -Provided Plugins ----------------- - -The following plugins are available when using the parser: - -================== ========================= ============================================ =================================================================== -Plugin Arguments Description Example -================== ========================= ============================================ =================================================================== -current_url Alias for the current_url helper function. ``{+ current_url +}`` -previous_url Alias for the previous_url helper function. ``{+ previous_url +}`` -siteURL Alias for the site_url helper function. ``{+ siteURL "login" +}`` -mailto email, title, attributes Alias for the mailto helper function. ``{+ mailto email=foo@example.com title="Stranger Things" +}`` -safe_mailto email, title, attributes Alias for the safe_mailto helper function. ``{+ safe_mailto email=foo@example.com title="Stranger Things" +}`` -lang language string Alias for the lang helper function. ``{+ lang number.terabyteAbbr +}`` -validation_errors fieldname(optional) Returns either error string for the field ``{+ validation_errors +} , {+ validation_errors field="email" +}`` - (if specified) or all validation errors. -route route name Alias for the route_to helper function. ``{+ route "login" +}`` -csp_script_nonce Alias for the csp_script_nonce helper ``{+ csp_script_nonce +}`` - function. -csp_style_nonce Alias for the csp_style_nonce helper ``{+ csp_style_nonce +}`` - function. -================== ========================= ============================================ =================================================================== - -Registering a Plugin --------------------- - -At its simplest, all you need to do to register a new plugin and make it ready for use is to add it to -**app/Config/View.php**, under the ``$plugins`` array. The key is the name of the plugin that is used within the -template file. The value is any valid PHP callable, including static class methods: - -.. literalinclude:: view_parser/014.php - -You can also use closures, but these can only be defined in the config file's constructor: - -.. literalinclude:: view_parser/015.php - -If the callable is on its own, it is treated as a single tag, not an open/close one. It will be replaced by the return -value from the plugin: - -.. literalinclude:: view_parser/016.php - -If the callable is wrapped in an array, it is treated as an open/close tag pair that can operate on any of the content -between its tags: - -.. literalinclude:: view_parser/017.php - -*********** -Usage Notes -*********** - -If you include substitution parameters that are not referenced in your template, they are ignored: - -.. literalinclude:: view_parser/018.php - -If you do not include a substitution parameter that is referenced in your template, the original pseudo-variable is -shown in the result: - -.. literalinclude:: view_parser/019.php - -If you provide a string substitution parameter when an array is expected, i.e., for a variable pair, the substitution is -done for the opening variable pair tag, but the closing variable pair tag is not rendered properly: - -.. literalinclude:: view_parser/020.php - -View Fragments -============== - -You do not have to use variable pairs to get the effect of iteration in your views. It is possible to use a view -fragment for what would be inside a variable pair, and to control the iteration in your controller instead of in the -view. - -An example with the iteration controlled in the view:: - - $template = '
      {menuitems} -
    • {title}
    • - {/menuitems}
    '; - - $data = [ - 'menuitems' => [ - ['title' => 'First Link', 'link' => '/first'], - ['title' => 'Second Link', 'link' => '/second'], - ] - ]; - - return $parser->setData($data)->renderString($template); - -Result:: - - - -An example with the iteration controlled in the controller, using a view fragment: - -.. literalinclude:: view_parser/021.php - -Result:: - - - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\View - -.. php:class:: Parser - - .. php:method:: render($view[, $options[, $saveData]]) - - :param string $view: File name of the view source - :param array $options: Array of options, as key/value pairs - :param boolean $saveData: If true, will save data for use with any other calls. If false, will clean the data after rendering the view. - :returns: The rendered text for the chosen view - :rtype: string - - Builds the output based upon a file name and any data that has already been set: - - .. literalinclude:: view_parser/022.php - - Options supported: - - - ``cache`` - the time in seconds to save a view's results - - ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath - - ``cascadeData`` - true if the data pairs in effect when a nested or loop substitution occurs should be - propagated - - ``saveData`` - true if the view data parameter should be retained for subsequent calls - - Any conditional substitutions are performed first, then remaining substitutions are performed for each data - pair. - - .. php:method:: renderString($template[, $options[, $saveData]]) - - :param string $template: Trusted view source provided as a string - :param array $options: Array of options, as key/value pairs - :param boolean $saveData: If true, will save data for use with any other calls. If false, will clean the data after rendering the view. - :returns: The rendered text for the chosen view - :rtype: string - - Builds the output based upon a provided template source and any data that has already been set: - - .. literalinclude:: view_parser/023.php - - Never build the template source from user-provided content. Pass it as data through ``setData()`` instead, or - :ref:`restrict conditionals ` if users are meant to edit the template: - - .. literalinclude:: view_parser/029.php - - Options supported, and behavior, as above. - - .. php:method:: setData([$data[, $context = null]]) - - :param array $data: Array of view data strings, as key/value pairs - :param string $context: The context to use for data escaping. - :returns: The Renderer, for method chaining - :rtype: CodeIgniter\\View\\RendererInterface - - Sets several pieces of view data at once: - - .. literalinclude:: view_parser/024.php - - Supported escape contexts: html, css, js, url, attr or raw. If 'raw', no escaping will happen. - - .. php:method:: setVar($name[, $value = null[, $context = null]]) - - :param string $name: Name of the view data variable - :param mixed $value: The value of this view data - :param string $context: The context to use for data escaping. - :returns: The Renderer, for method chaining - :rtype: CodeIgniter\\View\\RendererInterface - - Sets a single piece of view data: - - .. literalinclude:: view_parser/025.php - - Supported escape contexts: html, css, js, url, attr or raw. If 'raw', no escaping will happen. - - .. php:method:: setDelimiters($leftDelimiter = '{', $rightDelimiter = '}') - - :param string $leftDelimiter: Left delimiter for substitution fields - :param string $rightDelimiter: Right delimiter for substitution fields - :returns: The Renderer, for method chaining - :rtype: CodeIgniter\\View\\RendererInterface - - Override the substitution field delimiters: - - .. literalinclude:: view_parser/026.php - - .. php:method:: setConditionalDelimiters($leftDelimiter = '{', $rightDelimiter = '}') - - :param string $leftDelimiter: Left delimiter for conditionals - :param string $rightDelimiter: Right delimiter for conditionals - :returns: The Renderer, for method chaining - :rtype: CodeIgniter\\View\\RendererInterface - - Override the conditional delimiters: - - .. literalinclude:: view_parser/027.php diff --git a/user_guide_src/source/outgoing/view_parser/001.php b/user_guide_src/source/outgoing/view_parser/001.php deleted file mode 100644 index e9f733df13e4..000000000000 --- a/user_guide_src/source/outgoing/view_parser/001.php +++ /dev/null @@ -1,3 +0,0 @@ - 'My Blog Title', - 'blog_heading' => 'My Blog Heading', -]; - -return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/004.php b/user_guide_src/source/outgoing/view_parser/004.php deleted file mode 100644 index 643f541a5b3e..000000000000 --- a/user_guide_src/source/outgoing/view_parser/004.php +++ /dev/null @@ -1,6 +0,0 @@ -render('blog_template', [ - 'cache' => HOUR, - 'cache_name' => 'something_unique', -]); diff --git a/user_guide_src/source/outgoing/view_parser/005.php b/user_guide_src/source/outgoing/view_parser/005.php deleted file mode 100644 index e85e49db45a2..000000000000 --- a/user_guide_src/source/outgoing/view_parser/005.php +++ /dev/null @@ -1,7 +0,0 @@ -{blog_title}'; -$data = ['blog_title' => 'My ramblings']; - -return $parser->setData($data)->renderString($template); -// Result: My ramblings diff --git a/user_guide_src/source/outgoing/view_parser/006.php b/user_guide_src/source/outgoing/view_parser/006.php deleted file mode 100644 index 40d379aec2ea..000000000000 --- a/user_guide_src/source/outgoing/view_parser/006.php +++ /dev/null @@ -1,15 +0,0 @@ - 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - 'blog_entries' => [ - ['title' => 'Title 1', 'body' => 'Body 1'], - ['title' => 'Title 2', 'body' => 'Body 2'], - ['title' => 'Title 3', 'body' => 'Body 3'], - ['title' => 'Title 4', 'body' => 'Body 4'], - ['title' => 'Title 5', 'body' => 'Body 5'], - ], -]; - -return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/007.php b/user_guide_src/source/outgoing/view_parser/007.php deleted file mode 100644 index 5128ed3cbe4a..000000000000 --- a/user_guide_src/source/outgoing/view_parser/007.php +++ /dev/null @@ -1,11 +0,0 @@ -query('SELECT * FROM blog'); - -$data = [ - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - 'blog_entries' => $query->getResultArray(), -]; - -return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/008.php b/user_guide_src/source/outgoing/view_parser/008.php deleted file mode 100644 index 34fc2d6f0fdb..000000000000 --- a/user_guide_src/source/outgoing/view_parser/008.php +++ /dev/null @@ -1,14 +0,0 @@ - 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - 'blog_entries' => [ - [ - 'title' => 'Title 1', - 'body' => 'Body 1', - ], - ], -]; - -return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/009.php b/user_guide_src/source/outgoing/view_parser/009.php deleted file mode 100644 index bfe83a52b41e..000000000000 --- a/user_guide_src/source/outgoing/view_parser/009.php +++ /dev/null @@ -1,13 +0,0 @@ - 'George', - 'locations' => [ - ['city' => 'Red City', 'planet' => 'Mars'], - ], -]; - -return $parser->setData($data)->renderString($template); -// Result: George lives in Red City on Mars. diff --git a/user_guide_src/source/outgoing/view_parser/010.php b/user_guide_src/source/outgoing/view_parser/010.php deleted file mode 100644 index d0b52c4c300e..000000000000 --- a/user_guide_src/source/outgoing/view_parser/010.php +++ /dev/null @@ -1,18 +0,0 @@ - 'George', - 'locations' => [ - ['city' => 'Red City', 'planet' => 'Mars'], - ], -]; - -return $parser->setData($data)->renderString($template, ['cascadeData' => false]); -// Result: {name} lives in Red City on Mars. - -// or - -return $parser->setData($data)->renderString($template, ['cascadeData' => true]); -// Result: George lives in Red City on Mars. diff --git a/user_guide_src/source/outgoing/view_parser/011.php b/user_guide_src/source/outgoing/view_parser/011.php deleted file mode 100644 index 88e2060b1ed5..000000000000 --- a/user_guide_src/source/outgoing/view_parser/011.php +++ /dev/null @@ -1,3 +0,0 @@ - -

    Welcome, Admin!

    - diff --git a/user_guide_src/source/outgoing/view_parser/012.php b/user_guide_src/source/outgoing/view_parser/012.php deleted file mode 100644 index 696bd2d29c22..000000000000 --- a/user_guide_src/source/outgoing/view_parser/012.php +++ /dev/null @@ -1,15 +0,0 @@ - '\Some\Class::methodName', - 'str_repeat' => 'str_repeat', // native php function - ]; - - // ... -} diff --git a/user_guide_src/source/outgoing/view_parser/013.php b/user_guide_src/source/outgoing/view_parser/013.php deleted file mode 100644 index e5546bdda272..000000000000 --- a/user_guide_src/source/outgoing/view_parser/013.php +++ /dev/null @@ -1,14 +0,0 @@ - '\str_repeat', - ]; - - // ... -} diff --git a/user_guide_src/source/outgoing/view_parser/014.php b/user_guide_src/source/outgoing/view_parser/014.php deleted file mode 100644 index 5153c4ee6757..000000000000 --- a/user_guide_src/source/outgoing/view_parser/014.php +++ /dev/null @@ -1,14 +0,0 @@ - '\Some\Class::methodName', - ]; - - // ... -} diff --git a/user_guide_src/source/outgoing/view_parser/015.php b/user_guide_src/source/outgoing/view_parser/015.php deleted file mode 100644 index c0aa68b3381f..000000000000 --- a/user_guide_src/source/outgoing/view_parser/015.php +++ /dev/null @@ -1,19 +0,0 @@ -plugins['bar'] = static fn (array $params = []) => $params[0] ?? ''; - - parent::__construct(); - } - - // ... -} diff --git a/user_guide_src/source/outgoing/view_parser/016.php b/user_guide_src/source/outgoing/view_parser/016.php deleted file mode 100644 index 5120c1eebf27..000000000000 --- a/user_guide_src/source/outgoing/view_parser/016.php +++ /dev/null @@ -1,19 +0,0 @@ - '\Some\Class::methodName', - ]; - - // ... -} - -/* - * Tag is replaced by the return value of Some\Class::methodName() static function. - * {+ foo +} - */ diff --git a/user_guide_src/source/outgoing/view_parser/017.php b/user_guide_src/source/outgoing/view_parser/017.php deleted file mode 100644 index d9427bde4bf4..000000000000 --- a/user_guide_src/source/outgoing/view_parser/017.php +++ /dev/null @@ -1,16 +0,0 @@ - ['\Some\Class::methodName'], - ]; - - // ... -} - -// {+ foo +} inner content {+ /foo +} diff --git a/user_guide_src/source/outgoing/view_parser/018.php b/user_guide_src/source/outgoing/view_parser/018.php deleted file mode 100644 index 5a88dd651c25..000000000000 --- a/user_guide_src/source/outgoing/view_parser/018.php +++ /dev/null @@ -1,11 +0,0 @@ - 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe', -]; - -return $parser->setData($data)->renderString($template); -// Result: Hello, John Doe diff --git a/user_guide_src/source/outgoing/view_parser/019.php b/user_guide_src/source/outgoing/view_parser/019.php deleted file mode 100644 index 5f465be2296b..000000000000 --- a/user_guide_src/source/outgoing/view_parser/019.php +++ /dev/null @@ -1,11 +0,0 @@ - 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe', -]; - -return $parser->setData($data)->renderString($template); -// Result: Hello, John {initials} Doe diff --git a/user_guide_src/source/outgoing/view_parser/020.php b/user_guide_src/source/outgoing/view_parser/020.php deleted file mode 100644 index fd072cbc0e5c..000000000000 --- a/user_guide_src/source/outgoing/view_parser/020.php +++ /dev/null @@ -1,15 +0,0 @@ - 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe', - 'titles' => [ - ['degree' => 'BSc'], - ['degree' => 'PhD'], - ], -]; - -return $parser->setData($data)->renderString($template); -// Result: Hello, John Doe (Mr{degree} {/degrees}) diff --git a/user_guide_src/source/outgoing/view_parser/021.php b/user_guide_src/source/outgoing/view_parser/021.php deleted file mode 100644 index 60fbb625da79..000000000000 --- a/user_guide_src/source/outgoing/view_parser/021.php +++ /dev/null @@ -1,19 +0,0 @@ -{title}'; -$data1 = [ - ['title' => 'First Link', 'link' => '/first'], - ['title' => 'Second Link', 'link' => '/second'], -]; - -foreach ($data1 as $menuItem) { - $temp .= $parser->setData($menuItem)->renderString($template1); -} - -$template2 = '
      {menuitems}
    '; -$data = [ - 'menuitems' => $temp, -]; - -return $parser->setData($data)->renderString($template2); diff --git a/user_guide_src/source/outgoing/view_parser/022.php b/user_guide_src/source/outgoing/view_parser/022.php deleted file mode 100644 index 1bdb256d92f1..000000000000 --- a/user_guide_src/source/outgoing/view_parser/022.php +++ /dev/null @@ -1,3 +0,0 @@ -render('myview'); diff --git a/user_guide_src/source/outgoing/view_parser/023.php b/user_guide_src/source/outgoing/view_parser/023.php deleted file mode 100644 index 8e65d489f492..000000000000 --- a/user_guide_src/source/outgoing/view_parser/023.php +++ /dev/null @@ -1,3 +0,0 @@ -renderString('
    • Item 1
    • Item 2
    '); diff --git a/user_guide_src/source/outgoing/view_parser/024.php b/user_guide_src/source/outgoing/view_parser/024.php deleted file mode 100644 index 17a0a477e756..000000000000 --- a/user_guide_src/source/outgoing/view_parser/024.php +++ /dev/null @@ -1,3 +0,0 @@ -setData(['name' => 'George', 'position' => 'Boss']); diff --git a/user_guide_src/source/outgoing/view_parser/025.php b/user_guide_src/source/outgoing/view_parser/025.php deleted file mode 100644 index fe67fe17aeb4..000000000000 --- a/user_guide_src/source/outgoing/view_parser/025.php +++ /dev/null @@ -1,3 +0,0 @@ -setVar('name', 'Joe', 'html'); diff --git a/user_guide_src/source/outgoing/view_parser/026.php b/user_guide_src/source/outgoing/view_parser/026.php deleted file mode 100644 index a7efd14837f2..000000000000 --- a/user_guide_src/source/outgoing/view_parser/026.php +++ /dev/null @@ -1,3 +0,0 @@ -setDelimiters('[', ']'); diff --git a/user_guide_src/source/outgoing/view_parser/027.php b/user_guide_src/source/outgoing/view_parser/027.php deleted file mode 100644 index 84730679ced5..000000000000 --- a/user_guide_src/source/outgoing/view_parser/027.php +++ /dev/null @@ -1,3 +0,0 @@ -setConditionalDelimiters('{%', '%}'); diff --git a/user_guide_src/source/outgoing/view_parser/028.php b/user_guide_src/source/outgoing/view_parser/028.php deleted file mode 100644 index 87096cf85d3f..000000000000 --- a/user_guide_src/source/outgoing/view_parser/028.php +++ /dev/null @@ -1,5 +0,0 @@ -setData(['role' => $userData['role']]); - -echo $parser->renderString('{if $role === "admin"}Admin{endif}'); diff --git a/user_guide_src/source/outgoing/view_parser/029.php b/user_guide_src/source/outgoing/view_parser/029.php deleted file mode 100644 index 3b9517040005..000000000000 --- a/user_guide_src/source/outgoing/view_parser/029.php +++ /dev/null @@ -1,7 +0,0 @@ -renderString('Hello ' . $name); - -// Safe: $name is passed as data. -echo $parser->setData(['name' => $name])->renderString('Hello {name}'); diff --git a/user_guide_src/source/outgoing/view_parser/030.php b/user_guide_src/source/outgoing/view_parser/030.php deleted file mode 100644 index b1514c5d8d8d..000000000000 --- a/user_guide_src/source/outgoing/view_parser/030.php +++ /dev/null @@ -1,4 +0,0 @@ -setData(['first_name' => $user->first_name]) - ->renderString($emailTemplate, ['restrictConditionals' => true]); diff --git a/user_guide_src/source/outgoing/view_parser/031.php b/user_guide_src/source/outgoing/view_parser/031.php deleted file mode 100644 index 09b8ee0db52f..000000000000 --- a/user_guide_src/source/outgoing/view_parser/031.php +++ /dev/null @@ -1,14 +0,0 @@ -render('dashboard', ['restrictConditionals' => false]); diff --git a/user_guide_src/source/outgoing/view_renderer.rst b/user_guide_src/source/outgoing/view_renderer.rst deleted file mode 100644 index e8ef917ac9b1..000000000000 --- a/user_guide_src/source/outgoing/view_renderer.rst +++ /dev/null @@ -1,200 +0,0 @@ -############# -View Renderer -############# - -.. contents:: - :local: - :depth: 2 - -*********************** -Using the View Renderer -*********************** - -The :php:func:`view()` function is a convenience function that grabs an instance of the ``renderer`` service, sets the -data, and renders the view. While this is often exactly what you want, you may find times where you want to work with it -more directly. In that case you can access the View service directly: - -.. literalinclude:: view_renderer/001.php - :lines: 2- - -Alternatively, if you are not using the ``View`` class as your default renderer, you can instantiate it directly: - -.. literalinclude:: view_renderer/002.php - :lines: 2- - -.. important:: You should create services only within controllers. If you need access to the View class from a library, - you should set that as a dependency in your library's constructor. - -Then you can use any of the three standard methods that it provides: -:php:meth:`render() `, :php:meth:`setVar() ` and -:php:meth:`setData() `. - -What It Does -============ - -The ``View`` class processes conventional HTML/PHP scripts stored in the application's view path, after extracting view -parameters into PHP variables, accessible inside the scripts. This means that your view parameter names need to be legal -PHP variable names. - -The View class uses an associative array internally to accumulate view parameters until you call its ``render()`` -method. This means that your parameter (or variable) names need to be unique, or a later variable setting will override -an earlier one. - -This also impacts escaping parameter values for different contexts inside your script. You will have to give each -escaped value a unique parameter name. - -No special meaning is attached to parameters whose value is an array. It is up to you to process the array appropriately -in your PHP code. - -Setting View Parameters -======================= - -The :php:meth:`setVar() ` method sets a view parameter. - -.. literalinclude:: view_renderer/008.php - :lines: 2- - -The :php:meth:`setData() ` method sets multiple view parameters at once. - -.. literalinclude:: view_renderer/007.php - :lines: 2- - -Method Chaining -=============== - -The ``setVar()`` and ``setData()`` methods are chainable, allowing you to combine a number of different calls together -in a chain: - -.. literalinclude:: view_renderer/003.php - :lines: 2- - -Escaping Data -============= - -When you pass data to the ``setVar()`` and ``setData()`` functions, you have the option to escape the data to protect -against cross-site scripting attacks. As the last parameter in either method, you can pass the desired context to escape -the data for. See below for context descriptions. - -If you don't want the data to be escaped, you can pass ``null`` or ``'raw'`` as the final parameter to each function: - -.. literalinclude:: view_renderer/004.php - :lines: 2- - -If you choose not to escape data, or you are passing in an object instance, you can manually escape the data within the -view with the :php:func:`esc()` function. The first parameter is the string to escape. The second parameter is the -context to escape the data for (see below):: - - getStat()) ?> - -Escaping Contexts ------------------ - -By default, the ``esc()`` and, in turn, the ``setVar()`` and ``setData()`` functions assume that the data you want to -escape is intended to be used within standard HTML. However, if the data is intended for use in JavaScript, CSS, or in -an href attribute, you would need different escaping rules to be effective. You can pass in the name of the context as -the second parameter. Valid contexts are ``'html'``, ``'js'``, ``'css'``, ``'url'``, and ``'attr'``:: - - Some Link - - - - - -View Renderer Options -===================== - -Several options can be passed to the ``render()`` or ``renderString()`` methods: - -- ``$options`` - - - ``cache`` - the time in seconds to save a view's results; ignored for ``renderString()``. - - ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the ``$viewPath``; ignored for - ``renderString()``. - - ``debug`` - can be set to false to disable the addition of debug code for the - :ref:`Debug Toolbar `. - -- ``$saveData`` - true if the view data parameters should be retained for subsequent calls. - -.. note:: ``$saveData`` as defined by the interface must be a boolean, but implementing classes (like ``View`` below) - may extend this to include ``null`` values. - -*************** -Class Reference -*************** - -.. php:namespace:: CodeIgniter\View - -.. php:class:: View - - .. php:method:: render($view[, $options[, $saveData = false]]) - - :param string $view: File name of the view source - :param array $options: Array of options, as key/value pairs - :param boolean|null $saveData: If true, will save data for use with any other calls. If false, will clean the data after rendering the view. If null, uses the config setting. - :returns: The rendered text for the chosen view - :rtype: string - - Builds the output based upon a file name and any data that has already been set: - - .. literalinclude:: view_renderer/005.php - :lines: 2- - - .. php:method:: renderString($view[, $options[, $saveData = false]]) - - :param string $view: Contents of the view to render, executed as PHP code - :param array $options: Array of options, as key/value pairs - :param boolean|null $saveData: If true, will save data for use with any other calls. If false, will clean the data after rendering the view. If null, uses the config setting. - :returns: The rendered text for the chosen view - :rtype: string - - Builds the output based upon a view fragment and any data that has already been set: - - .. literalinclude:: view_renderer/006.php - :lines: 2- - - .. warning:: ``renderString()`` executes the given view contents as PHP code, just like a view file. Treat them - as trusted code: never pass contents that less-trusted users can edit, even if they are stored in your - database. Escaping or validating such contents does not make them safe to execute. Pass user-provided values - as view data instead. - - .. php:method:: setData([$data[, $context = null]]) - - :param array $data: Array of view data strings, as key/value pairs - :param string $context: The context to use for data escaping. - :returns: The Renderer, for method chaining - :rtype: CodeIgniter\\View\\RendererInterface - - Sets several pieces of view data at once: - - .. literalinclude:: view_renderer/007.php - :lines: 2- - - Supported escape contexts: ``html``, ``css``, ``js``, ``url``, ``attr`` or ``raw``. If ``'raw'``, no escaping - will happen. - - Each call adds to the array of data that the object is accumulating, until the view is rendered. - - .. php:method:: setVar($name[, $value = null[, $context = null]]) - - :param string $name: Name of the view data variable - :param mixed $value: The value of this view data - :param string $context: The context to use for data escaping. - :returns: The Renderer, for method chaining - :rtype: CodeIgniter\\View\\RendererInterface - - Sets a single piece of view data: - - .. literalinclude:: view_renderer/008.php - :lines: 2- - - Supported escape contexts: ``html``, ``css``, ``js``, ``url``, ``attr`` or ``raw``. If ``'raw'``, no escaping - will happen. - - If you use a view data variable that you have previously used for this object, the new value will replace the - existing one. diff --git a/user_guide_src/source/outgoing/view_renderer/001.php b/user_guide_src/source/outgoing/view_renderer/001.php deleted file mode 100644 index 1c594a1a8e26..000000000000 --- a/user_guide_src/source/outgoing/view_renderer/001.php +++ /dev/null @@ -1,3 +0,0 @@ -setVar('one', $one) - ->setVar('two', $two) - ->render('myView'); diff --git a/user_guide_src/source/outgoing/view_renderer/004.php b/user_guide_src/source/outgoing/view_renderer/004.php deleted file mode 100644 index b690f3478c82..000000000000 --- a/user_guide_src/source/outgoing/view_renderer/004.php +++ /dev/null @@ -1,3 +0,0 @@ -setVar('one', $one, 'raw'); diff --git a/user_guide_src/source/outgoing/view_renderer/005.php b/user_guide_src/source/outgoing/view_renderer/005.php deleted file mode 100644 index 9bb35502f352..000000000000 --- a/user_guide_src/source/outgoing/view_renderer/005.php +++ /dev/null @@ -1,3 +0,0 @@ -render('myview'); diff --git a/user_guide_src/source/outgoing/view_renderer/006.php b/user_guide_src/source/outgoing/view_renderer/006.php deleted file mode 100644 index 8f3c21abd99d..000000000000 --- a/user_guide_src/source/outgoing/view_renderer/006.php +++ /dev/null @@ -1,3 +0,0 @@ -renderString('
    My Sharona
    '); diff --git a/user_guide_src/source/outgoing/view_renderer/007.php b/user_guide_src/source/outgoing/view_renderer/007.php deleted file mode 100644 index 99080056b1bc..000000000000 --- a/user_guide_src/source/outgoing/view_renderer/007.php +++ /dev/null @@ -1,3 +0,0 @@ -setData(['name' => 'George', 'position' => 'Boss']); diff --git a/user_guide_src/source/outgoing/view_renderer/008.php b/user_guide_src/source/outgoing/view_renderer/008.php deleted file mode 100644 index f0b868b54bca..000000000000 --- a/user_guide_src/source/outgoing/view_renderer/008.php +++ /dev/null @@ -1,3 +0,0 @@ -setVar('name', 'Joe', 'html'); diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst deleted file mode 100644 index adbf95005a82..000000000000 --- a/user_guide_src/source/outgoing/views.rst +++ /dev/null @@ -1,239 +0,0 @@ -##### -Views -##### - -.. contents:: - :local: - :depth: 2 - -A view is simply a web page, or a page fragment, like a header, footer, sidebar, etc. In fact, views can flexibly be -embedded within other views (within other views, etc.) if you need this type of hierarchy. - -Views are never called directly. They must be loaded by a controller or :ref:`view route `. - -Remember that in an MVC framework, the Controller acts as the traffic cop, so it is responsible for fetching a -particular view. If you have not read the :doc:`Controllers ` page, you should do so before -continuing. - -Using the example controller you created in the controller page, let's add a view to it. - -Creating a View -=============== - -Using your text editor, create a file called **blog_view.php** and put this in it:: - - - - My Blog - - -

    Welcome to my Blog!

    - - - -Then save the file in your **app/Views** directory. - -Displaying a View -================= - -To load and display a particular view file, you will use the :php:func:`view()` function in your controller, as in the -following code: - -.. literalinclude:: views/001.php - :lines: 2- - -Where *name* is the name of your view file. - -.. important:: If the file extension is omitted, then the views are expected to end with the **.php** extension. - -.. note:: The ``view()`` function uses :doc:`view_renderer` internally. - -Now, create a file called **Blog.php** in the **app/Controllers** directory, and put this in it: - -.. literalinclude:: views/002.php - -Open the routing file located at **app/Config/Routes.php**, and look for the "Route Definitions". Add the following -code: - -.. literalinclude:: views/013.php - :lines: 2- - -If you visit your site, you should see your new view. The URL is similar to this:: - - example.com/index.php/blog/ - -Loading Multiple Views -====================== - -CodeIgniter will intelligently handle multiple calls to :php:func:`view()` from within a controller. If more than one -call happens, they will be appended together. - -For example, you may wish to have a header view, a menu view, a content view, and a footer view. That might look -something like this: - -.. literalinclude:: views/003.php - -In the example above, we are using "dynamically added data", which you will see below. - -Storing Views within Sub-directories -==================================== - -Your view files can also be stored within sub-directories if you prefer that type of organization. When doing so, you -will need to include the directory name when loading the view. Example: - -.. literalinclude:: views/004.php - :lines: 2- - -.. _namespaced-views: - -Namespaced Views -================ - -You can store views under a **Views** directory that is namespaced, and load that view as if it were namespaced. While -PHP does not support loading non-class files from a namespace, CodeIgniter provides this feature to make it possible to -package your views together in a module-like fashion for easy re-use or distribution. - -If you have an **example/blog** directory that has a PSR-4 mapping set up in the -:doc:`Autoloader ` living under the namespace ``Example\Blog``, you could retrieve view files as -if they were namespaced also. - -Following this example, you could load the **blog_view.php** file from **example/blog/Views** by prepending the -namespace to the view name (specifying the end directory ``Views`` as in ``Example\Blog\Views\`` is not required): - -.. literalinclude:: views/005.php - -.. note:: You must use backslashes (``\``) when referencing namespaced views, as this is how CodeIgniter distinguishes a - namespaced view from a regular file path. Forward slashes (``/``) are only used for subdirectories within the - standard **app/Views** folder. - -.. _views-overriding-namespaced-views: - -Overriding Namespaced Views -=========================== - -.. versionadded:: 4.7.0 - -You can override a namespaced view by creating a matching directory structure within your application's **app/Views** -directory. This allows you to customize the output of modules or packages without modifying their core source code. - -Configuration -------------- - -By default, overrides are looked for in the **app/Views/overrides** directory. You can configure this location via the -``$appOverridesFolder`` property in **app/Config/View.php**: - -.. code-block:: php - - public string $appOverridesFolder = 'overrides'; - -If you prefer to map namespaces directly to the root of **app/Views** (without a subdirectory), you can set this value -to an empty string (``''``). - -Example -------- - -Assume you have a module named **Blog** with the namespace ``Example\Blog``. The original view file is located at: - -.. code-block:: text - - /modules - └── Example - └── Blog - └── Views - └── blog_view.php - -To override this view (using the default configuration), create a file at the matching path within -**app/Views/overrides**: - -.. code-block:: text - - /app - └── Views - └── overrides <-- Configured $appOverridesFolder - └── Example <-- Matches the first part of namespace - └── Blog <-- Matches the second part of namespace - └── blog_view.php <-- Your custom view - -Now, when you call ``view('Example\Blog\blog_view')``, CodeIgniter will automatically load your custom view from -**app/Views/overrides/Example/Blog/blog_view.php** instead of the original module view file. - -.. note:: The override path must match exactly how you reference the view. If you load a view as - ``view('Example\Blog\blog_view')``, the override path is **app/Views/overrides/Example/Blog/blog_view.php**. - However, if you explicitly include the ``Views`` directory in the call, e.g., - ``view('Example\Blog\Views\blog_view')``, the override path must also include it: - **app/Views/overrides/Example/Blog/Views/blog_view.php**. - -.. _caching-views: - -Caching Views -============= - -You can cache a view with the :php:func:`view()` function by passing a ``cache`` option with the number of seconds to -cache the view for, in the third parameter: - -.. literalinclude:: views/006.php - :lines: 2- - -By default, the view will be cached using the same name as the view file itself. You can customize this by passing along -``cache_name`` and the cache ID you wish to use: - -.. literalinclude:: views/007.php - :lines: 2- - -Adding Dynamic Data to the View -=============================== - -Data is passed from the controller to the view by way of an array in the second parameter of the :php:func:`view()` -function. - -Here's an example: - -.. literalinclude:: views/008.php - :lines: 2- - -Let's try it with your controller file. Open it and add this code: - -.. literalinclude:: views/009.php - -Now open your view file and change the text to variables that correspond to the array keys in your data:: - - - - <?= esc($title) ?> - - -

    - - - -Then load the page at the URL you've been using and you should see the variables replaced. - -The saveData Option -------------------- - -The data passed in is retained for subsequent calls to :php:func:`view()`. If you call the function multiple times in a -single request, you will not have to pass the desired data to each ``view()``. - -However, this might allow data to "bleed" into other views, potentially causing issues. If you would prefer to clean the -data after one call, you can pass the ``saveData`` option into the ``$options`` array in the third parameter. - -.. literalinclude:: views/010.php - :lines: 2- - -Additionally, if you would like the ``view()`` function to clear the data by default between calls, you can set -``$saveData`` to ``false`` in **app/Config/View.php**. - -Creating Loops -============== - -The data array you pass to your view files is not limited to simple variables. You can pass multi-dimensional arrays, -which can be looped to generate multiple rows. For example, if you pull data from your database, it will typically be in -the form of a multi-dimensional array. - -Here's a simple example. Add this to your controller: - -.. literalinclude:: views/011.php - -Now open your view file and create a loop: - -.. literalinclude:: views/012.php diff --git a/user_guide_src/source/outgoing/views/001.php b/user_guide_src/source/outgoing/views/001.php deleted file mode 100644 index c1b1ff23a6dd..000000000000 --- a/user_guide_src/source/outgoing/views/001.php +++ /dev/null @@ -1,3 +0,0 @@ - 'Your title', - ]; - - return view('header') - . view('menu') - . view('content', $data) - . view('footer'); - } -} diff --git a/user_guide_src/source/outgoing/views/004.php b/user_guide_src/source/outgoing/views/004.php deleted file mode 100644 index 7c665c263391..000000000000 --- a/user_guide_src/source/outgoing/views/004.php +++ /dev/null @@ -1,3 +0,0 @@ - 60]); diff --git a/user_guide_src/source/outgoing/views/007.php b/user_guide_src/source/outgoing/views/007.php deleted file mode 100644 index 1b020abbc5a5..000000000000 --- a/user_guide_src/source/outgoing/views/007.php +++ /dev/null @@ -1,4 +0,0 @@ - 60, 'cache_name' => 'my_cached_view']); diff --git a/user_guide_src/source/outgoing/views/008.php b/user_guide_src/source/outgoing/views/008.php deleted file mode 100644 index 8f3218c7029b..000000000000 --- a/user_guide_src/source/outgoing/views/008.php +++ /dev/null @@ -1,9 +0,0 @@ - 'My title', - 'heading' => 'My Heading', - 'message' => 'My Message', -]; - -return view('blog_view', $data); diff --git a/user_guide_src/source/outgoing/views/009.php b/user_guide_src/source/outgoing/views/009.php deleted file mode 100644 index 3cb2e017aad9..000000000000 --- a/user_guide_src/source/outgoing/views/009.php +++ /dev/null @@ -1,14 +0,0 @@ - 'My title', - 'heading' => 'My Heading', - 'message' => 'My Message', -]; - -return view('blog_view', $data, ['saveData' => false]); diff --git a/user_guide_src/source/outgoing/views/011.php b/user_guide_src/source/outgoing/views/011.php deleted file mode 100644 index a74b670c3e49..000000000000 --- a/user_guide_src/source/outgoing/views/011.php +++ /dev/null @@ -1,17 +0,0 @@ - ['Clean House', 'Call Mom', 'Run Errands'], - 'title' => 'My Real Title', - 'heading' => 'My Real Heading', - ]; - - return view('blog_view', $data); - } -} diff --git a/user_guide_src/source/outgoing/views/012.php b/user_guide_src/source/outgoing/views/012.php deleted file mode 100644 index 509b548a1813..000000000000 --- a/user_guide_src/source/outgoing/views/012.php +++ /dev/null @@ -1,19 +0,0 @@ - - - <?= esc($title) ?> - - -

    - -

    My Todo List

    - -
      - - -
    • - - -
    - - - diff --git a/user_guide_src/source/outgoing/views/013.php b/user_guide_src/source/outgoing/views/013.php deleted file mode 100644 index 2868ed564dba..000000000000 --- a/user_guide_src/source/outgoing/views/013.php +++ /dev/null @@ -1,5 +0,0 @@ -get('blog', [Blog::class, 'index']); diff --git a/user_guide_src/source/testing/benchmark.rst b/user_guide_src/source/testing/benchmark.rst deleted file mode 100644 index 3e7ed81d6791..000000000000 --- a/user_guide_src/source/testing/benchmark.rst +++ /dev/null @@ -1,125 +0,0 @@ -############ -Benchmarking -############ - -CodeIgniter provides two separate tools to help you benchmark your code and test different options: the **Timer** and -the **Iterator**. The Timer allows you to easily calculate the time between two points in the execution of your script. -The Iterator allows you to set up several variations and run those tests, recording performance and memory statistics to -help you decide which version is the best. - -The Timer class is always active, being started from the moment the framework is invoked until right before sending the -output to the user, enabling a very accurate timing of the entire system execution. - -.. contents:: - :local: - :depth: 2 - -*************** -Using the Timer -*************** - -With the Timer, you can measure the time between two moments in the execution of your application. This makes it simple -to measure the performance of different aspects of your application. All measurement is done using the ``start()`` and -``stop()`` methods. - -Timer::start() -============== - -The ``start()`` method takes a single parameter: the name of this timer. You can use any string as the name of the -timer. It is only used as a later reference, to know which measurement is which: - -.. literalinclude:: benchmark/001.php - -Timer::stop() -============= - -The ``stop()`` method also takes the name of the timer that you want to stop as its only parameter: - -.. literalinclude:: benchmark/002.php - -The name is not case-sensitive, but otherwise must match the name you gave it when you started the timer. - -timer() -======= - -Alternatively, you can use the :doc:`global function ` ``timer()`` to start and stop timers: - -.. literalinclude:: benchmark/003.php - -.. _benchmark-timer-record: - -Timer::record() -=============== - -.. versionadded:: 4.3.0 - -Since v4.3.0, if you use very small code blocks to benchmark, you can also use the ``record()`` method. It accepts a -no-parameter callable and measures its execution time. The ``start()`` and ``stop()`` methods will be called -automatically around the function call. - -.. literalinclude:: benchmark/010.php - -You can also return the callable's return value for further processing. - -.. literalinclude:: benchmark/011.php - -The same functionality is also available when passing a callable to ``timer()`` as the second parameter. - -.. literalinclude:: benchmark/012.php - -Viewing Your Benchmark Points -============================= - -When your application runs, all of the timers that you have set are collected by the Timer class. It does not -automatically display them, though. You can retrieve all of your timers by calling the ``getTimers()`` method. This -returns an array of benchmark information, including start, end, and duration: - -.. literalinclude:: benchmark/004.php - -You can change the precision of the calculated duration by passing in the number of decimal places you want to be shown -as the only parameter. The default value is 4 digits after the decimal point: - -.. literalinclude:: benchmark/005.php - -The timers are automatically displayed in the :doc:`Debug Toolbar `. - -Displaying Execution Time -========================= - -While the ``getTimers()`` method will give you the raw data for all of the timers in your project, you can retrieve the -duration of a single timer, in seconds, with the ``getElapsedTime()`` method. The first parameter is the name of the -timer to display. The second is the number of decimal places to display. This defaults to 4: - -.. literalinclude:: benchmark/006.php - -****************** -Using the Iterator -****************** - -The Iterator is a simple tool that is designed to allow you to try out multiple variations on a solution to see the -speed differences and different memory usage patterns. You can add any number of "tasks" for it to run and the class -will run the task hundreds or thousands of times to get a clearer picture of performance. The results can then be -retrieved and used by your script, or displayed as an HTML table. - -Creating Tasks To Run -===================== - -Tasks are defined within Closures. Any output the task creates will be discarded automatically. They are added to the -Iterator class through the ``add()`` method. The first parameter is a name you want to refer to this test by. The second -parameter is the Closure itself: - -.. literalinclude:: benchmark/007.php - -Running the Tasks -================= - -Once you've added the tasks to run, you can use the ``run()`` method to loop over the tasks many times. By default, it -will run each task 1000 times. This is probably sufficient for most simple tests. If you need to run the tests more -times than that, you can pass the number as the first parameter: - -.. literalinclude:: benchmark/008.php - -Once it has run, it will return an HTML table with the results of the test. If you don't want the results, you can pass -in ``false`` as the second parameter: - -.. literalinclude:: benchmark/009.php diff --git a/user_guide_src/source/testing/benchmark/001.php b/user_guide_src/source/testing/benchmark/001.php deleted file mode 100644 index 4818bb3cdc26..000000000000 --- a/user_guide_src/source/testing/benchmark/001.php +++ /dev/null @@ -1,4 +0,0 @@ -start('render view'); diff --git a/user_guide_src/source/testing/benchmark/002.php b/user_guide_src/source/testing/benchmark/002.php deleted file mode 100644 index 003d1cc18cf7..000000000000 --- a/user_guide_src/source/testing/benchmark/002.php +++ /dev/null @@ -1,3 +0,0 @@ -stop('render view'); diff --git a/user_guide_src/source/testing/benchmark/003.php b/user_guide_src/source/testing/benchmark/003.php deleted file mode 100644 index 861dbd8232a5..000000000000 --- a/user_guide_src/source/testing/benchmark/003.php +++ /dev/null @@ -1,7 +0,0 @@ -getTimers(); -/* - * Produces: - * [ - * 'render view' => [ - * 'start' => 1234567890, - * 'end' => 1345678920, - * 'duration' => 15.4315, // number of seconds - * ] - * ] - */ diff --git a/user_guide_src/source/testing/benchmark/005.php b/user_guide_src/source/testing/benchmark/005.php deleted file mode 100644 index 309c02f92a9b..000000000000 --- a/user_guide_src/source/testing/benchmark/005.php +++ /dev/null @@ -1,3 +0,0 @@ -getTimers(6); diff --git a/user_guide_src/source/testing/benchmark/006.php b/user_guide_src/source/testing/benchmark/006.php deleted file mode 100644 index a5f93a20fbf9..000000000000 --- a/user_guide_src/source/testing/benchmark/006.php +++ /dev/null @@ -1,4 +0,0 @@ -getElapsedTime('render view'); -// Displays: 0.0234 diff --git a/user_guide_src/source/testing/benchmark/007.php b/user_guide_src/source/testing/benchmark/007.php deleted file mode 100644 index 4997eb1875b0..000000000000 --- a/user_guide_src/source/testing/benchmark/007.php +++ /dev/null @@ -1,7 +0,0 @@ -add('double', static function ($word = 'little') { - "Some basic {$word} string test."; -}); diff --git a/user_guide_src/source/testing/benchmark/008.php b/user_guide_src/source/testing/benchmark/008.php deleted file mode 100644 index 931250447f6c..000000000000 --- a/user_guide_src/source/testing/benchmark/008.php +++ /dev/null @@ -1,4 +0,0 @@ -run(3000); diff --git a/user_guide_src/source/testing/benchmark/009.php b/user_guide_src/source/testing/benchmark/009.php deleted file mode 100644 index 0e966c638e70..000000000000 --- a/user_guide_src/source/testing/benchmark/009.php +++ /dev/null @@ -1,4 +0,0 @@ -run(1000, false); diff --git a/user_guide_src/source/testing/benchmark/010.php b/user_guide_src/source/testing/benchmark/010.php deleted file mode 100644 index e148c83f6fbe..000000000000 --- a/user_guide_src/source/testing/benchmark/010.php +++ /dev/null @@ -1,11 +0,0 @@ -record('slow_function', static function () { slow_function('...'); }); - -/* - * Same as: - * - * $benchmark->start('slow_function'); - * slow_function('...'); - * $benchmark->stop('slow_function'); -*/ diff --git a/user_guide_src/source/testing/benchmark/011.php b/user_guide_src/source/testing/benchmark/011.php deleted file mode 100644 index 239d193a5ca8..000000000000 --- a/user_guide_src/source/testing/benchmark/011.php +++ /dev/null @@ -1,13 +0,0 @@ -record('string length', static fn () => strlen('CI4')); - -/* - * $length = 3 - * - * Same as: - * - * $benchmark->start('string length'); - * $length = strlen('CI4'); - * $benchmark->stop('string length'); -*/ diff --git a/user_guide_src/source/testing/benchmark/012.php b/user_guide_src/source/testing/benchmark/012.php deleted file mode 100644 index ecd25688b556..000000000000 --- a/user_guide_src/source/testing/benchmark/012.php +++ /dev/null @@ -1,13 +0,0 @@ - strlen('CI4')); - -/* - * $length = 3 - * - * Same as: - * - * timer('string length'); - * $length = strlen('CI4'); - * timer('string length'); -*/ diff --git a/user_guide_src/source/testing/cli.rst b/user_guide_src/source/testing/cli.rst deleted file mode 100644 index 4e0ea9fb6f3f..000000000000 --- a/user_guide_src/source/testing/cli.rst +++ /dev/null @@ -1,149 +0,0 @@ -#################### -Testing CLI Commands -#################### - -.. contents:: - :local: - :depth: 3 - -.. _using-mock-input-output: - -********************* -Using MockInputOutput -********************* - -.. versionadded:: 4.5.0 - -MockInputOutput -=============== - -**MockInputOutput** provides an easy way to write tests for commands that require user input, such as ``CLI::prompt()``, -``CLI::wait()``, and ``CLI::input()``. - -You can replace the ``InputOutput`` class with ``MockInputOutput`` during test execution to capture inputs and outputs. - -.. note:: When you use ``MockInputOutput``, you don't need to use :ref:`stream-filter-trait`, - :ref:`ci-test-stream-filter`, and :ref:`php-stream-wrapper`. - -Helper Methods --------------- - -getOutput(?int $index = null): string -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Gets the output. - -- If you call it like ``$io->getOutput()``, it returns the whole output string. -- If you specify ``0`` or a positive number, it returns the output array item. Each item has the output of a - ``CLI::fwrite()`` call. -- If you specify a negative number ``-n``, it returns the last ``n``-th item of the output array. - -getOutputs(): array -^^^^^^^^^^^^^^^^^^^ - -Returns the output array. Each item has the output of a ``CLI::fwrite()`` call. - -How to Use -========== - -- ``CLI::setInputOutput()`` can set the ``MockInputOutput`` instance to the ``CLI`` class. -- ``CLI::resetInputOutput()`` resets the ``InputOutput`` instance in the ``CLI`` class. -- ``MockInputOutput::setInputs()`` sets the user input array. -- ``MockInputOutput::getOutput()`` gets the command output. - -The following code tests the command ``spark db:table``: - -.. literalinclude:: cli/001.php - -*********************** -Without MockInputOutput -*********************** - -.. _testing-cli-output: - -Testing CLI Output -================== - -.. _stream-filter-trait: - -StreamFilterTrait ------------------ - -.. versionadded:: 4.3.0 - -**StreamFilterTrait** provides an alternative to ``MockInputOutput`` for capturing CLI output. - -You may need to test things that are difficult to test. Sometimes, capturing a stream, like PHP's own STDOUT or STDERR, -might be helpful. The ``StreamFilterTrait`` helps you capture the output from the stream of your choice. - -How to Use -^^^^^^^^^^ - -- ``StreamFilterTrait::getStreamFilterBuffer()`` gets the captured data from the buffer. -- ``StreamFilterTrait::resetStreamFilterBuffer()`` resets captured data. - -An example demonstrating this inside one of your test cases: - -.. literalinclude:: overview/018.php - -The ``StreamFilterTrait`` has a configurator that is called automatically. See -:ref:`Testing Traits `. - -If you override the ``setUp()`` or ``tearDown()`` methods in your test, then you must call the ``parent::setUp()`` and -``parent::tearDown()`` methods respectively to configure the ``StreamFilterTrait``. - -.. _ci-test-stream-filter: - -CITestStreamFilter ------------------- - -**CITestStreamFilter** is for manual/single use. - -If you need to capture streams in only one test, then instead of using the StreamFilterTrait trait, you can manually add -a filter to streams. - -How to Use -^^^^^^^^^^ - -- ``CITestStreamFilter::registration()`` Filter registration. -- ``CITestStreamFilter::addOutputFilter()`` Adding a filter to the output stream. -- ``CITestStreamFilter::addErrorFilter()`` Adding a filter to the error stream. -- ``CITestStreamFilter::removeOutputFilter()`` Removing a filter from the output stream. -- ``CITestStreamFilter::removeErrorFilter()`` Removing a filter from the error stream. - -.. literalinclude:: overview/020.php - -.. _testing-cli-input: - -Testing CLI Input -================= - -.. _php-stream-wrapper: - -PhpStreamWrapper ----------------- - -.. versionadded:: 4.3.0 - -**PhpStreamWrapper** provides a way to write tests for methods that require user input, such as ``CLI::prompt()``, -``CLI::wait()``, and ``CLI::input()``. - -.. note:: The PhpStreamWrapper is a stream wrapper class. If you don't know PHP's stream wrapper, see - `The streamWrapper class `_ in the PHP manual. - -How to Use -^^^^^^^^^^ - -- ``PhpStreamWrapper::register()`` Register the ``PhpStreamWrapper`` to the ``php`` protocol. -- ``PhpStreamWrapper::restore()`` Restore the php protocol wrapper back to the PHP built-in wrapper. -- ``PhpStreamWrapper::setContent()`` Set the input data. - -.. important:: The PhpStreamWrapper is intended only for testing ``php://stdin``. But when you register it, it handles - all the `php protocol `_ streams, such as ``php://stdout``, - ``php://stderr``, ``php://memory``. So it is strongly recommended that ``PhpStreamWrapper`` be - registered/unregistered only when needed. Otherwise, it will interfere with other built-in php streams while - registered. - -An example demonstrating this inside one of your test cases: - -.. literalinclude:: overview/019.php diff --git a/user_guide_src/source/testing/cli/001.php b/user_guide_src/source/testing/cli/001.php deleted file mode 100644 index c01212049b8c..000000000000 --- a/user_guide_src/source/testing/cli/001.php +++ /dev/null @@ -1,37 +0,0 @@ -setInputs(['a', '0']); - - command('db:table'); - - // Get the whole output string. - $output = $io->getOutput(); - - $expected = 'Which table do you want to see? [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]: a'; - $this->assertStringContainsString($expected, $output); - - $expected = 'Data of Table "db_migrations":'; - $this->assertStringContainsString($expected, $output); - - // Remove MockInputOutput. - CLI::resetInputOutput(); - } -} diff --git a/user_guide_src/source/testing/controllers.rst b/user_guide_src/source/testing/controllers.rst deleted file mode 100644 index 1422e506a5f2..000000000000 --- a/user_guide_src/source/testing/controllers.rst +++ /dev/null @@ -1,228 +0,0 @@ -################### -Testing Controllers -################### - -Testing your controllers is made convenient with a couple of new helper classes and traits. When testing controllers, -you can execute the code within a controller, without first running through the entire application bootstrap process. -Often, using the :doc:`Feature Testing tools ` will be simpler, but this functionality is here in case you need -it. - -.. note:: Because the entire framework has not been bootstrapped, there will be times when you cannot test a controller - this way. - -.. contents:: - :local: - :depth: 2 - -The Helper Trait -================ - -To enable Controller Testing, you need to use the ``ControllerTestTrait`` trait within your tests: - -.. literalinclude:: controllers/001.php - -Once the trait has been included, you can start setting up the environment, including the request and response classes, -the request body, URI, and more. You specify the controller to use with the ``controller()`` method, passing in the -fully qualified class name of your controller. Finally, call the ``execute()`` method with the name of the method to run -as the parameter: - -.. literalinclude:: controllers/002.php - -Helper Methods -============== - -controller($class) ------------------- - -Specifies the class name of the controller to test. The first parameter must be a fully qualified class name (i.e., -include the namespace): - -.. literalinclude:: controllers/003.php - -execute(string $method, ...$params) ------------------------------------ - -Executes the specified method within the controller. The first parameter is the name of the method to run: - -.. literalinclude:: controllers/004.php - -By specifying the second and subsequent parameters, you can pass them to the controller method. - -This returns a new helper class that provides a number of routines for checking the response itself. See below for -details. - -withConfig($config) -------------------- - -Allows you to pass in a modified version of **app/Config/App.php** to test with different settings: - -.. literalinclude:: controllers/005.php - -If you do not provide one, the application's App config file will be used. - -withRequest($request) ---------------------- - -Allows you to provide an **IncomingRequest** instance tailored to your testing needs: - -.. literalinclude:: controllers/006.php - -If you do not provide one, a new IncomingRequest instance with the default application values will be passed into your -controller. - -withResponse($response) ------------------------ - -Allows you to provide a **Response** instance: - -.. literalinclude:: controllers/007.php - -If you do not provide one, a new Response instance with the default application values will be passed into your -controller. - -withLogger($logger) -------------------- - -Allows you to provide a **Logger** instance: - -.. literalinclude:: controllers/008.php - -If you do not provide one, a new Logger instance with the default configuration values will be passed into your -controller. - -withUri(string $uri) --------------------- - -Allows you to provide a new URI that simulates the URL the client was visiting when this controller was run. This is -helpful if you need to check URI segments within your controller. The only parameter is a string representing a valid -URI: - -.. literalinclude:: controllers/009.php - -It is a good practice to always provide the URI during testing to avoid surprises. - -.. note:: Since v4.4.0, this method creates a new Request instance with the URI, because the Request instance should - have the URI instance. Also, if the hostname in the URI string is invalid with ``Config\App``, the valid hostname - will be set. - -withBody($body) ---------------- - -Allows you to provide a custom body for the request. This can be helpful when testing API controllers where you need to -set a JSON value as the body. The only parameter is a string that represents the body of the request: - -.. literalinclude:: controllers/010.php - -Checking the Response -===================== - -``ControllerTestTrait::execute()`` returns an instance of a ``TestResponse``. See :doc:`Testing Responses ` on -how to use this class to perform additional assertions and verification in your test cases. - -Filter Testing -============== - -Similar to Controller Testing, the framework provides tools to help with creating tests for custom -:doc:`Filters ` and your project's use of them in routing. - -The Helper Trait ----------------- - -Just like with the Controller Tester, you need to include the ``FilterTestTrait`` in your test cases to enable these -features: - -.. literalinclude:: controllers/011.php - -Configuration -------------- - -Because of the logical overlap with Controller Testing, ``FilterTestTrait`` is designed to work together with -``ControllerTestTrait`` should you need both on the same class. Once the trait has been included, ``CIUnitTestCase`` -will detect its ``setUp`` method and prepare all the components needed for your tests. Should you need a special -configuration, you can alter any of the properties before calling the support methods: - -* ``$request`` A prepared version of the default ``IncomingRequest`` service -* ``$response`` A prepared version of the default ``ResponseInterface`` service -* ``$filtersConfig`` The default ``Config\Filters`` configuration (note: discovery is handled by ``Filters`` so this - will not include module aliases) -* ``$filters`` An instance of ``CodeIgniter\Filters\Filters`` using the three components above -* ``$collection`` A prepared version of ``RouteCollection`` which includes the discovery of ``Config\Routes`` - -The default configuration will usually be best for your testing since it most closely emulates a "live" project, but -(for example) if you wanted to simulate a filter triggering accidentally on an unfiltered route, you could add it to the -Config: - -.. literalinclude:: controllers/012.php - -Checking Routes ---------------- - -The first helper method is ``getFiltersForRoute()``, which will simulate the provided route and return a list of all -Filters (by their alias) that would have run for the given position ("before" or "after"), without actually executing -any controller or routing code. This has a large performance advantage over Controller and HTTP Testing. - -.. php:function:: getFiltersForRoute($route, $position) - - :param string $route: The URI to check - :param string $position: The filter method to check, "before" or "after" - :returns: Aliases for each filter that would have run - :rtype: string[] - - Usage example: - - .. literalinclude:: controllers/013.php - -Calling Filter Methods ----------------------- - -The properties described in Configuration are all set up to ensure maximum performance without interference from other -tests. The next helper method will return a callable method using these properties to test your Filter code safely and -check the results. - -.. php:function:: getFilterCaller($filter, $position) - - :param FilterInterface|string $filter: The filter instance, class, or alias - :param string $position: The filter method to run, "before" or "after" - :returns: A callable method to run the simulated Filter event - :rtype: Closure - - Usage example: - - .. literalinclude:: controllers/014.php - - Notice how the ``Closure`` can take input parameters which are passed to your filter method. - -Assertions ----------- - -In addition to the helper methods above, ``FilterTestTrait`` also comes with some assertions to streamline your test -methods. - -assertFilter() -^^^^^^^^^^^^^^ - -The ``assertFilter()`` method checks that the given route at the given position uses the filter (by its alias): - -.. literalinclude:: controllers/015.php - -assertNotFilter() -^^^^^^^^^^^^^^^^^ - -The ``assertNotFilter()`` method checks that the given route at the given position does not use the filter (by its -alias): - -.. literalinclude:: controllers/016.php - -assertHasFilters() -^^^^^^^^^^^^^^^^^^ - -The ``assertHasFilters()`` method checks that the given route at the given position has at least one filter set: - -.. literalinclude:: controllers/017.php - -assertNotHasFilters() -^^^^^^^^^^^^^^^^^^^^^ - -The ``assertNotHasFilters()`` method checks that the given route at the given position has no filters set: - -.. literalinclude:: controllers/018.php diff --git a/user_guide_src/source/testing/controllers/001.php b/user_guide_src/source/testing/controllers/001.php deleted file mode 100644 index ae51187f949d..000000000000 --- a/user_guide_src/source/testing/controllers/001.php +++ /dev/null @@ -1,13 +0,0 @@ -withUri('http://example.com/categories') - ->controller(ForumController::class) - ->execute('showCategories'); - - $this->assertTrue($result->isOK()); - } -} diff --git a/user_guide_src/source/testing/controllers/003.php b/user_guide_src/source/testing/controllers/003.php deleted file mode 100644 index 51e810538e87..000000000000 --- a/user_guide_src/source/testing/controllers/003.php +++ /dev/null @@ -1,3 +0,0 @@ -controller(\App\Controllers\ForumController::class); diff --git a/user_guide_src/source/testing/controllers/004.php b/user_guide_src/source/testing/controllers/004.php deleted file mode 100644 index 17b5f42590ce..000000000000 --- a/user_guide_src/source/testing/controllers/004.php +++ /dev/null @@ -1,4 +0,0 @@ -controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/005.php b/user_guide_src/source/testing/controllers/005.php deleted file mode 100644 index 11717bc79e7a..000000000000 --- a/user_guide_src/source/testing/controllers/005.php +++ /dev/null @@ -1,8 +0,0 @@ -appTimezone = 'America/Chicago'; - -$results = $this->withConfig($config) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/006.php b/user_guide_src/source/testing/controllers/006.php deleted file mode 100644 index 17d532269e78..000000000000 --- a/user_guide_src/source/testing/controllers/006.php +++ /dev/null @@ -1,14 +0,0 @@ -setLocale($locale); - -$results = $this->withRequest($request) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/007.php b/user_guide_src/source/testing/controllers/007.php deleted file mode 100644 index 8f7d55448035..000000000000 --- a/user_guide_src/source/testing/controllers/007.php +++ /dev/null @@ -1,7 +0,0 @@ -withResponse($response) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/008.php b/user_guide_src/source/testing/controllers/008.php deleted file mode 100644 index 641a7f92f68b..000000000000 --- a/user_guide_src/source/testing/controllers/008.php +++ /dev/null @@ -1,8 +0,0 @@ -withResponse($response) - ->withLogger($logger) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/009.php b/user_guide_src/source/testing/controllers/009.php deleted file mode 100644 index 710402481076..000000000000 --- a/user_guide_src/source/testing/controllers/009.php +++ /dev/null @@ -1,5 +0,0 @@ -withUri('http://example.com/forums/categories') - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/010.php b/user_guide_src/source/testing/controllers/010.php deleted file mode 100644 index e257dcbc4928..000000000000 --- a/user_guide_src/source/testing/controllers/010.php +++ /dev/null @@ -1,7 +0,0 @@ - 'bar']); - -$results = $this->withBody($body) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/011.php b/user_guide_src/source/testing/controllers/011.php deleted file mode 100644 index e53aa42c8768..000000000000 --- a/user_guide_src/source/testing/controllers/011.php +++ /dev/null @@ -1,11 +0,0 @@ -filtersConfig->globals['before'] = ['admin-only-filter']; - - $this->assertHasFilters('unfiltered/route', 'before'); - } - - // ... -} diff --git a/user_guide_src/source/testing/controllers/013.php b/user_guide_src/source/testing/controllers/013.php deleted file mode 100644 index e205f0f4ea54..000000000000 --- a/user_guide_src/source/testing/controllers/013.php +++ /dev/null @@ -1,3 +0,0 @@ -getFiltersForRoute('/', 'after'); // ['toolbar'] diff --git a/user_guide_src/source/testing/controllers/014.php b/user_guide_src/source/testing/controllers/014.php deleted file mode 100644 index abbce05cac1e..000000000000 --- a/user_guide_src/source/testing/controllers/014.php +++ /dev/null @@ -1,19 +0,0 @@ -getFilterCaller('permission', 'before'); - $result = $caller('MayEditWidgets'); - - $this->assertInstanceOf('CodeIgniter\HTTP\RedirectResponse', $result); - } -} diff --git a/user_guide_src/source/testing/controllers/015.php b/user_guide_src/source/testing/controllers/015.php deleted file mode 100644 index 866d2e80ce43..000000000000 --- a/user_guide_src/source/testing/controllers/015.php +++ /dev/null @@ -1,4 +0,0 @@ -assertFilter('users/account', 'before', 'login'); diff --git a/user_guide_src/source/testing/controllers/016.php b/user_guide_src/source/testing/controllers/016.php deleted file mode 100644 index cdbf08ccc36b..000000000000 --- a/user_guide_src/source/testing/controllers/016.php +++ /dev/null @@ -1,4 +0,0 @@ -assertNotFilter('api/v1/widgets', 'after', 'toolbar'); diff --git a/user_guide_src/source/testing/controllers/017.php b/user_guide_src/source/testing/controllers/017.php deleted file mode 100644 index 15db694e5419..000000000000 --- a/user_guide_src/source/testing/controllers/017.php +++ /dev/null @@ -1,4 +0,0 @@ -assertHasFilters('filtered/route', 'after'); diff --git a/user_guide_src/source/testing/controllers/018.php b/user_guide_src/source/testing/controllers/018.php deleted file mode 100644 index 33606c0e122e..000000000000 --- a/user_guide_src/source/testing/controllers/018.php +++ /dev/null @@ -1,4 +0,0 @@ -assertNotHasFilters('about/contact', 'before'); diff --git a/user_guide_src/source/testing/database.rst b/user_guide_src/source/testing/database.rst deleted file mode 100644 index a451f77c8735..000000000000 --- a/user_guide_src/source/testing/database.rst +++ /dev/null @@ -1,170 +0,0 @@ -##################### -Testing Your Database -##################### - -.. contents:: - :local: - :depth: 2 - -The Test Class -************** - -In order to take advantage of the built-in database tools that CodeIgniter provides for testing, your tests must extend -``CIUnitTestCase`` and use the ``DatabaseTestTrait``: - -.. literalinclude:: database/001.php - -Because special functionality is executed during the ``setUp()`` and ``tearDown()`` phases, you must ensure that you -call the parent's methods if you need to use those methods. Otherwise, you will lose much of the functionality described -here: - -.. literalinclude:: database/002.php - -Setting Up a Test Database -************************** - -When running database tests, you need to provide a database that can be used during testing. Instead of using the -PHPUnit built-in database features, the framework provides tools specific to CodeIgniter. The first step is to ensure -that you have set up a ``tests`` database group in **app/Config/Database.php**. This specifies a database connection -that is only used while running tests, to keep your other data safe. - -If you have multiple developers on your team, you will likely want to keep your credentials stored in the **.env** file. -To do so, edit the file to ensure the following lines are present and have the correct information:: - - database.tests.hostname = localhost - database.tests.database = ci4_test - database.tests.username = root - database.tests.password = root - database.tests.DBDriver = MySQLi - database.tests.DBPrefix = - database.tests.port = 3306 - -Migrations and Seeds -==================== - -When running tests, you need to ensure that your database has the correct schema set up and that it is in a known state -for every test. You can use migrations and seeds to set up your database, by adding a couple of class properties to your -test. - -.. literalinclude:: database/003.php - -Migrations ----------- - -$migrate -^^^^^^^^ - -This boolean value determines whether the database migration runs before a test. By default, the database is always -migrated to the latest available state as defined by ``$namespace``. If ``false``, migration never runs. If you want to -disable migration, set it to ``false``. - -$migrateOnce -^^^^^^^^^^^^ - -This boolean value determines whether the database migration runs only once. If you want to run migration once before -the first test, set it to ``true``. If not present or ``false``, migration runs before each test. - -$refresh -^^^^^^^^ - -This boolean value determines whether the database is completely refreshed before a test. If ``true``, all migrations -are rolled back to version 0. - -$namespace -^^^^^^^^^^ - -By default, CodeIgniter will look in **tests/_support/Database/Migrations** to locate the migrations that it should run -during testing. You can change this location by specifying a new namespace in the ``$namespace`` property. This should -not include the **Database\\Migrations** sub-namespace but just the base namespace. - -.. important:: If you set this property to ``null``, it runs migrations from all available namespaces like - ``php spark migrate --all``. - -Seeds ------ - -$seed -^^^^^ - -If present and not empty, this specifies the name of a Seed file that is used to populate the database with test data -before the test runs. - -$seedOnce -^^^^^^^^^ - -This boolean value determines whether the database seeding runs only once. If you want to run database seeding once -before the first test, set it to ``true``. If not present or ``false``, database seeding runs before each test. - -$basePath -^^^^^^^^^ - -By default, CodeIgniter will look in **tests/_support/Database/Seeds** to locate the seeds that it should run during -testing. You can change this directory by specifying the ``$basePath`` property. This should not include the **Seeds** -directory, but the path to the single directory that holds the sub-directory. - -Helper Methods -************** - -The **DatabaseTestTrait** class provides several helper methods to aid in testing your database. - -Changing Database State -======================= - -regressDatabase() ------------------ - -Called during ``$refresh`` described above, this method is available if you need to reset the database manually. - -migrateDatabase() ------------------ - -Called during ``setUp()``, this method is available if you need to run migrations manually. - -seed($name) ------------ - -Allows you to manually load a Seed into the database. The only parameter is the name of the seed to run. The seed must -be present within the path specified in ``$basePath``. - -hasInDatabase($table, $data) ----------------------------- - -Inserts a new row into the database. This row is removed after the current test runs. ``$data`` is an associative array -with the data to insert into the table. - -.. literalinclude:: database/007.php - -Getting Data from Database -========================== - -grabFromDatabase($table, $column, $criteria) --------------------------------------------- - -Returns the value of ``$column`` from the specified table where the row matches ``$criteria``. If more than one row is -found, it will only return the first one. - -.. literalinclude:: database/006.php - -Assertions -========== - -dontSeeInDatabase($table, $criteria) ------------------------------------- - -Asserts that a row with criteria matching the key/value pairs in ``$criteria`` DOES NOT exist in the database. - -.. literalinclude:: database/004.php - -seeInDatabase($table, $criteria) --------------------------------- - -Asserts that a row with criteria matching the key/value pairs in ``$criteria`` DOES exist in the database. - -.. literalinclude:: database/005.php - -seeNumRecords($expected, $table, $criteria) -------------------------------------------- - -Asserts that the number of rows in the database matching ``$criteria`` equals ``$expected``. - -.. literalinclude:: database/008.php diff --git a/user_guide_src/source/testing/database/001.php b/user_guide_src/source/testing/database/001.php deleted file mode 100644 index 809cd59d8c0f..000000000000 --- a/user_guide_src/source/testing/database/001.php +++ /dev/null @@ -1,13 +0,0 @@ - 'joe@example.com', - 'active' => 1, -]; -$this->dontSeeInDatabase('users', $criteria); diff --git a/user_guide_src/source/testing/database/005.php b/user_guide_src/source/testing/database/005.php deleted file mode 100644 index 960ba5e5b91e..000000000000 --- a/user_guide_src/source/testing/database/005.php +++ /dev/null @@ -1,7 +0,0 @@ - 'joe@example.com', - 'active' => 1, -]; -$this->seeInDatabase('users', $criteria); diff --git a/user_guide_src/source/testing/database/006.php b/user_guide_src/source/testing/database/006.php deleted file mode 100644 index 951736b95611..000000000000 --- a/user_guide_src/source/testing/database/006.php +++ /dev/null @@ -1,3 +0,0 @@ -grabFromDatabase('users', 'username', ['email' => 'joe@example.com']); diff --git a/user_guide_src/source/testing/database/007.php b/user_guide_src/source/testing/database/007.php deleted file mode 100644 index 46ebb8fbe695..000000000000 --- a/user_guide_src/source/testing/database/007.php +++ /dev/null @@ -1,7 +0,0 @@ - 'joe@example.com', - 'name' => 'Joe Cool', -]; -$this->hasInDatabase('users', $data); diff --git a/user_guide_src/source/testing/database/008.php b/user_guide_src/source/testing/database/008.php deleted file mode 100644 index 9a60e154d331..000000000000 --- a/user_guide_src/source/testing/database/008.php +++ /dev/null @@ -1,6 +0,0 @@ - 1, -]; -$this->seeNumRecords(2, 'users', $criteria); diff --git a/user_guide_src/source/testing/debugging.rst b/user_guide_src/source/testing/debugging.rst deleted file mode 100644 index a269f40da153..000000000000 --- a/user_guide_src/source/testing/debugging.rst +++ /dev/null @@ -1,227 +0,0 @@ -########################## -Debugging Your Application -########################## - -.. contents:: - :local: - :depth: 2 - -************* -Checking Logs -************* - -.. _codeigniter-error-logs: - -CodeIgniter Error Logs -====================== - -CodeIgniter logs error messages, according to the settings in **app/Config/Logger.php**. - -The default configuration has daily log files stored in **writable/logs**. It would be a good idea to check them if -things aren't working the way you expect! - -You can adjust the error threshold to see more or fewer messages. See :ref:`Logging ` for -details. - -Logging All SQL Queries -======================= - -All SQL queries issued by CodeIgniter can be logged. See :ref:`Database Events ` for details. - -******************** -Replacing var_dump() -******************** - -While using Xdebug and a good IDE can be indispensable to debug your application, sometimes a quick ``var_dump()`` is -all you need. CodeIgniter makes that even better by bundling in the excellent `Kint `_ -debugging tool for PHP. - -This goes way beyond your usual tool, providing many alternate pieces of data, like formatting timestamps into -recognizable dates, showing you hexcodes as colors, displaying array data as a table for easy reading, and much, much -more. - -Enabling Kint -============= - -By default, Kint is enabled in **development** and **testing** :doc:`environments ` only. It will -be enabled whenever the constant ``CI_DEBUG`` is defined and its value is truthy. This is defined in the boot files -(e.g. **app/Config/Boot/development.php**). - -Using Kint -========== - -d() ---- - -The ``d()`` method dumps to the screen all of the data it knows about the contents passed as its only parameter, and -allows the script to continue executing: - -.. literalinclude:: debugging/001.php - :lines: 2- - -dd() ----- - -This method is identical to ``d()``, except that it also calls ``die()``, so no further code is executed during this -request. - -trace() -------- - -This provides a backtrace to the current execution point, with Kint's own unique spin: - -.. literalinclude:: debugging/002.php - :lines: 2- - -For more information, see `Kint's page `_. - -.. _the-debug-toolbar: - -***************** -The Debug Toolbar -***************** - -The Debug Toolbar provides at-a-glance information about the current page request, including benchmark results, queries -you have run, request and response data, and more. This can all prove very useful during development to help you debug -and optimize. - -.. note:: The Debug Toolbar is still under construction with several planned features not yet implemented. - -Enabling the Toolbar -==================== - -The toolbar is enabled by default in any :doc:`environment ` *except* **production**. It will be -shown whenever the constant ``CI_DEBUG`` is defined and its value is truthy. This is defined in the boot files (e.g. -**app/Config/Boot/development.php**) and can be modified there to determine the environments in which it is shown. - -.. note:: The Debug Toolbar is not displayed when your ``baseURL`` setting (in **app/Config/App.php** or ``app.baseURL`` - in **.env**) does not match your actual URL. - -The toolbar itself is displayed as an :doc:`After Filter `. You can stop it from ever running by -removing ``'toolbar'`` from the ``$required`` (or ``$globals``) property of **app/Config/Filters.php**. - -.. note:: Prior to v4.5.0, the toolbar was set to ``$globals`` by default. - -Choosing What to Show ---------------------- - -CodeIgniter ships with several Collectors that, as the name implies, collect data to display on the toolbar. You can -easily make your own to customize the toolbar. To determine which collectors are shown, again head over to the -**app/Config/Toolbar.php** configuration file: - -.. literalinclude:: debugging/003.php - -Comment out any collectors that you do not want to show. Add custom Collectors here by providing the fully qualified -class name. The exact collectors that appear here will affect which tabs are shown, as well as what information is shown -on the Timeline. - -.. note:: Some tabs, like Database and Logs, will only display when they have content to show. Otherwise, they are - removed to help out on smaller displays. - -The Collectors that ship with CodeIgniter are: - -* **Timers** collects all of the benchmark data, both from the system and from your application. -* **Database** displays a list of queries that all database connections have performed, and their execution time. -* **Logs** displays any information that was logged. In long-running systems, or systems with many items being logged, - this can cause memory issues and should be disabled. -* **Views** displays render time for views on the timeline, and shows any data passed to the views on a separate tab. -* **Cache** displays information about cache hits and misses, and execution times. -* **Files** displays a list of all files that have been loaded during this request. -* **Routes** displays information about the current route and all routes defined in the system. -* **Events** displays a list of all events that have been loaded during this request. - -Setting Benchmark Points -======================== - -Use the Timer library to record benchmark data for display in the Debug Toolbar's timeline. - -Please read the information on setting Benchmark points in the :doc:`Benchmark Library ` page. - -Creating Custom Collectors -========================== - -Creating custom collectors is a straightforward task. You create a new class that extends -``CodeIgniter\Debug\Toolbar\Collectors\BaseCollector``, fully namespaced so that the autoloader can locate it. This -provides a number of methods that you can override, and has four required class properties that you must correctly set -depending on how you want the Collector to work: - -.. literalinclude:: debugging/004.php - -**$hasTimeline** should be set to ``true`` for any Collector that wants to display information in the toolbar's -timeline. If this is true, you will need to implement the ``formatTimelineData()`` method to format and return the data -for display. - -**$hasTabContent** should be ``true`` if the Collector wants to display its own tab with custom content. If this is -true, you will need to provide a ``$title``, implement the ``display()`` method to render the tab's contents, and might -need to implement the ``getTitleDetails()`` method if you want to display additional information just to the right of -the tab content's title. - -**$hasVarData** should be ``true`` if this Collector wants to add additional data to the ``Vars`` tab. If this is true, -you will need to implement the ``getVarData()`` method. - -**$title** is displayed on open tabs. - -Displaying a Toolbar Tab ------------------------- - -To display a toolbar tab, you must: - -1. Fill in ``$title`` with the text displayed as both the toolbar title and the tab header. -2. Set ``$hasTabContent`` to ``true``. -3. Implement the ``display()`` method. -4. Optionally, implement the ``getTitleDetails()`` method. - -The ``display()`` method creates the HTML that is displayed within the tab itself. It does not need to worry about the -title of the tab, as that is automatically handled by the toolbar. It should return a string of HTML. - -The ``getTitleDetails()`` method should return a string that is displayed just to the right of the tab's title. It can -be used to provide additional overview information. For example, the Database tab displays the total number of queries -across all connections, while the Files tab displays the total number of files. - -Providing Timeline Data ------------------------ - -To provide information to be displayed in the Timeline, you must: - -1. Set ``$hasTimeline`` to ``true``. -2. Implement the ``formatTimelineData()`` method. - -The ``formatTimelineData()`` method must return an array of arrays formatted in a way that the timeline can use to sort -it correctly and display the correct information. The inner arrays must include the following information: - -.. literalinclude:: debugging/005.php - -Providing Vars --------------- - -To add data to the Vars tab, you must: - -1. Set ``$hasVarData`` to ``true``. -2. Implement the ``getVarData()`` method. - -The ``getVarData()`` method should return an array containing arrays of key/value pairs to display. The name of the -outer array's key is the name of the section on the Vars tab: - -.. literalinclude:: debugging/006.php - -.. _debug-toolbar-hot-reload: - -Hot Reloading -============= - -.. versionadded:: 4.4.0 - -The Debug Toolbar includes a feature called Hot Reloading that allows you to make changes to your application's code and -have them automatically reloaded in the browser without having to refresh the page. This is a great time-saver during -development. - -To enable Hot Reloading while you are developing, you can click the button on the left side of the toolbar that looks -like a refresh icon. This will enable Hot Reloading for all pages until you disable it. - -Hot Reloading works by scanning the files within the **app** directory every second and looking for changes. If it finds -any, it will send a message to the browser to reload the page. It does not scan any other directories, so if you are -making changes to files outside of the **app** directory, you will need to manually refresh the page. - -If you need to watch files outside of the **app** directory, or are finding it slow due to the size of your project, you -can specify the directories to scan and the file extensions to scan for in the ``$watchedDirectories`` and -``$watchedExtensions`` properties of the **app/Config/Toolbar.php** configuration file. diff --git a/user_guide_src/source/testing/debugging/001.php b/user_guide_src/source/testing/debugging/001.php deleted file mode 100644 index f54b4701f98e..000000000000 --- a/user_guide_src/source/testing/debugging/001.php +++ /dev/null @@ -1,3 +0,0 @@ - '', // Name displayed on the left of the timeline - 'component' => '', // Name of the Component listed in the middle of timeline - 'start' => 0.00, // start time, like microtime(true) - 'duration' => 0.00, // duration, like mircrotime(true) - microtime(true) -]; diff --git a/user_guide_src/source/testing/debugging/006.php b/user_guide_src/source/testing/debugging/006.php deleted file mode 100644 index 3ad25be67894..000000000000 --- a/user_guide_src/source/testing/debugging/006.php +++ /dev/null @@ -1,12 +0,0 @@ - [ - 'foo' => 'bar', - 'bar' => 'baz', - ], - 'section 2' => [ - 'foo' => 'bar', - 'bar' => 'baz', - ], -]; diff --git a/user_guide_src/source/testing/fabricator.rst b/user_guide_src/source/testing/fabricator.rst deleted file mode 100644 index 2b8bac4ba75b..000000000000 --- a/user_guide_src/source/testing/fabricator.rst +++ /dev/null @@ -1,218 +0,0 @@ -#################### -Generating Test Data -#################### - -Often you will need sample data for your application to run its tests. The ``Fabricator`` class uses -`Faker `_ to turn models into generators of random data. Use fabricators in your -seeds or test cases to stage fake data for your unit tests. - -.. contents:: - :local: - :depth: 2 - -Supported Models -================ - -``Fabricator`` supports any model that extends the framework's core model, ``CodeIgniter\Model``. You may use your own -custom models by ensuring they implement ``CodeIgniter\Test\Interfaces\FabricatorModel``: - -.. literalinclude:: fabricator/001.php - -.. note:: In addition to methods, the interface outlines some necessary properties for the target model. Please see the - interface code for details. - -Loading Fabricators -=================== - -At its most basic, a fabricator takes the model to act on: - -.. literalinclude:: fabricator/002.php - -The parameter can be a string specifying the name of the model, or an instance of the model itself: - -.. literalinclude:: fabricator/003.php - -Defining Formatters -=================== - -Faker generates data by requesting it from a formatter. With no formatters defined, ``Fabricator`` will attempt to guess -at the most appropriate fit based on the field name and properties of the model it represents, falling back on -``$fabricator->defaultFormatter``. This may be fine if your field names correspond with common formatters, or if you -don't care much about the content of the fields, but most of the time you will want to specify the formatters to use as -the second parameter to the constructor: - -.. literalinclude:: fabricator/004.php - -You can also change the formatters after a fabricator is initialized by using the ``setFormatters()`` method. - -Advanced Formatting -------------------- - -Sometimes the default return of a formatter is not enough. Faker providers allow parameters to most formatters to -further limit the scope of random data. A fabricator will check its representative model for the ``fake()`` method where -you can define exactly what the faked data should look like: - -.. literalinclude:: fabricator/005.php - -Notice in this example how the first three values are equivalent to the formatters from before. However, for ``avatar`` -we have requested an image size other than the default and ``login`` uses a conditional based on app configuration, -neither of which is possible using the ``$formatters`` parameter. - -You may want to keep your test data separate from your production models, so it is a good practice to define a child -class in your test support folder: - -.. literalinclude:: fabricator/006.php - -Setting Modifiers -================= - -.. versionadded:: 4.5.0 - -Faker provides three special providers, ``unique()``, ``optional()``, and ``valid()``, to be called before any provider. -Fabricator fully supports these modifiers by providing dedicated methods. - -.. literalinclude:: fabricator/022.php - -The arguments passed after the field name are passed directly to the modifiers as-is. You can refer to -`Faker's documentation on modifiers`_ for details. - -.. _Faker's documentation on modifiers: https://fakerphp.github.io/#modifiers - -Instead of calling each method on Fabricator, you may use Faker's modifiers directly if you are using the ``fake()`` -method on your models. - -.. literalinclude:: fabricator/023.php - -Localization -============ - -Faker supports a lot of different locales. Check their documentation to determine which providers support your locale. -Specify a locale in the third parameter while initiating a fabricator: - -.. literalinclude:: fabricator/007.php - -If no locale is specified, it will use the one defined in **app/Config/App.php** as ``defaultLocale``. You can check the -locale of an existing fabricator using its ``getLocale()`` method. - -Faking the Data -=============== - -Once you have a properly initialized fabricator, it is easy to generate test data with the ``make()`` command: - -.. literalinclude:: fabricator/008.php - -You might get back something like this: - -.. literalinclude:: fabricator/009.php - -You can also get a lot of them back by supplying a count: - -.. literalinclude:: fabricator/010.php - -The return type of ``make()`` mimics what is defined in the representative model, but you can force a type using the -methods directly: - -.. literalinclude:: fabricator/011.php - -The return from ``make()`` is ready to be used in tests or inserted into the database. Alternatively, ``Fabricator`` -includes the ``create()`` command to insert it for you and return the result. Due to model callbacks, database -formatting, and special keys like primary and timestamps, the return from ``create()`` can differ from ``make()``. You -might get back something like this: - -.. literalinclude:: fabricator/012.php - -Similar to ``make()``, you can supply a count to insert and return an array of objects: - -.. literalinclude:: fabricator/013.php - -Finally, there may be times you want to test with the full database object but you are not actually using a database. -``create()`` takes a second parameter to allow mocking the object, returning the object with extra database fields above -without actually touching the database: - -.. literalinclude:: fabricator/014.php - -Specifying Test Data -==================== - -Generated data is great, but sometimes you may want to supply a specific field for a test without compromising your -formatters configuration. Rather than creating a new fabricator for each variant, you can use ``setOverrides()`` to -specify the value for any fields: - -.. literalinclude:: fabricator/015.php - -Now any data generated with ``make()`` or ``create()`` will always use "Bobby" for the ``first`` field: - -.. literalinclude:: fabricator/016.php - -``setOverrides()`` can take a second parameter to indicate whether this should be a persistent override or only for a -single action: - -.. literalinclude:: fabricator/017.php - -Notice that after the first return, the fabricator stops using the overrides: - -.. literalinclude:: fabricator/018.php - -If no second parameter is supplied then passed values will persist by default. - -Test Helper -=========== - -Often all you will need is a one-and-done fake object for testing. The Test Helper provides the -``fake($model, $overrides, $persist = true)`` function to do just this: - -.. literalinclude:: fabricator/019.php - -This is equivalent to: - -.. literalinclude:: fabricator/020.php - -If you just need a fake object without saving it to the database, you can pass false into the persist parameter. - -Table Counts -============ - -Frequently your faked data will depend on other faked data. ``Fabricator`` provides a static count of the number of -faked items you have created for each table. Consider the following example: - -Your project has users and groups. In your test case you want to create various scenarios with groups of different -sizes, so you use ``Fabricator`` to create a bunch of groups. Now you want to create fake users but don't want to assign -them to a non-existent group ID. Your model's fake method could look like this: - -.. literalinclude:: fabricator/021.php - -Now creating a new user will ensure it is a part of a valid group: ``$user = fake(UserModel::class);`` - -Methods -------- - -``Fabricator`` handles the counts internally, but you can also access these static methods to assist with using them: - -getCount(string $table): int -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Return the current value for a specific table (default: 0). - -setCount(string $table, int $count): int -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Set the value for a specific table manually, for example if you create some test items without using a fabricator that -you still wanted factored into the final counts. - -upCount(string $table): int -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Increment the value for a specific table by one and return the new value. (This is what is used internally with -``Fabricator::create()``.) - -downCount(string $table): int -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Decrement the value for a specific table by one and return the new value, for example if you deleted a fake item but -wanted to track the change. - -resetCounts() -^^^^^^^^^^^^^ - -Resets all counts. It is a good idea to call this between test cases (though using ``CIUnitTestCase::$refresh = true`` -does it automatically). diff --git a/user_guide_src/source/testing/fabricator/001.php b/user_guide_src/source/testing/fabricator/001.php deleted file mode 100644 index f237d56b1324..000000000000 --- a/user_guide_src/source/testing/fabricator/001.php +++ /dev/null @@ -1,20 +0,0 @@ - 'firstName', - 'email' => 'email', - 'phone' => 'phoneNumber', - 'avatar' => 'imageUrl', -]; - -$fabricator = new Fabricator(UserModel::class, $formatters); diff --git a/user_guide_src/source/testing/fabricator/005.php b/user_guide_src/source/testing/fabricator/005.php deleted file mode 100644 index 5a601cebc050..000000000000 --- a/user_guide_src/source/testing/fabricator/005.php +++ /dev/null @@ -1,34 +0,0 @@ - $faker->firstName(), - 'email' => $faker->email(), - 'phone' => $faker->phoneNumber(), - 'avatar' => \Faker\Provider\Image::imageUrl(800, 400), - 'login' => config('Auth')->allowRemembering ? date('Y-m-d') : null, - ]; - - /* - * Or you can return a return type object. - - return new User([ - 'first' => $faker->firstName(), - 'email' => $faker->email(), - 'phone' => $faker->phoneNumber(), - 'avatar' => \Faker\Provider\Image::imageUrl(800, 400), - 'login' => config('Auth')->allowRemembering ? date('Y-m-d') : null, - ]); - - */ - } -} diff --git a/user_guide_src/source/testing/fabricator/006.php b/user_guide_src/source/testing/fabricator/006.php deleted file mode 100644 index 4cbe439a19a3..000000000000 --- a/user_guide_src/source/testing/fabricator/006.php +++ /dev/null @@ -1,14 +0,0 @@ -make(); -print_r($testUser); diff --git a/user_guide_src/source/testing/fabricator/009.php b/user_guide_src/source/testing/fabricator/009.php deleted file mode 100644 index a82d6063213e..000000000000 --- a/user_guide_src/source/testing/fabricator/009.php +++ /dev/null @@ -1,9 +0,0 @@ - 'Maynard', - 'email' => 'king.alford@example.org', - 'phone' => '201-886-0269 x3767', - 'avatar' => 'http://lorempixel.com/800/400/', - 'login' => null, -]; diff --git a/user_guide_src/source/testing/fabricator/010.php b/user_guide_src/source/testing/fabricator/010.php deleted file mode 100644 index 54b795ee2f72..000000000000 --- a/user_guide_src/source/testing/fabricator/010.php +++ /dev/null @@ -1,3 +0,0 @@ -make(10); diff --git a/user_guide_src/source/testing/fabricator/011.php b/user_guide_src/source/testing/fabricator/011.php deleted file mode 100644 index 9b9f62fd84ee..000000000000 --- a/user_guide_src/source/testing/fabricator/011.php +++ /dev/null @@ -1,5 +0,0 @@ -makeArray(); -$userObject = $fabricator->makeObject(); -$userEntity = $fabricator->makeObject('App\Entities\User'); diff --git a/user_guide_src/source/testing/fabricator/012.php b/user_guide_src/source/testing/fabricator/012.php deleted file mode 100644 index 98e83b610318..000000000000 --- a/user_guide_src/source/testing/fabricator/012.php +++ /dev/null @@ -1,12 +0,0 @@ - 1, - 'first' => 'Rachel', - 'email' => 'bradley72@gmail.com', - 'phone' => '741-241-2356', - 'avatar' => 'http://lorempixel.com/800/400/', - 'login' => null, - 'created_at' => '2020-05-08 14:52:10', - 'updated_at' => '2020-05-08 14:52:10', -]; diff --git a/user_guide_src/source/testing/fabricator/013.php b/user_guide_src/source/testing/fabricator/013.php deleted file mode 100644 index 6e89dd774eb9..000000000000 --- a/user_guide_src/source/testing/fabricator/013.php +++ /dev/null @@ -1,3 +0,0 @@ -create(100); diff --git a/user_guide_src/source/testing/fabricator/014.php b/user_guide_src/source/testing/fabricator/014.php deleted file mode 100644 index 60f0161b795f..000000000000 --- a/user_guide_src/source/testing/fabricator/014.php +++ /dev/null @@ -1,6 +0,0 @@ -assertIsNumeric($user->id); -$this->dontSeeInDatabase('user', ['id' => $user->id]); diff --git a/user_guide_src/source/testing/fabricator/015.php b/user_guide_src/source/testing/fabricator/015.php deleted file mode 100644 index 277c32fa370b..000000000000 --- a/user_guide_src/source/testing/fabricator/015.php +++ /dev/null @@ -1,4 +0,0 @@ -setOverrides(['first' => 'Bobby']); -$bobbyUser = $fabricator->make(); diff --git a/user_guide_src/source/testing/fabricator/016.php b/user_guide_src/source/testing/fabricator/016.php deleted file mode 100644 index 8b3f9513280d..000000000000 --- a/user_guide_src/source/testing/fabricator/016.php +++ /dev/null @@ -1,17 +0,0 @@ - 'Bobby', - 'email' => 'latta.kindel@company.org', - 'phone' => '251-806-2169', - 'avatar' => 'http://lorempixel.com/800/400/', - 'login' => null, -]; - -[ - 'first' => 'Bobby', - 'email' => 'melissa.strike@fabricon.us', - 'phone' => '525-214-2656 x23546', - 'avatar' => 'http://lorempixel.com/800/400/', - 'login' => null, -]; diff --git a/user_guide_src/source/testing/fabricator/017.php b/user_guide_src/source/testing/fabricator/017.php deleted file mode 100644 index ee79ea6f8d03..000000000000 --- a/user_guide_src/source/testing/fabricator/017.php +++ /dev/null @@ -1,5 +0,0 @@ -setOverrides(['first' => 'Bobby'], $persist = false); -$bobbyUser = $fabricator->make(); -$bobbyUser = $fabricator->make(); diff --git a/user_guide_src/source/testing/fabricator/018.php b/user_guide_src/source/testing/fabricator/018.php deleted file mode 100644 index 9eb1dbf0334d..000000000000 --- a/user_guide_src/source/testing/fabricator/018.php +++ /dev/null @@ -1,17 +0,0 @@ - 'Bobby', - 'email' => 'belingadon142@example.org', - 'phone' => '741-857-1933 x1351', - 'avatar' => 'http://lorempixel.com/800/400/', - 'login' => null, -]; - -[ - 'first' => 'Hans', - 'email' => 'hoppifur@metraxalon.com', - 'phone' => '487-235-7006', - 'avatar' => 'http://lorempixel.com/800/400/', - 'login' => null, -]; diff --git a/user_guide_src/source/testing/fabricator/019.php b/user_guide_src/source/testing/fabricator/019.php deleted file mode 100644 index 4c1de5f23dd2..000000000000 --- a/user_guide_src/source/testing/fabricator/019.php +++ /dev/null @@ -1,4 +0,0 @@ - 'Gerry']); diff --git a/user_guide_src/source/testing/fabricator/020.php b/user_guide_src/source/testing/fabricator/020.php deleted file mode 100644 index 784afa93718c..000000000000 --- a/user_guide_src/source/testing/fabricator/020.php +++ /dev/null @@ -1,7 +0,0 @@ -setOverrides(['name' => 'Gerry']); -$user = $fabricator->create(); diff --git a/user_guide_src/source/testing/fabricator/021.php b/user_guide_src/source/testing/fabricator/021.php deleted file mode 100644 index af6297f53946..000000000000 --- a/user_guide_src/source/testing/fabricator/021.php +++ /dev/null @@ -1,20 +0,0 @@ - $faker->firstName(), - 'email' => $faker->email(), - 'group_id' => mt_rand(1, Fabricator::getCount('groups')), - ]; - } -} diff --git a/user_guide_src/source/testing/fabricator/022.php b/user_guide_src/source/testing/fabricator/022.php deleted file mode 100644 index dbde0ff3a5f7..000000000000 --- a/user_guide_src/source/testing/fabricator/022.php +++ /dev/null @@ -1,11 +0,0 @@ -setUnique('email'); // sets generated emails to be always unique -$fabricator->setOptional('group_id'); // sets group id to be optional, with 50% chance to be `null` -$fabricator->setValid('age', static fn (int $age): bool => $age >= 18); // sets age to be 18 and above only - -$users = $fabricator->make(10); diff --git a/user_guide_src/source/testing/fabricator/023.php b/user_guide_src/source/testing/fabricator/023.php deleted file mode 100644 index 2729e60d18a3..000000000000 --- a/user_guide_src/source/testing/fabricator/023.php +++ /dev/null @@ -1,20 +0,0 @@ - $faker->firstName(), - 'email' => $faker->unique()->email(), - 'group_id' => $faker->optional()->passthrough(mt_rand(1, Fabricator::getCount('groups'))), - ]; - } -} diff --git a/user_guide_src/source/testing/feature.rst b/user_guide_src/source/testing/feature.rst deleted file mode 100644 index 8d0a4f4d0c8d..000000000000 --- a/user_guide_src/source/testing/feature.rst +++ /dev/null @@ -1,124 +0,0 @@ -#################### -HTTP Feature Testing -#################### - -Feature testing allows you to view the results of a single call to your application. This might be returning the results -of a single web form, hitting an API endpoint, and more. This is handy because it allows you to test the entire -life-cycle of a single request, ensuring that the routing works and the response is in the correct format, analyzing the -results, and more. - -.. contents:: - :local: - :depth: 2 - -The Test Class -============== - -Feature testing requires the ``CodeIgniter\Test\FeatureTestTrait`` trait. Add ``CodeIgniter\Test\DatabaseTestTrait`` -when your tests also need database staging. Ensure that ``parent::setUp()`` and ``parent::tearDown()`` are called if you -implement your own methods. - -.. literalinclude:: feature/001.php - -.. _feature-requesting-a-page: - -Requesting a Page -================= - -Essentially, feature tests simply allow you to call an endpoint on your application and get the results back. To do -this, you use the ``call()`` method. - -1. The first parameter is the HTTP method to use (most frequently either ``GET`` or ``POST``). -2. The second parameter is the URI path on your site to test. -3. The third parameter ``$params`` accepts an array that is used to populate the superglobal variables for the HTTP verb - you are using. So, a method of **GET** would have the ``$_GET`` variable populated, while a **POST** request would - have the ``$_POST`` array populated. The ``$params`` is also used in :ref:`feature-formatting-the-request`. - - .. note:: The ``$params`` array does not make sense for every HTTP verb, but is included for consistency. - -.. literalinclude:: feature/002.php - :lines: 2- - -Shorthand Methods ------------------ - -Shorthand methods for each of the HTTP verbs exist to ease typing and make things clearer: - -.. literalinclude:: feature/003.php - :lines: 2- - -Setting Different Routes ------------------------- - -You can use a custom collection of routes by passing an array of "routes" into the ``withRoutes()`` method. This will -override any existing routes in the system: - -.. literalinclude:: feature/004.php - :lines: 2- - -Each of the "routes" is a 3-element array containing the HTTP verb (or "add" for all), the URI to match, and the routing -destination. - -.. _feature-setting-session-values: - -Setting Session Values ----------------------- - -You can set custom session values to use during a single test with the ``withSession()`` method. This takes an array of -key/value pairs that should exist within the ``$_SESSION`` variable when this request is made, or ``null`` to indicate -that the current values of ``$_SESSION`` should be used. This is handy for testing authentication and more. - -.. literalinclude:: feature/005.php - :lines: 2- - -Setting Headers ---------------- - -You can set header values with the ``withHeaders()`` method. This takes an array of key/value pairs that would be passed -as a header into the call: - -.. literalinclude:: feature/006.php - :lines: 2- - -Bypassing Events ----------------- - -Events are handy to use in your application, but can be problematic during testing, especially events that are used to -send out emails. You can tell the system to skip any event handling with the ``skipEvents()`` method: - -.. literalinclude:: feature/007.php - :lines: 2- - -.. _feature-formatting-the-request: - -Formatting the Request ----------------------- - -You can set the format of your request's body using the ``withBodyFormat()`` method. Currently, this supports either -``json`` or ``xml``. This is useful when testing JSON or XML APIs so that you can set the request in the form that the -controller will expect. - -This will take the parameters passed into ``call()``, ``post()``, ``get()``... and assign them to the body of the -request in the given format. - -This will also set the ``Content-Type`` header for your request accordingly. - -.. literalinclude:: feature/008.php - :lines: 2- - -.. _feature-setting-the-body: - -Setting the Body ----------------- - -You can set the body of your request with the ``withBody()`` method. This allows you to format the body however you -want. It is recommended that you use this if you have more complicated XML to test. - -This will not set the ``Content-Type`` header for you. If you need that, you can set it with the ``withHeaders()`` -method. - -Checking the Response -===================== - -``FeatureTestTrait::call()`` returns an instance of a ``TestResponse``. See :doc:`Testing Responses ` on how -to use this class to perform additional assertions and verification in your test cases. diff --git a/user_guide_src/source/testing/feature/001.php b/user_guide_src/source/testing/feature/001.php deleted file mode 100644 index 9884535d41f2..000000000000 --- a/user_guide_src/source/testing/feature/001.php +++ /dev/null @@ -1,27 +0,0 @@ -myClassMethod(); - } - - protected function tearDown(): void - { - parent::tearDown(); - - $this->anotherClassMethod(); - } -} diff --git a/user_guide_src/source/testing/feature/002.php b/user_guide_src/source/testing/feature/002.php deleted file mode 100644 index a47406b24aeb..000000000000 --- a/user_guide_src/source/testing/feature/002.php +++ /dev/null @@ -1,10 +0,0 @@ -call('GET', '/'); - -// Submit a form -$result = $this->call('post', 'contact', [ - 'name' => 'Fred Flintstone', - 'email' => 'flintyfred@example.com', -]); diff --git a/user_guide_src/source/testing/feature/003.php b/user_guide_src/source/testing/feature/003.php deleted file mode 100644 index 1905a2dcf110..000000000000 --- a/user_guide_src/source/testing/feature/003.php +++ /dev/null @@ -1,8 +0,0 @@ -get($path, $params); -$this->post($path, $params); -$this->put($path, $params); -$this->patch($path, $params); -$this->delete($path, $params); -$this->options($path, $params); diff --git a/user_guide_src/source/testing/feature/004.php b/user_guide_src/source/testing/feature/004.php deleted file mode 100644 index 7e9a45d71c33..000000000000 --- a/user_guide_src/source/testing/feature/004.php +++ /dev/null @@ -1,7 +0,0 @@ -withRoutes($routes)->get('users'); diff --git a/user_guide_src/source/testing/feature/005.php b/user_guide_src/source/testing/feature/005.php deleted file mode 100644 index 448e68800a4e..000000000000 --- a/user_guide_src/source/testing/feature/005.php +++ /dev/null @@ -1,13 +0,0 @@ - 123, -]; - -$result = $this->withSession($values)->get('admin'); - -// Or... - -$_SESSION['logged_in'] = 123; - -$result = $this->withSession()->get('admin'); diff --git a/user_guide_src/source/testing/feature/006.php b/user_guide_src/source/testing/feature/006.php deleted file mode 100644 index e3cf72b69b47..000000000000 --- a/user_guide_src/source/testing/feature/006.php +++ /dev/null @@ -1,7 +0,0 @@ - 'application/json', -]; - -$result = $this->withHeaders($headers)->post('users'); diff --git a/user_guide_src/source/testing/feature/007.php b/user_guide_src/source/testing/feature/007.php deleted file mode 100644 index f44369c79865..000000000000 --- a/user_guide_src/source/testing/feature/007.php +++ /dev/null @@ -1,3 +0,0 @@ -skipEvents()->post('users', $userInfo); diff --git a/user_guide_src/source/testing/feature/008.php b/user_guide_src/source/testing/feature/008.php deleted file mode 100644 index f5118ea42091..000000000000 --- a/user_guide_src/source/testing/feature/008.php +++ /dev/null @@ -1,7 +0,0 @@ -withBodyFormat('json')->post('users', $userInfo); - -// Your controller can then get the parameters passed in with: -$userInfo = $this->request->getJson(); diff --git a/user_guide_src/source/testing/index.rst b/user_guide_src/source/testing/index.rst deleted file mode 100644 index 5fa01a853da2..000000000000 --- a/user_guide_src/source/testing/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -####### -Testing -####### - -CodeIgniter ships with a number of tools to help you test and debug your application thoroughly. The following sections -should get you quickly testing your applications. - -.. toctree:: - :titlesonly: - - Getting Started - Database - Generating Data - Controller Testing - HTTP Testing - response - cli - Mocking - benchmark - debugging - Session Testing diff --git a/user_guide_src/source/testing/mocking.rst b/user_guide_src/source/testing/mocking.rst deleted file mode 100644 index b1b2eacec5d4..000000000000 --- a/user_guide_src/source/testing/mocking.rst +++ /dev/null @@ -1,41 +0,0 @@ -###################### -Mocking System Classes -###################### - -Several components within the framework provide mocked versions of their classes that can be used during testing. These -classes can take the place of the normal class during test execution, often providing additional assertions to test that -actions have taken place (or not taken place) during the execution of the test. This might be checking that data gets -cached correctly, that emails were sent correctly, etc. - -.. contents:: - :local: - :depth: 2 - -Cache -===== - -You can mock the cache with the ``mock()`` method, using the ``CacheFactory`` as its only parameter. - -.. literalinclude:: mocking/001.php - -While this returns an instance of ``CodeIgniter\Test\Mock\MockCache`` that you can use directly, it also inserts the -mock into the Service class, so any calls within your code to ``service('cache')`` or ``Config\Services::cache()`` will -use the mocked class in its place. - -When using this in more than one test method within a single file, you should call either the ``clean()`` or -``bypass()`` methods during the test ``setUp()`` to ensure a clean slate when your tests run. - -Additional Methods ------------------- - -You can instruct the mocked cache handler to never do any caching with the ``bypass()`` method. This will emulate using -the dummy handler and ensures that your test does not rely on cached data. - -.. literalinclude:: mocking/002.php - -Available Assertions --------------------- - -The following new assertions are available on the mocked class for use during testing: - -.. literalinclude:: mocking/003.php diff --git a/user_guide_src/source/testing/mocking/001.php b/user_guide_src/source/testing/mocking/001.php deleted file mode 100644 index 69e69239049d..000000000000 --- a/user_guide_src/source/testing/mocking/001.php +++ /dev/null @@ -1,3 +0,0 @@ -bypass(); diff --git a/user_guide_src/source/testing/mocking/003.php b/user_guide_src/source/testing/mocking/003.php deleted file mode 100644 index 4a3babddaf54..000000000000 --- a/user_guide_src/source/testing/mocking/003.php +++ /dev/null @@ -1,10 +0,0 @@ -assertHas($key); -// Assert that a cached item named $key exists with a value of $value -$mock->assertHasValue($key, $value); -// Assert that a cached item named $key does NOT exist -$mock->assertMissing($key); diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst deleted file mode 100644 index c18f1edd7da0..000000000000 --- a/user_guide_src/source/testing/overview.rst +++ /dev/null @@ -1,295 +0,0 @@ -####### -Testing -####### - -CodeIgniter has been built to make testing both the framework and your application as simple as possible. Support for -`PHPUnit `__ is built in, and the framework provides a number of convenient helper methods to make -testing every aspect of your application as painless as possible. - -.. contents:: - :local: - :depth: 3 - -************ -System Setup -************ - -Installing PHPUnit -================== - -CodeIgniter uses `PHPUnit `__ as the basis for all of its testing. There are two ways to install -PHPUnit to use within your system. - -Composer --------- - -The recommended method is to install it in your project using `Composer `__. While it's -possible to install it globally, we do not recommend it, since it can cause compatibility issues with other projects on -your system as time goes on. - -Ensure that you have Composer installed on your system. From the project root (the directory that contains the -application and system directories) type the following from the command line: - -.. code-block:: console - - composer require --dev phpunit/phpunit - -This will install the correct version for your current PHP version. Once that is done, you can run all of the tests for -this project by typing: - -.. code-block:: console - - vendor/bin/phpunit - -If you are using Windows, use the following command: - -.. code-block:: console - - vendor\bin\phpunit - -Phar ----- - -The other option is to download the .phar file as described in the -`PHPUnit installation guide `__. This is a standalone file that -should be placed within your project root. - -************************ -Testing Your Application -************************ - -PHPUnit Configuration -===================== - -In your CodeIgniter project root, there is the ``phpunit.dist.xml`` file. This controls unit testing of your -application. If you provide your own ``phpunit.xml``, it will override this. - -By default, test files are placed under the **tests** directory in the project root. - -The Test Class -============== - -In order to take advantage of the additional tools provided, your tests must extend ``CodeIgniter\Test\CIUnitTestCase``. - -There are no rules for how test files must be placed. However, we recommend that you establish placement rules in -advance so that you can quickly understand where the test files are located. - -In this document, the test files corresponding to the classes in the **app** directory will be placed in the -**tests/app** directory. To test a new library, **app/Libraries/Foo.php**, you would create a new file at -**tests/app/Libraries/FooTest.php**: - -.. literalinclude:: overview/001.php - -To test one of your models, **app/Models/UserModel.php**, you might end up with something like this in -**tests/app/Models/UserModelTest.php**: - -.. literalinclude:: overview/002.php - -You can create any directory structure that fits your testing style/needs. When namespacing the test classes, remember -that the **app** directory is the root of the ``App`` namespace, so any classes you use must have the correct namespace -relative to ``App``. - -.. note:: Namespaces are not strictly required for test classes, but they are helpful to ensure no class names collide. - -When testing database results, you must use the :doc:`DatabaseTestTrait ` in your class. - -Staging -------- - -Most tests require some preparation in order to run correctly. PHPUnit's ``TestCase`` provides four methods to help with -staging and cleanup:: - - public static function setUpBeforeClass(): void - public static function tearDownAfterClass(): void - - protected function setUp(): void - protected function tearDown(): void - -The static methods ``setUpBeforeClass()`` and ``tearDownAfterClass()`` run before and after the entire test case, -whereas the protected methods ``setUp()`` and ``tearDown()`` run between each test. - -If you implement any of these special functions, make sure you run their parent as well so extended test cases do not -interfere with staging: - -.. literalinclude:: overview/003.php - -.. _testing-overview-traits: - -Traits ------- - -A common way to enhance your tests is to use traits to consolidate staging across different test cases. -``CIUnitTestCase`` will detect any class traits and look for staging methods to run named for the trait itself (i.e., -``setUp{NameOfTrait}()`` and ``tearDown{NameOfTrait}()``). - -For example, if you needed to add authentication to some of your test cases, you could create an authentication trait -with a setup method to fake a logged-in user: - -.. literalinclude:: overview/006.php - -.. literalinclude:: overview/022.php - -Additional Assertions ---------------------- - -``CIUnitTestCase`` provides additional unit testing assertions that you might find useful. - -assertLogged($level, $expectedMessage) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Ensure that something you expected to be logged was actually logged: - -.. literalinclude:: overview/007.php - :lines: 3-8 - -assertLogContains($level, $logMessage) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Ensure that there's a record in the logs which contains a message part. - -.. literalinclude:: overview/007.php - :lines: 10-13 - -assertEventTriggered($eventName) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Ensure that an event you expected to be triggered actually was: - -.. literalinclude:: overview/008.php - -assertHeaderEmitted($header, $ignoreCase = false) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Ensure that a header or cookie was actually emitted: - -.. literalinclude:: overview/009.php - -.. note:: The test case with this should be run as a separate process (with `@runInSeparateProcess annotation`_ or - `RunInSeparateProcess attribute`_) in PHPUnit. - -.. _@runInSeparateProcess annotation: https://docs.phpunit.de/en/10.5/annotations.html#runinseparateprocess -.. _RunInSeparateProcess attribute: https://docs.phpunit.de/en/10.5/attributes.html#runinseparateprocess - -assertHeaderNotEmitted($header, $ignoreCase = false) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Ensure that a header or cookie was not emitted: - -.. literalinclude:: overview/010.php - -.. note:: The test case with this should be run as a separate process (with `@runInSeparateProcess annotation`_ or - `RunInSeparateProcess attribute`_) in PHPUnit. - -assertCloseEnough($expected, $actual, $message = '', $tolerance = 1) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For extended execution time testing, tests that the absolute difference between expected and actual time is within the -prescribed tolerance: - -.. literalinclude:: overview/011.php - -The above test will allow the actual time to be either 660 or 661 seconds. - -assertCloseEnoughString($expected, $actual, $message = '', $tolerance = 1) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For extended execution time testing, tests that the absolute difference between expected and actual time, formatted as -strings, is within the prescribed tolerance: - -.. literalinclude:: overview/012.php - -The above test will allow the actual time to be either 660 or 661 seconds. - -Accessing Protected/Private Properties --------------------------------------- - -When testing, you can use the following setter and getter methods to access protected and private methods and properties -in the classes that you are testing. - -getPrivateMethodInvoker($instance, $method) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Enables you to call private methods from outside the class. This returns a function that can be called. The first -parameter is an instance of the class to test. The second parameter is the name of the method you want to call. - -.. literalinclude:: overview/013.php - -getPrivateProperty($instance, $property) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Retrieves the value of a private/protected class property from an instance of a class. The first parameter is an -instance of the class to test. The second parameter is the name of the property. - -.. literalinclude:: overview/014.php - -setPrivateProperty($instance, $property, $value) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Set a protected value within a class instance. The first parameter is an instance of the class to test. The second -parameter is the name of the property to set the value of. The third parameter is the value to set it to: - -.. literalinclude:: overview/015.php - -Mocking Services -================ - -You will often find that you need to mock one of the services defined in **app/Config/Services.php** to limit your tests -to only the code in question, while simulating various responses from the services. This is especially true when testing -controllers and other integration testing. The **Services** class provides the following methods to simplify this. - -Services::injectMock() ----------------------- - -This method allows you to define the exact instance that will be returned by the Services class. You can use this to set -properties of a service so that it behaves in a certain way, or replace a service with a mocked class. - -.. literalinclude:: overview/016.php - -The first parameter is the service that you are replacing. The name must match the function name in the Services class -exactly. The second parameter is the instance to replace it with. - -Services::reset() ------------------ - -Removes all mocked classes from the Services class, bringing it back to its original state. - -You can also use the ``$this->resetServices()`` method that ``CIUnitTestCase`` provides. - -.. note:: This method resets all states of Services, and the ``RouteCollection`` will have no routes. If you want your - routes to be loaded, you need to call the ``loadRoutes()`` method like ``Services::routes()->loadRoutes()``. - -Services::resetSingle(string $name) ------------------------------------ - -Removes any mock and shared instances for a single service, by its name. - -.. note:: The ``Cache``, ``Email`` and ``Session`` services are mocked by default to prevent intrusive testing behavior. - To prevent these from being mocked, remove their method callback from the class property: - ``$setUpMethods = ['mockEmail', 'mockSession'];`` - -Mocking Factory Instances -========================= - -Similar to Services, you may find yourself needing to supply a pre-configured class instance during testing that will be -used with ``Factories``. Use the same ``Factories::injectMock()`` and ``Factories::reset()`` static methods as -**Services**, but they take an additional preceding parameter for the component name: - -.. literalinclude:: overview/017.php - -.. note:: All component Factories are reset by default between each test. Modify your test case's ``$setUpMethods`` if - you need instances to persist. - -Testing and Time -================ - -Testing time-dependent code can be challenging. However, when using the :doc:`Time <../libraries/time>` class, the -current time can be fixed or changed at will during testing. - -Below is sample test code that fixes the current time: - -.. literalinclude:: overview/021.php - -You can fix the current time with the ``Time::setTestNow()`` method. Optionally, you can specify a locale as the second -parameter. - -Don't forget to reset the current time after the test by calling it without parameters. diff --git a/user_guide_src/source/testing/overview/001.php b/user_guide_src/source/testing/overview/001.php deleted file mode 100644 index 6dac95d2b671..000000000000 --- a/user_guide_src/source/testing/overview/001.php +++ /dev/null @@ -1,13 +0,0 @@ -createFakeUser(); - $this->logInUser($user); - } - - // ... -} diff --git a/user_guide_src/source/testing/overview/007.php b/user_guide_src/source/testing/overview/007.php deleted file mode 100644 index c4ab265edde0..000000000000 --- a/user_guide_src/source/testing/overview/007.php +++ /dev/null @@ -1,13 +0,0 @@ -log('error', "That's no moon"); -$this->assertLogged('error', "That's no moon"); - -// check that a portion of the message is found in the logs -$exception = new \RuntimeException('Hello world.'); -$logger->log('error', $exception->getTraceAsString()); -$this->assertLogContains('error', '{main}'); diff --git a/user_guide_src/source/testing/overview/008.php b/user_guide_src/source/testing/overview/008.php deleted file mode 100644 index 6599533453e8..000000000000 --- a/user_guide_src/source/testing/overview/008.php +++ /dev/null @@ -1,11 +0,0 @@ -assertEventTriggered('foo'); diff --git a/user_guide_src/source/testing/overview/009.php b/user_guide_src/source/testing/overview/009.php deleted file mode 100644 index 506d75a8d433..000000000000 --- a/user_guide_src/source/testing/overview/009.php +++ /dev/null @@ -1,9 +0,0 @@ -setCookie('foo', 'bar'); - -ob_start(); -$this->response->send(); -$output = ob_get_clean(); // in case you want to check the actual body - -$this->assertHeaderEmitted('Set-Cookie: foo=bar'); diff --git a/user_guide_src/source/testing/overview/010.php b/user_guide_src/source/testing/overview/010.php deleted file mode 100644 index 10e9d4a0d31b..000000000000 --- a/user_guide_src/source/testing/overview/010.php +++ /dev/null @@ -1,9 +0,0 @@ -setCookie('foo', 'bar'); - -ob_start(); -$this->response->send(); -$output = ob_get_clean(); // in case you want to check the actual body - -$this->assertHeaderNotEmitted('Set-Cookie: banana'); diff --git a/user_guide_src/source/testing/overview/011.php b/user_guide_src/source/testing/overview/011.php deleted file mode 100644 index 7f96f4f93e44..000000000000 --- a/user_guide_src/source/testing/overview/011.php +++ /dev/null @@ -1,7 +0,0 @@ -start('longjohn', strtotime('-11 minutes')); -$this->assertCloseEnough(11 * 60, $timer->getElapsedTime('longjohn')); diff --git a/user_guide_src/source/testing/overview/012.php b/user_guide_src/source/testing/overview/012.php deleted file mode 100644 index af7f506d2a46..000000000000 --- a/user_guide_src/source/testing/overview/012.php +++ /dev/null @@ -1,7 +0,0 @@ -start('longjohn', strtotime('-11 minutes')); -$this->assertCloseEnoughString(11 * 60, $timer->getElapsedTime('longjohn')); diff --git a/user_guide_src/source/testing/overview/013.php b/user_guide_src/source/testing/overview/013.php deleted file mode 100644 index 3eedfa9e1144..000000000000 --- a/user_guide_src/source/testing/overview/013.php +++ /dev/null @@ -1,12 +0,0 @@ -assertEquals('bar', $method('param1', 'param2')); diff --git a/user_guide_src/source/testing/overview/014.php b/user_guide_src/source/testing/overview/014.php deleted file mode 100644 index eb2509ac64b8..000000000000 --- a/user_guide_src/source/testing/overview/014.php +++ /dev/null @@ -1,9 +0,0 @@ -assertEquals('bar', $this->getPrivateProperty($obj, 'baz')); diff --git a/user_guide_src/source/testing/overview/015.php b/user_guide_src/source/testing/overview/015.php deleted file mode 100644 index 059c55a12011..000000000000 --- a/user_guide_src/source/testing/overview/015.php +++ /dev/null @@ -1,11 +0,0 @@ -setPrivateProperty($obj, 'baz', 'oops!'); - -// Do normal testing... diff --git a/user_guide_src/source/testing/overview/016.php b/user_guide_src/source/testing/overview/016.php deleted file mode 100644 index 8598a4a7a3c5..000000000000 --- a/user_guide_src/source/testing/overview/016.php +++ /dev/null @@ -1,20 +0,0 @@ -getMockBuilder(CURLRequest::class) - ->onlyMethods(['request']) - ->getMock(); - Services::injectMock('curlrequest', $curlrequest); - - // Do normal testing here.... - } -} diff --git a/user_guide_src/source/testing/overview/017.php b/user_guide_src/source/testing/overview/017.php deleted file mode 100644 index d989ed7e7da1..000000000000 --- a/user_guide_src/source/testing/overview/017.php +++ /dev/null @@ -1,19 +0,0 @@ -assertSame("\nfirst.\n", $this->getStreamFilterBuffer()); - - $this->resetStreamFilterBuffer(); - - CLI::write('second.'); - - $this->assertSame("second.\n", $this->getStreamFilterBuffer()); - } -} diff --git a/user_guide_src/source/testing/overview/019.php b/user_guide_src/source/testing/overview/019.php deleted file mode 100644 index a9bed8f0de8a..000000000000 --- a/user_guide_src/source/testing/overview/019.php +++ /dev/null @@ -1,27 +0,0 @@ -assertSame($expected, $output); - - // Restore php protocol wrapper. - PhpStreamWrapper::restore(); - } -} diff --git a/user_guide_src/source/testing/overview/020.php b/user_guide_src/source/testing/overview/020.php deleted file mode 100644 index 11bcdf33e2bc..000000000000 --- a/user_guide_src/source/testing/overview/020.php +++ /dev/null @@ -1,20 +0,0 @@ -assertSame('2023-11-25 12:00:00', (string) Time::now()); - } -} diff --git a/user_guide_src/source/testing/overview/022.php b/user_guide_src/source/testing/overview/022.php deleted file mode 100644 index 8d53304ebfec..000000000000 --- a/user_guide_src/source/testing/overview/022.php +++ /dev/null @@ -1,13 +0,0 @@ -` or -:doc:`HTTP Feature Tests `, but you can always create your own directly using any ``ResponseInterface``: - -.. literalinclude:: response/001.php - :lines: 2- - -.. contents:: - :local: - :depth: 2 - -Testing the Response -******************** - -Whether you have received a ``TestResponse`` as a result of your tests or created one yourself, there are a number of -new assertions that you can use in your tests. - -Accessing Request/Response -========================== - -request() ---------- - -You can directly access the Request object, if it was set during testing: - -.. literalinclude:: response/002.php - :lines: 2- - -response() ----------- - -This allows you direct access to the response object: - -.. literalinclude:: response/003.php - :lines: 2- - -Checking Response Status -======================== - -isOK() ------- - -Returns a boolean true/false based on whether the response is perceived to be "ok". This is primarily determined by a -response status code in the 200s or 300s. An empty body is not considered valid, unless in redirects. - -.. literalinclude:: response/004.php - :lines: 2- - -assertOK() ----------- - -This assertion simply uses the ``isOK()`` method to test a response. ``assertNotOK()`` is the inverse of this assertion. - -.. literalinclude:: response/005.php - :lines: 2- - -isRedirect() ------------- - -Returns a boolean true/false based on whether the response is a redirected response. - -.. literalinclude:: response/006.php - :lines: 2- - -assertRedirect() ----------------- - -Asserts that the Response is an instance of RedirectResponse. ``assertNotRedirect()`` is the inverse of this assertion. - -.. literalinclude:: response/007.php - :lines: 2- - -assertRedirectTo() ------------------- - -Asserts that the Response is an instance of RedirectResponse and the destination matches the URI given. - -.. literalinclude:: response/008.php - :lines: 2- - -getRedirectUrl() ----------------- - -Returns the URL set for a RedirectResponse, or null for failure. - -.. literalinclude:: response/009.php - :lines: 2- - -assertStatus(int $code) ------------------------ - -Asserts that the HTTP status code returned matches ``$code``. - -.. literalinclude:: response/010.php - :lines: 2- - -.. _response-session-assertions: - -Session Assertions -================== - -assertSessionHas(string $key, $value = null) --------------------------------------------- - -Asserts that a value exists in the resulting session. If ``$value`` is passed, it will also assert that the variable's -value matches what was specified. - -.. literalinclude:: response/011.php - :lines: 2- - -assertSessionMissing(string $key) ---------------------------------- - -Asserts that the resulting session does not include the specified ``$key``. - -.. literalinclude:: response/012.php - :lines: 2- - -Header Assertions -================= - -assertHeader(string $key, $value = null) ----------------------------------------- - -Asserts that a header named ``$key`` exists in the response. If ``$value`` is not empty, it will also assert that the -values match. - -.. literalinclude:: response/013.php - :lines: 2- - -assertHeaderMissing(string $key) --------------------------------- - -Asserts that a header named ``$key`` does not exist in the response. - -.. literalinclude:: response/014.php - :lines: 2- - -Cookie Assertions -================= - -assertCookie(string $key, $value = null, string $prefix = '') -------------------------------------------------------------- - -Asserts that a cookie named ``$key`` exists in the response. If ``$value`` is not empty, it will also assert that the -values match. You can set the cookie prefix, if needed, by passing it in as the third parameter. - -.. literalinclude:: response/015.php - :lines: 2- - -assertCookieMissing(string $key) --------------------------------- - -Asserts that a cookie named ``$key`` does not exist in the response. - -.. literalinclude:: response/016.php - :lines: 2- - -assertCookieExpired(string $key, string $prefix = '') ------------------------------------------------------ - -Asserts that a cookie named ``$key`` exists, but has expired. You can set the cookie prefix, if needed, by passing it in -as the second parameter. - -.. literalinclude:: response/017.php - :lines: 2- - -DOM Helpers -=========== - -The response you get back contains a number of helper methods to inspect the HTML output within the response. These are -useful for use within assertions in your tests. - -see() ------ - -Returns a boolean true/false based on whether the text on the page exists either by itself, or more specifically within -a tag, as specified by type, class, or id: - -.. literalinclude:: response/018.php - :lines: 2- - -The ``dontSee()`` method is the exact opposite: - -.. literalinclude:: response/019.php - :lines: 2- - -seeElement() ------------- - -The ``seeElement()`` and ``dontSeeElement()`` methods are very similar to the previous methods, but do not look at the -values of the elements. Instead, they simply check that the elements exist on the page: - -.. literalinclude:: response/020.php - :lines: 2- - -seeLink() ---------- - -You can use ``seeLink()`` to ensure that a link appears on the page with the specified text: - -.. literalinclude:: response/021.php - :lines: 2- - -seeInField() ------------- - -The ``seeInField()`` method checks whether any input tags exist with the name and value: - -.. literalinclude:: response/022.php - :lines: 2- - -seeCheckboxIsChecked() ----------------------- - -Finally, you can check if a checkbox exists and is checked with the ``seeCheckboxIsChecked()`` method: - -.. literalinclude:: response/023.php - :lines: 2- - -seeXPath() ----------- - -.. versionadded:: 4.5.0 - -You can use ``seeXPath()`` to take advantage of the full power that XPath gives you. This method is aimed at more -advanced users who want to write more complex expressions using the DOMXPath object directly: - -.. literalinclude:: response/033.php - :lines: 2- - -The ``dontSeeXPath()`` method is the exact opposite: - -.. literalinclude:: response/034.php - :lines: 2- - -DOM Assertions -============== - -You can perform tests to see if specific elements/text/etc. exist within the body of the response with the following -assertions. - -assertSee(string $search = null, string $element = null) --------------------------------------------------------- - -Asserts that text/HTML is on the page, either by itself or, more specifically, within a tag, as specified by type, -class, or id: - -.. literalinclude:: response/024.php - :lines: 2- - -assertDontSee(string $search = null, string $element = null) ------------------------------------------------------------- - -Asserts the exact opposite of the ``assertSee()`` method: - -.. literalinclude:: response/025.php - :lines: 2- - -assertSeeElement(string $search) --------------------------------- - -Similar to ``assertSee()``, but this only checks for an existing element. It does not check for specific text: - -.. literalinclude:: response/026.php - :lines: 2- - -assertDontSeeElement(string $search) ------------------------------------- - -Similar to ``assertSee()``, but this only checks for a missing element. It does not check for specific text: - -.. literalinclude:: response/027.php - :lines: 2- - -assertSeeLink(string $text, string $details = null) ---------------------------------------------------- - -Asserts that an anchor tag is found with matching ``$text`` as the body of the tag: - -.. literalinclude:: response/028.php - :lines: 2- - -assertSeeInField(string $field, string $value = null) ------------------------------------------------------ - -Asserts that an input tag exists with the name and value: - -.. literalinclude:: response/029.php - :lines: 2- - -Working with JSON -================= - -Responses will frequently contain JSON, especially when working with API methods. The following methods can help to test -the responses. - -getJSON() ---------- - -This method will return the body of the response as a JSON string: - -.. literalinclude:: response/030.php - :lines: 2- - -You can use this method to determine if ``$response`` actually holds JSON content: - -.. literalinclude:: response/031.php - :lines: 2- - -.. note:: Be aware that the JSON string will be pretty-printed in the result. - -assertJSONFragment(array $fragment) ------------------------------------ - -Asserts that ``$fragment`` is found within the JSON response. It does not need to match the entire JSON value. - -.. literalinclude:: response/032.php - :lines: 2- - -assertJSONExact($test) ----------------------- - -Similar to ``assertJSONFragment()``, but checks the entire JSON response to ensure exact matches. - -Working with XML -================ - -getXML() --------- - -If your application returns XML, you can retrieve it through this method. diff --git a/user_guide_src/source/testing/response/001.php b/user_guide_src/source/testing/response/001.php deleted file mode 100644 index 0e37cfec37ba..000000000000 --- a/user_guide_src/source/testing/response/001.php +++ /dev/null @@ -1,4 +0,0 @@ -assertOK(); diff --git a/user_guide_src/source/testing/response/002.php b/user_guide_src/source/testing/response/002.php deleted file mode 100644 index a835659904db..000000000000 --- a/user_guide_src/source/testing/response/002.php +++ /dev/null @@ -1,3 +0,0 @@ -request(); diff --git a/user_guide_src/source/testing/response/003.php b/user_guide_src/source/testing/response/003.php deleted file mode 100644 index c0cb73899f30..000000000000 --- a/user_guide_src/source/testing/response/003.php +++ /dev/null @@ -1,3 +0,0 @@ -response(); diff --git a/user_guide_src/source/testing/response/004.php b/user_guide_src/source/testing/response/004.php deleted file mode 100644 index d3ccbf4f4d12..000000000000 --- a/user_guide_src/source/testing/response/004.php +++ /dev/null @@ -1,5 +0,0 @@ -isOK()) { - // ... -} diff --git a/user_guide_src/source/testing/response/005.php b/user_guide_src/source/testing/response/005.php deleted file mode 100644 index 9c01964bc050..000000000000 --- a/user_guide_src/source/testing/response/005.php +++ /dev/null @@ -1,3 +0,0 @@ -assertOK(); diff --git a/user_guide_src/source/testing/response/006.php b/user_guide_src/source/testing/response/006.php deleted file mode 100644 index dcca55a4938b..000000000000 --- a/user_guide_src/source/testing/response/006.php +++ /dev/null @@ -1,5 +0,0 @@ -isRedirect()) { - // ... -} diff --git a/user_guide_src/source/testing/response/007.php b/user_guide_src/source/testing/response/007.php deleted file mode 100644 index 38b43a99b200..000000000000 --- a/user_guide_src/source/testing/response/007.php +++ /dev/null @@ -1,3 +0,0 @@ -assertRedirect(); diff --git a/user_guide_src/source/testing/response/008.php b/user_guide_src/source/testing/response/008.php deleted file mode 100644 index 62b8da3db6af..000000000000 --- a/user_guide_src/source/testing/response/008.php +++ /dev/null @@ -1,3 +0,0 @@ -assertRedirectTo('foo/bar'); diff --git a/user_guide_src/source/testing/response/009.php b/user_guide_src/source/testing/response/009.php deleted file mode 100644 index ba58bc23bb9e..000000000000 --- a/user_guide_src/source/testing/response/009.php +++ /dev/null @@ -1,4 +0,0 @@ -getRedirectUrl(); -$this->assertEquals(site_url('foo/bar'), $url); diff --git a/user_guide_src/source/testing/response/010.php b/user_guide_src/source/testing/response/010.php deleted file mode 100644 index 70faf34078e1..000000000000 --- a/user_guide_src/source/testing/response/010.php +++ /dev/null @@ -1,3 +0,0 @@ -assertStatus(403); diff --git a/user_guide_src/source/testing/response/011.php b/user_guide_src/source/testing/response/011.php deleted file mode 100644 index e9fccd725002..000000000000 --- a/user_guide_src/source/testing/response/011.php +++ /dev/null @@ -1,3 +0,0 @@ -assertSessionHas('logged_in', 123); diff --git a/user_guide_src/source/testing/response/012.php b/user_guide_src/source/testing/response/012.php deleted file mode 100644 index 0af2b74f0662..000000000000 --- a/user_guide_src/source/testing/response/012.php +++ /dev/null @@ -1,3 +0,0 @@ -assertSessionMissing('logged_in'); diff --git a/user_guide_src/source/testing/response/013.php b/user_guide_src/source/testing/response/013.php deleted file mode 100644 index 761b39943842..000000000000 --- a/user_guide_src/source/testing/response/013.php +++ /dev/null @@ -1,3 +0,0 @@ -assertHeader('Content-Type', 'text/html'); diff --git a/user_guide_src/source/testing/response/014.php b/user_guide_src/source/testing/response/014.php deleted file mode 100644 index 109ce46d1097..000000000000 --- a/user_guide_src/source/testing/response/014.php +++ /dev/null @@ -1,3 +0,0 @@ -assertHeader('Accepts'); diff --git a/user_guide_src/source/testing/response/015.php b/user_guide_src/source/testing/response/015.php deleted file mode 100644 index ded077e66a9b..000000000000 --- a/user_guide_src/source/testing/response/015.php +++ /dev/null @@ -1,3 +0,0 @@ -assertCookie('foo', 'bar'); diff --git a/user_guide_src/source/testing/response/016.php b/user_guide_src/source/testing/response/016.php deleted file mode 100644 index 3aa73f14899a..000000000000 --- a/user_guide_src/source/testing/response/016.php +++ /dev/null @@ -1,3 +0,0 @@ -assertCookieMissing('ci_session'); diff --git a/user_guide_src/source/testing/response/017.php b/user_guide_src/source/testing/response/017.php deleted file mode 100644 index 5ce2b3e2ab9f..000000000000 --- a/user_guide_src/source/testing/response/017.php +++ /dev/null @@ -1,3 +0,0 @@ -assertCookieExpired('foo'); diff --git a/user_guide_src/source/testing/response/018.php b/user_guide_src/source/testing/response/018.php deleted file mode 100644 index a32d2742d4f8..000000000000 --- a/user_guide_src/source/testing/response/018.php +++ /dev/null @@ -1,21 +0,0 @@ -see('Hello World')) { - // ... -} - -// Check that "Hello World" is within an h1 tag -if ($results->see('Hello World', 'h1')) { - // ... -} - -// Check that "Hello World" is within an element with the "notice" class -if ($results->see('Hello World', '.notice')) { - // ... -} - -// Check that "Hello World" is within an element with id of "title" -if ($results->see('Hello World', '#title')) { - // ... -} diff --git a/user_guide_src/source/testing/response/019.php b/user_guide_src/source/testing/response/019.php deleted file mode 100644 index 128e6862b99b..000000000000 --- a/user_guide_src/source/testing/response/019.php +++ /dev/null @@ -1,11 +0,0 @@ -dontSee('Hello World')) { - // ... -} - -// Checks that "Hellow World" does NOT exist within any h1 tag -if ($results->dontSee('Hello World', 'h1')) { - // ... -} diff --git a/user_guide_src/source/testing/response/020.php b/user_guide_src/source/testing/response/020.php deleted file mode 100644 index 94598bf98680..000000000000 --- a/user_guide_src/source/testing/response/020.php +++ /dev/null @@ -1,16 +0,0 @@ -seeElement('.notice')) { - // ... -} - -// Check that an element with id 'title' exists -if ($results->seeElement('#title')) { - // ... -} - -// Verify that an element with id 'title' does NOT exist -if ($results->dontSeeElement('#title')) { - // ... -} diff --git a/user_guide_src/source/testing/response/021.php b/user_guide_src/source/testing/response/021.php deleted file mode 100644 index d073ec5a3400..000000000000 --- a/user_guide_src/source/testing/response/021.php +++ /dev/null @@ -1,11 +0,0 @@ -seeLink('Upgrade Account')) { - // ... -} - -// Check that a link exists with 'Upgrade Account' as the text, AND a class of 'upsell' -if ($results->seeLink('Upgrade Account', '.upsell')) { - // ... -} diff --git a/user_guide_src/source/testing/response/022.php b/user_guide_src/source/testing/response/022.php deleted file mode 100644 index 791d72da4d3f..000000000000 --- a/user_guide_src/source/testing/response/022.php +++ /dev/null @@ -1,11 +0,0 @@ -seeInField('user', 'John Snow')) { - // ... -} - -// Check a multi-dimensional input -if ($results->seeInField('user[name]', 'John Snow')) { - // ... -} diff --git a/user_guide_src/source/testing/response/023.php b/user_guide_src/source/testing/response/023.php deleted file mode 100644 index af7c768e3758..000000000000 --- a/user_guide_src/source/testing/response/023.php +++ /dev/null @@ -1,11 +0,0 @@ -seeCheckboxIsChecked('.foo')) { - // ... -} - -// Check if checkbox with id of 'bar' is checked -if ($results->seeCheckboxIsChecked('#bar')) { - // ... -} diff --git a/user_guide_src/source/testing/response/024.php b/user_guide_src/source/testing/response/024.php deleted file mode 100644 index 9238cd2fd877..000000000000 --- a/user_guide_src/source/testing/response/024.php +++ /dev/null @@ -1,13 +0,0 @@ -assertSee('Hello World'); - -// Verify that "Hello World" is within an h1 tag -$result->assertSee('Hello World', 'h1'); - -// Verify that "Hello World" is within an element with the "notice" class -$result->assertSee('Hello World', '.notice'); - -// Verify that "Hello World" is within an element with id of "title" -$result->assertSee('Hello World', '#title'); diff --git a/user_guide_src/source/testing/response/025.php b/user_guide_src/source/testing/response/025.php deleted file mode 100644 index ea65727d0d36..000000000000 --- a/user_guide_src/source/testing/response/025.php +++ /dev/null @@ -1,7 +0,0 @@ -assertDontSee('Hello World'); - -// Verify that "Hello World" does NOT exist within any h1 tag -$results->assertDontSee('Hello World', 'h1'); diff --git a/user_guide_src/source/testing/response/026.php b/user_guide_src/source/testing/response/026.php deleted file mode 100644 index 5a6b38df324b..000000000000 --- a/user_guide_src/source/testing/response/026.php +++ /dev/null @@ -1,7 +0,0 @@ -assertSeeElement('.notice'); - -// Verify that an element with id 'title' exists -$results->assertSeeElement('#title'); diff --git a/user_guide_src/source/testing/response/027.php b/user_guide_src/source/testing/response/027.php deleted file mode 100644 index e5df1d09feaa..000000000000 --- a/user_guide_src/source/testing/response/027.php +++ /dev/null @@ -1,4 +0,0 @@ -assertDontSeeElement('#title'); diff --git a/user_guide_src/source/testing/response/028.php b/user_guide_src/source/testing/response/028.php deleted file mode 100644 index 91b42c99a9a9..000000000000 --- a/user_guide_src/source/testing/response/028.php +++ /dev/null @@ -1,7 +0,0 @@ -assertSeeLink('Upgrade Account'); - -// Verify that a link exists with 'Upgrade Account' as the text, AND a class of 'upsell' -$results->assertSeeLink('Upgrade Account', '.upsell'); diff --git a/user_guide_src/source/testing/response/029.php b/user_guide_src/source/testing/response/029.php deleted file mode 100644 index dfa511aa065f..000000000000 --- a/user_guide_src/source/testing/response/029.php +++ /dev/null @@ -1,7 +0,0 @@ -assertSeeInField('user', 'John Snow'); - -// Verify a multi-dimensional input -$results->assertSeeInField('user[name]', 'John Snow'); diff --git a/user_guide_src/source/testing/response/030.php b/user_guide_src/source/testing/response/030.php deleted file mode 100644 index 47e480c6081f..000000000000 --- a/user_guide_src/source/testing/response/030.php +++ /dev/null @@ -1,14 +0,0 @@ - 'bar'] - */ - -$json = $result->getJSON(); -/* - * $json is this: - * { - * "foo": "bar" - * } -`*/ diff --git a/user_guide_src/source/testing/response/031.php b/user_guide_src/source/testing/response/031.php deleted file mode 100644 index 6e746800e034..000000000000 --- a/user_guide_src/source/testing/response/031.php +++ /dev/null @@ -1,4 +0,0 @@ -assertTrue($result->getJSON() !== false); diff --git a/user_guide_src/source/testing/response/032.php b/user_guide_src/source/testing/response/032.php deleted file mode 100644 index 14f13f1942f5..000000000000 --- a/user_guide_src/source/testing/response/032.php +++ /dev/null @@ -1,11 +0,0 @@ - ['key-a', 'key-b'], - * ] - */ - -// Is true -$result->assertJSONFragment(['config' => ['key-a']]); diff --git a/user_guide_src/source/testing/response/033.php b/user_guide_src/source/testing/response/033.php deleted file mode 100644 index cf8cf3a7a3df..000000000000 --- a/user_guide_src/source/testing/response/033.php +++ /dev/null @@ -1,11 +0,0 @@ -seeXPath('//h1[contains(@class, "heading")]')) { - // ... -} - -// Check that h1 element which contains class "heading" have a text "Hello World" -if ($results->seeXPath('//h1[contains(@class, "heading")][contains(.,"Hello world")]')) { - // ... -} diff --git a/user_guide_src/source/testing/response/034.php b/user_guide_src/source/testing/response/034.php deleted file mode 100644 index e900dd1fff99..000000000000 --- a/user_guide_src/source/testing/response/034.php +++ /dev/null @@ -1,11 +0,0 @@ -dontSeeXPath('//h1[contains(@class, "heading")]')) { - // ... -} - -// Check that h1 element which contains class "heading" and text "Hello World" does NOT exist on the page -if ($results->dontSeeXPath('//h1[contains(@class, "heading")][contains(.,"Hello world")]')) { - // ... -} diff --git a/user_guide_src/source/testing/session_testing.rst b/user_guide_src/source/testing/session_testing.rst deleted file mode 100644 index 749185e17090..000000000000 --- a/user_guide_src/source/testing/session_testing.rst +++ /dev/null @@ -1,69 +0,0 @@ -############### -Session Testing -############### - -Testing session behavior in your application is made simple with the ArrayHandler session driver. Unlike other session -drivers, ArrayHandler does not persist data to disk, database, or external storage. This allows you to simulate session -interactions safely during unit or integration tests, without affecting real session data. - -Using this driver, you can set, retrieve, and assert session data entirely in memory, making your tests faster and more -isolated. While in most production scenarios you would use file, database, or cache-backed sessions, ArrayHandler exists -specifically to support testing workflows and prevent side effects. - -.. contents:: - :local: - :depth: 2 - -Initializing Sessions -===================== - -You can initialize a session using the ArrayHandler driver for testing. This example shows how to create a session -instance with a proper configuration: - -.. literalinclude:: session_testing/001.php - -Setting and Retrieving Data -=========================== - -Once initialized, you can set session values and retrieve them as usual: - -.. literalinclude:: session_testing/002.php - -.. note:: - - Session data is stored in memory and lasts as long as the ArrayHandler object exists; after the object is destroyed - (typically at the end of a request or test), the data is lost. - -Example Test Case -================= - -Here's a simple example demonstrating usage of the ArrayHandler in a PHPUnit test: - -.. literalinclude:: session_testing/003.php - -Session Assertions -================== - -Using PHPUnit Assertions with ArrayHandler ------------------------------------------- - -When testing sessions directly with Session and ArrayHandler in a unit test, use standard PHPUnit assertions. -``assertSessionHas()`` and ``assertSessionMissing()`` are not available in this context because you are interacting -directly with the session object, not a response object. - -.. literalinclude:: session_testing/004.php - -Session Assertions via TestResponse ------------------------------------ - -When testing controllers or HTTP responses, you can use CodeIgniter 4's session assertion helpers, such as -``assertSessionHas()`` and ``assertSessionMissing()``, which are available on the ``TestResponse`` object. These helpers -allow you to assert the state of the session during the HTTP request/response lifecycle. See -:ref:`Session Assertions ` for more details. - -Custom Session Values -===================== - -In Feature Tests, you can provide custom session data for a single test using the ``withSession()`` method. This allows -you to simulate session states such as logged-in users or specific roles during the request. For full details and -examples, see :ref:`Setting Session Values `. diff --git a/user_guide_src/source/testing/session_testing/001.php b/user_guide_src/source/testing/session_testing/001.php deleted file mode 100644 index 01ad520b7ed0..000000000000 --- a/user_guide_src/source/testing/session_testing/001.php +++ /dev/null @@ -1,14 +0,0 @@ -set('framework', 'CodeIgniter4'); - -// Retrieve session data -echo $testSession->get('framework'); // outputs 'CodeIgniter4' - -// Remove session data -$testSession->remove('framework'); diff --git a/user_guide_src/source/testing/session_testing/003.php b/user_guide_src/source/testing/session_testing/003.php deleted file mode 100644 index 8a9ecaf64b92..000000000000 --- a/user_guide_src/source/testing/session_testing/003.php +++ /dev/null @@ -1,38 +0,0 @@ -testSession = new Session($arrayHandler, $config); - } - - public function testFrameworkNameInSession(): void - { - // Set a session value - $this->testSession->set('framework', 'CodeIgniter'); - - // Assert the value exists and is correct - $this->assertSame('CodeIgniter', $this->testSession->get('framework')); - - // Remove the session value - $this->testSession->remove('framework'); - $this->assertNull($this->testSession->get('framework')); - } -} diff --git a/user_guide_src/source/testing/session_testing/004.php b/user_guide_src/source/testing/session_testing/004.php deleted file mode 100644 index ef7ab12ba472..000000000000 --- a/user_guide_src/source/testing/session_testing/004.php +++ /dev/null @@ -1,16 +0,0 @@ -set('framework', 'CodeIgniter4'); - -// Assert the state of the session using PHPUnit assertions -$this->assertSame('CodeIgniter4', $testSession->get('framework')); // Value exists - -// Not empty -$this->assertNotEmpty($testSession->get('framework')); - -// Remove the value and assert it's gone -$testSession->remove('framework'); - -// Should be null -$this->assertNull($testSession->get('framework')); diff --git a/utils/check_permission_x.php b/utils/check_permission_x.php index c6155ea23a8c..81d6787a9dc8 100644 --- a/utils/check_permission_x.php +++ b/utils/check_permission_x.php @@ -33,7 +33,6 @@ function findExecutableFiles(string $dir, array $excludeDirs = []): array '.github/scripts/deploy-userguide', '.github/scripts/secure-git-push', 'admin/starter/builds', - 'user_guide_src/add-edit-this-page', ]; $executableFiles = []; @@ -78,7 +77,7 @@ function findExecutableFiles(string $dir, array $excludeDirs = []): array // Main chdir(__DIR__ . '/../'); -$includeDirs = ['.github', 'admin', 'app', 'public', 'system', 'tests', 'user_guide_src', 'utils', 'writable']; +$includeDirs = ['.github', 'admin', 'app', 'public', 'system', 'tests', 'utils', 'writable']; $excludeDirs = ['utils/vendor']; $executableFiles = []; diff --git a/utils/check_tabs_in_rst.php b/utils/check_tabs_in_rst.php deleted file mode 100644 index 69e8f92de1ee..000000000000 --- a/utils/check_tabs_in_rst.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -namespace Utils; - -require __DIR__ . '/../system/util_bootstrap.php'; - -use CodeIgniter\CLI\CLI; - -$rstFilesWithTabs = (string) shell_exec('git grep -EIPn "\t" -- "*.rst"'); -$rstFilesWithTabs = explode("\n", $rstFilesWithTabs); -$rstFilesWithTabs = array_map(static function (string $line): array { - preg_match('/^(?P[^:]+):(?P\d+):(?P.+)$/', $line, $matches); - - return [ - 'file' => $matches['file'], - 'line' => $matches['line'], - 'code' => $matches['code'], - ]; -}, array_filter($rstFilesWithTabs)); - -$normalizedRstFilesWithTabs = []; - -foreach ($rstFilesWithTabs as ['file' => $file, 'line' => $line, 'code' => $code]) { - if (! isset($normalizedRstFilesWithTabs[$file])) { - $normalizedRstFilesWithTabs[$file] = []; - } - - $normalizedRstFilesWithTabs[$file][] = ['line' => $line, 'code' => $code]; -} - -unset($rstFilesWithTabs); - -if ($normalizedRstFilesWithTabs !== []) { - printf( - "%s\n\n%s\n", - CLI::color('Tabs in RST files were detected:', 'light_gray', 'red'), - implode("\n", array_map( - static fn (string $file, array $parts): string => sprintf( - "%s%s\n%s\n", - CLI::color('* in ', 'light_red'), - CLI::color($file, 'yellow'), - implode("\n", array_map(static fn (array $line): string => sprintf( - '%s | %s', - str_pad($line['line'], 4, ' ', STR_PAD_LEFT), - str_replace("\t", CLI::color('....', 'light_gray', 'red'), $line['code']), - ), $parts)), - ), - array_keys($normalizedRstFilesWithTabs), - array_values($normalizedRstFilesWithTabs), - )), - ); - - exit(1); -} - -CLI::write('No tabs in RST files were detected.', 'black', 'green'); - -exit(0);