diff --git a/.editorconfig b/.editorconfig index 23a7072c587b..7382bb8eb572 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,12 +1,15 @@ -; top-most EditorConfig file +; This file is for unifying the coding style for different editors and IDEs. +; More information at http://editorconfig.org + root = true -; Unix-style newlines [*] -end_of_line = lf - -[*.php] -indent_style = tab charset = utf-8 -trim_trailing_whitespace = true +indent_size = 4 +indent_style = space +end_of_line = lf insert_final_newline = true +trim_trailing_whitespace = true + +[*.{yml,yaml}] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes index 51fea41744d4..3f67f2e35167 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,18 +5,35 @@ # git files .gitattributes export-ignore -# .gitignore +.gitignore export-ignore -# helper config files -.travis.yml export-ignore -phpdoc.dist.xml export-ignore - -# Misc other files -readme.rst +# admin files +.github/ export-ignore +admin/ export-ignore +contributing/ export-ignore +.editorconfig export-ignore +CODE_OF_CONDUCT.md export-ignore +CONTRIBUTING.md export-ignore -# They don't want all of our tests... -tests/codeigniter/ export-ignore -tests/travis/ export-ignore +# contributor/development files +tests/ export-ignore +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 +deptrac.yaml export-ignore +phpmetrics.json export-ignore +phpstan-baseline.php export-ignore +phpstan-bootstrap.php export-ignore +phpstan.neon.dist export-ignore +phpunit.xml.dist export-ignore +psalm-baseline.xml export-ignore +psalm.xml export-ignore +psalm_autoload.php export-ignore +rector.php export-ignore -# User Guide Source Files -user_guide_src +# source user guide +user_guide_src/ export-ignore +.nojekyll export-ignore +phpdoc.dist.xml export-ignore diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000000..c00e70ba3291 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,138 @@ +name: Bug report +description: Create a report to help us improve CodeIgniter +title: "Bug: " +labels: ['bug'] + +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + + Before you begin, **please ensure that there are no existing issues, + whether still open or closed, related to your report**. + If there is, your report will be closed promptly. + + For example, if you get the error "*Undefined property: Config\\Exceptions::$sensitiveDataInTrace*", + you can search the GitHub repository with the keyword "[$sensitiveDataInTrace](https://github.com/codeigniter4/CodeIgniter4/search?q=%24sensitiveDataInTrace&type=issues)". + + --- + + - type: dropdown + id: php-version + attributes: + label: PHP Version + description: Which PHP versions did you run your code? + multiple: true + options: + - '8.1' + - '8.2' + - '8.3' + - '8.4' + validations: + required: true + + - type: input + id: codeigniter-version + attributes: + label: CodeIgniter4 Version + description: | + e.g. 4.1.5 + If you are not using the [latest version](https://github.com/codeigniter4/CodeIgniter4/releases), please + check to see if the problem occurs with the latest version. + validations: + required: true + + - type: dropdown + id: codeigniter-installation + attributes: + label: CodeIgniter4 Installation Method + multiple: false + options: + - Composer (using `codeigniter4/appstarter`) + - Composer (as dependency to an existing project) + - Manual (zip or tar.gz) + - Git + validations: + required: true + + - type: dropdown + id: operating-systems + attributes: + label: Which operating systems have you tested for this bug? + description: You may select more than one. + multiple: true + options: + - macOS + - Windows + - Linux + validations: + required: true + + - type: dropdown + id: server + attributes: + label: Which server did you use? + options: + - apache + - cli + - cli-server (PHP built-in webserver) + - cgi-fcgi + - fpm-fcgi + - phpdbg + validations: + required: true + + - type: dropdown + id: environment + attributes: + label: Environment + description: Which CI_ENVIRONMENT setting are you using? + multiple: true + options: + - production + - development + - testing + - other (custom) + validations: + required: true + + - type: input + id: database + attributes: + label: Database + description: e.g. MySQL 5.6, MariaDB 10.2, PostgreSQL 9.6 + validations: + required: false + + - type: textarea + id: description + attributes: + label: What happened? + placeholder: Tell us what you see! + validations: + required: true + + - type: textarea + attributes: + label: Steps to Reproduce + description: Steps to reproduce the behavior. + validations: + required: true + + - type: textarea + attributes: + label: Expected Output + description: What do you expect to happen instead of this filed bug? + validations: + required: true + + - type: textarea + attributes: + label: Anything else? + description: | + Links? References? Anything that will give us more context about the issue you are encountering! + + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000000..d399e41dca3e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,9 @@ +blank_issues_enabled: false +contact_links: + - name: CodeIgniter Forum + url: https://forum.codeigniter.com/forum-30.html + about: Please ask your support questions and/or feature requests in the forums. Thanks! + + - name: CodeIgniter Slack channel + url: https://codeigniterchat.slack.com + about: Engage with other members of the community in our Slack channel. diff --git a/.github/ISSUE_TEMPLATE/planned-work.md b/.github/ISSUE_TEMPLATE/planned-work.md new file mode 100644 index 000000000000..3da11a7dbc58 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/planned-work.md @@ -0,0 +1,10 @@ +--- +name: Planned work +about: Maintainers' space. DO NOT use this for your bug reports! +title: 'Dev: ' +labels: dev +assignees: '' + +--- + +Maintainers will create "issues" for planned work, so it can be tracked. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000000..e39d50b0b187 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,21 @@ + +**Description** +Explain what you have changed, and why. + +**Checklist:** +- [ ] Securely signed commits +- [ ] Component(s) with PHPDoc blocks, only if necessary or adds value (without duplication) +- [ ] Unit testing, with >80% coverage +- [ ] User guide updated +- [ ] Conforms to style guide diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..d3afefe5c9fd --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,18 @@ +version: 2 + +updates: + - package-ecosystem: 'composer' + directory: '/' + schedule: + interval: 'daily' + open-pull-requests-limit: 10 + + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'daily' + ignore: + - dependency-name: '*' + update-types: + - 'version-update:semver-minor' + - 'version-update:semver-patch' diff --git a/.github/mergeable.yml b/.github/mergeable.yml new file mode 100644 index 000000000000..2e58526188aa --- /dev/null +++ b/.github/mergeable.yml @@ -0,0 +1,69 @@ +# https://mergeable.readthedocs.io/en/latest/configuration.html + +version: 2 +mergeable: + - when: issues.opened, issues.reopened + validate: + - do: or + validate: + - do: and + validate: + - do: description + must_include: + regex: '### PHP Version' + - do: description + must_include: + regex: '### CodeIgniter4 Version' + - do: author + must_include: + regex: ^kenjis|lonnieezell|MGatner|michalsn|paulbalandan|samsonasik|ddevsr$ + fail: + - do: comment + payload: + body: | + Hi there, @@author! :wave: + + It looks like you opened an issue without following the bug report template: + + * Bug report ([open an issue](https://github.com/codeigniter4/CodeIgniter4/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=Bug%3A+)) + * For feature request or support question, please use the [forums](https://forum.codeigniter.com/forum-30.html). + + The current issue will be closed. This is a precaution to save maintainers' time, I hope you'll understand. + + Sincerely, the mergeable bot 🤖 + - do: close + + - when: pull_request.opened, pull_request.ready_for_review + filter: + - do: payload + pull_request: + author_association: + must_include: + regex: ^NONE|FIRST_TIME_CONTRIBUTOR|FIRST_TIMER$ + validate: [] + pass: + - do: comment + payload: + body: | + Hi there, @@author! :wave: + + Thank you for sending this PR! + + We expect the following in all Pull Requests (PRs). + - PRs must be sent to the [appropriate branch](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#branching) + - All git commits must be [GPG-signed](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#signing) + - Must follow our [style guide](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#php-style) + - Be [commented](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#comments) in the PHP source file + - Be documented in the [user guide](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#user-guide) + - Be [unit tested](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#unit-testing) + - Pass all checks in GitHub Actions + + > [!IMPORTANT] + > We expect all code changes or bug-fixes to be accompanied by one or more tests added to our test suite to prove the code works. + + If pull requests do not comply with the above, they will likely be closed. Since we are a team of volunteers, we don't have any more time to work + on the framework than you do. Please make it as painless for your contributions to be included as possible. + + See https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md + + Sincerely, the mergeable bot 🤖 diff --git a/.github/prlint.json b/.github/prlint.json new file mode 100644 index 000000000000..bb352e554b71 --- /dev/null +++ b/.github/prlint.json @@ -0,0 +1,8 @@ +{ + "title": [ + { + "pattern": "^(\\[\\d+\\.\\d+\\]\\s{1})?(feat|fix|chore|docs|perf|refactor|style|test|config|revert)(\\([\\-.@:`a-zA-Z0-9]+\\))?!?:\\s{1}\\S.+\\S|Prep for \\d\\.\\d\\.\\d release|\\d\\.\\d\\.\\d (Ready|Merge) code$", + "message": "PR title must include the type (feat, fix, chore, docs, perf, refactor, style, test, config, revert) of the commit per Conventional Commits specification. See https://www.conventionalcommits.org/en/v1.0.0/ for the discussion." + } + ] +} diff --git a/.github/release.yml b/.github/release.yml new file mode 100644 index 000000000000..de6e982d91a6 --- /dev/null +++ b/.github/release.yml @@ -0,0 +1,23 @@ +changelog: + exclude: + authors: + - dependabot + categories: + - title: Breaking Changes + labels: + - 'breaking change' + - title: Fixed Bugs + labels: + - bug + - title: New Features + labels: + - 'new feature' + - title: Enhancements + labels: + - enhancement + - title: Refactoring + labels: + - refactor + - title: Others (Only for checking. Remove this category) + labels: + - "*" diff --git a/.github/scripts/deploy-appstarter b/.github/scripts/deploy-appstarter new file mode 100644 index 000000000000..29dfe66db64c --- /dev/null +++ b/.github/scripts/deploy-appstarter @@ -0,0 +1,35 @@ +#!/bin/bash + +## Deploy codeigniter4/appstarter + +# Setup variables +SOURCE=$1 +TARGET=$2 +RELEASE=$3 + +echo "Preparing for version $3" +echo "Merging files from $1 to $2" + +# Prepare the source +cd $SOURCE +git checkout master + +# Prepare the target +cd $TARGET +git checkout master +rm -rf * + +# Copy common files +releasable='app public writable env LICENSE spark preload.php' +for fff in $releasable; +do + cp -Rf ${SOURCE}/$fff ./ +done + +# Copy repo-specific files +cp -Rf ${SOURCE}/admin/starter/. ./ + +# Commit the changes +git add . +git commit -m "Release ${RELEASE}" +git push diff --git a/.github/scripts/deploy-framework b/.github/scripts/deploy-framework new file mode 100644 index 000000000000..cc9d89e7acc7 --- /dev/null +++ b/.github/scripts/deploy-framework @@ -0,0 +1,37 @@ +#!/bin/bash + +## Deploy codeigniter4/framework + +# Setup variables +SOURCE=$1 +TARGET=$2 +RELEASE=$3 + +echo "Preparing for version $3" +echo "Merging files from $1 to $2" + +# Prepare the source +cd $SOURCE +git checkout master + +# Prepare the target +cd $TARGET +git checkout master +rm -rf * + +# Copy common files +releasable='app public writable env LICENSE spark system preload.php' +for fff in $releasable; +do + cp -Rf ${SOURCE}/$fff ./ +done + +# Copy repo-specific files +cp -Rf ${SOURCE}/admin/framework/. ./ +# Copy tests files +cp -Rf ${SOURCE}/admin/starter/tests/. ./tests/ + +# Commit the changes +git add . +git commit -m "Release ${RELEASE}" +git push diff --git a/.github/scripts/deploy-userguide b/.github/scripts/deploy-userguide new file mode 100755 index 000000000000..6d1c755107b7 --- /dev/null +++ b/.github/scripts/deploy-userguide @@ -0,0 +1,61 @@ +#!/bin/bash + +## Deploy codeigniter4/userguide + +# Setup variables +SOURCE=$1 +TARGET=$2 +RELEASE=$3 + +# Check if RELEASE is empty +if [ -z "$RELEASE" ]; then + echo "Error: \$RELEASE parameter is empty." + exit 1 +fi + +VERSION=$(echo "$RELEASE" | cut -c 2-) + +# Check if VERSION is empty +if [ -z "$VERSION" ]; then + echo "Error: Failed to extract \$VERSION from \$RELEASE parameter '$RELEASE'." + exit 1 +fi + +# Check if VERSION matches the format X.Y.Z +if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Error: VERSION '$VERSION' does not match the expected format X.Y.Z." + exit 1 +fi + +echo "Preparing for version $3" +echo "Merging files from $1 to $2" + +# Prepare the source +cd $SOURCE +git checkout master +cd user_guide_src +make html +make epub + +# Prepare the target +cd $TARGET +git checkout master +rm -rf docs + +# Copy common files +cp -Rf ${SOURCE}/LICENSE ./ + +# Copy repo-specific files +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 + +# Commit the changes +git add . +git commit -m "Release ${RELEASE}" +git push diff --git a/.github/scripts/validate-version b/.github/scripts/validate-version new file mode 100644 index 000000000000..411900dedb75 --- /dev/null +++ b/.github/scripts/validate-version @@ -0,0 +1,21 @@ +#!/bin/bash +set -o pipefail + +if [[ -z $1 ]]; then + echo "validate-version requires a version identifier" + exit 1 +fi + +FILES=("system/CodeIgniter.php" "user_guide_src/source/conf.py") +LENGTH="${#FILES[@]}" + +for FILE in "${FILES[@]}"; do + COUNT="$((COUNT + $(grep -c "$FILE" -e "'$1'")))" +done + +if [[ $COUNT -ne $LENGTH ]]; then + echo "CodeIgniter version is not updated to v"$1"" + exit 1 +fi + +echo "CodeIgniter version is updated to v"$1"" diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml new file mode 100644 index 000000000000..a660e33eb03c --- /dev/null +++ b/.github/workflows/deploy-apidocs.yml @@ -0,0 +1,74 @@ +# When changes are pushed to the develop branch, +# build the current version of the API documentation +# with phpDocumentor and deploy it to codeigniter4/api. +name: Deploy API Documentation + +on: + push: + branches: + - 'develop' + paths: + - 'system/**' + - '.github/workflows/deploy-apidocs.yml' + +permissions: + contents: read + +jobs: + build: + name: Deploy to api + permissions: + contents: write + if: github.repository == 'codeigniter4/CodeIgniter4' + runs-on: ubuntu-22.04 + + steps: + - name: Setup credentials + run: | + git config --global user.email "action@github.com" + git config --global user.name "${GITHUB_ACTOR}" + + - name: Checkout source + uses: actions/checkout@v6 + with: + path: source + + - name: Checkout target + uses: actions/checkout@v6 + with: + repository: codeigniter4/api + token: ${{ secrets.ACCESS_TOKEN }} + path: api + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + tools: phive + coverage: none + + - name: Download latest phpDocumentor + working-directory: source + run: phive --no-progress install --trust-gpg-keys 6DA3ACC4991FFAE5 phpDocumentor + + - name: Prepare API repo + working-directory: api + run: | + git reset --hard master + rm -rfv docs + mkdir --parents --verbose docs + + - name: Build API in source repo + working-directory: source + run: | + php tools/phpDocumentor --ansi --verbose + cp -R ${GITHUB_WORKSPACE}/source/api/build/* ${GITHUB_WORKSPACE}/api/docs + + - name: Deploy to API repo + working-directory: api + run: | + git add . + if ! git diff-index --quiet HEAD; then + git commit -m "Updated API for commit ${GITHUB_SHA}" + git push origin master + fi diff --git a/.github/workflows/deploy-distributables.yml b/.github/workflows/deploy-distributables.yml new file mode 100644 index 000000000000..e1a63e792ffa --- /dev/null +++ b/.github/workflows/deploy-distributables.yml @@ -0,0 +1,193 @@ +# When a new release is created, deploy relevant +# files to each of the generated repos. +name: Deploy Distributable Repos + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + check-version: + name: Check for updated version + runs-on: ubuntu-22.04 + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 # fetch all tags + + - name: Get latest version + run: | + echo 'LATEST_VERSION<> $GITHUB_ENV + echo $(git describe --tags --abbrev=0) | sed "s/v//" >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + + - name: Search for updated version + if: ${{ env.LATEST_VERSION }} + run: | + chmod +x ${GITHUB_WORKSPACE}/.github/scripts/validate-version + ${GITHUB_WORKSPACE}/.github/scripts/validate-version ${{ env.LATEST_VERSION }} + + framework: + name: Deploy to framework + permissions: + # Allow actions/github-script to create release + contents: write + if: github.repository == 'codeigniter4/CodeIgniter4' + runs-on: ubuntu-22.04 + needs: check-version + + steps: + - name: Identify + run: | + git config --global user.email "action@github.com" + git config --global user.name "${GITHUB_ACTOR}" + + - name: Checkout source + uses: actions/checkout@v6 + with: + path: source + + - name: Checkout target + uses: actions/checkout@v6 + with: + repository: codeigniter4/framework + token: ${{ secrets.ACCESS_TOKEN }} + path: framework + + - name: Chmod + run: chmod +x ./source/.github/scripts/deploy-framework + + - name: Deploy + run: ./source/.github/scripts/deploy-framework ${GITHUB_WORKSPACE}/source ${GITHUB_WORKSPACE}/framework ${GITHUB_REF##*/} + + - name: Release + uses: actions/github-script@v8 + with: + github-token: ${{secrets.ACCESS_TOKEN}} + script: | + const release = await github.rest.repos.getLatestRelease({ + owner: context.repo.owner, + repo: context.repo.repo + }) + github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: 'framework', + tag_name: release.data.tag_name, + name: release.data.name, + body: release.data.body + }) + + appstarter: + name: Deploy to appstarter + permissions: + # Allow actions/github-script to create release + contents: write + if: github.repository == 'codeigniter4/CodeIgniter4' + runs-on: ubuntu-22.04 + needs: check-version + + steps: + - name: Identify + run: | + git config --global user.email "action@github.com" + git config --global user.name "${GITHUB_ACTOR}" + + - name: Checkout source + uses: actions/checkout@v6 + with: + path: source + + - name: Checkout target + uses: actions/checkout@v6 + with: + repository: codeigniter4/appstarter + token: ${{ secrets.ACCESS_TOKEN }} + path: appstarter + + - name: Chmod + run: chmod +x ./source/.github/scripts/deploy-appstarter + + - name: Deploy + run: ./source/.github/scripts/deploy-appstarter ${GITHUB_WORKSPACE}/source ${GITHUB_WORKSPACE}/appstarter ${GITHUB_REF##*/} + + - name: Release + uses: actions/github-script@v8 + with: + github-token: ${{secrets.ACCESS_TOKEN}} + script: | + const release = await github.rest.repos.getLatestRelease({ + owner: context.repo.owner, + repo: context.repo.repo + }) + github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: 'appstarter', + tag_name: release.data.tag_name, + name: release.data.name, + body: release.data.body + }) + + userguide: + name: Deploy to userguide + permissions: + # Allow actions/github-script to create release + contents: write + if: github.repository == 'codeigniter4/CodeIgniter4' + runs-on: ubuntu-22.04 + needs: check-version + + steps: + - name: Identify + run: | + git config --global user.email "action@github.com" + git config --global user.name "${GITHUB_ACTOR}" + + - name: Checkout source + uses: actions/checkout@v6 + with: + path: source + + - name: Checkout target + uses: actions/checkout@v6 + with: + repository: codeigniter4/userguide + token: ${{ secrets.ACCESS_TOKEN }} + path: userguide + + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: '3.12' + + - name: Install Sphinx + run: | + python -m pip install --upgrade pip + pip install -r ./source/user_guide_src/requirements.txt + + - name: Chmod + run: chmod +x ./source/.github/scripts/deploy-userguide + + - name: Deploy + run: ./source/.github/scripts/deploy-userguide ${GITHUB_WORKSPACE}/source ${GITHUB_WORKSPACE}/userguide ${GITHUB_REF##*/} + + - name: Release + uses: actions/github-script@v8 + with: + github-token: ${{secrets.ACCESS_TOKEN}} + script: | + const release = await github.rest.repos.getLatestRelease({ + owner: context.repo.owner, + repo: context.repo.repo + }) + github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: 'userguide', + tag_name: release.data.tag_name, + name: release.data.name, + body: release.data.body + }) diff --git a/.github/workflows/deploy-userguide-latest.yml b/.github/workflows/deploy-userguide-latest.yml new file mode 100644 index 000000000000..8fee24da6299 --- /dev/null +++ b/.github/workflows/deploy-userguide-latest.yml @@ -0,0 +1,82 @@ +# 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 +name: Deploy User Guide (latest) + +on: + push: + branches: + - 'develop' + paths: + - 'user_guide_src/**' + +permissions: + contents: read + +jobs: + build: + name: Deploy to gh-pages + permissions: + # Allow ad-m/github-push-action to push commit to branch gh-pages + contents: write + if: (github.repository == 'codeigniter4/CodeIgniter4') + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + coverage: none + + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: '3.12' + + - name: Install Sphinx + run: | + python -m pip install --upgrade pip + pip install -r user_guide_src/requirements.txt + + # Build the latest User Guide + - name: Build Docs with Sphinx + run: make html + working-directory: user_guide_src + + - name: Add "Edit this page" links + run: | + cd user_guide_src + # Fix permissions + sudo chown -R runner:docker build/html/ + php add-edit-this-page build/html/ + + # Create an artifact of the html output + - name: Upload artifact + uses: actions/upload-artifact@v6 + 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 + + - name: Push changes + uses: ad-m/github-push-action@v1.0.0 + with: + branch: gh-pages + directory: gh-pages + github_token: ${{ secrets.ACCESS_TOKEN }} diff --git a/.github/workflows/label-add-conflict-all-pr.yml b/.github/workflows/label-add-conflict-all-pr.yml new file mode 100644 index 000000000000..16467abd161c --- /dev/null +++ b/.github/workflows/label-add-conflict-all-pr.yml @@ -0,0 +1,51 @@ +name: Auto Label "stale" for All PRs + +on: + push: + branches: + - develop + - '4.*' + +jobs: + build: + name: Check Conflicts + + permissions: + contents: read + pull-requests: write + + runs-on: ubuntu-22.04 + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Get PR List + id: PR-list + run: echo "pr_list=$(gh pr list -L 100 --json mergeable,url,labels,author)" >> $GITHUB_OUTPUT + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: 'Add label "stale" and comment' + env: + PR_LIST: ${{ steps.PR-list.outputs.pr_list }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + + IFS=$'\n' # Set Internal Field Separator to newline to handle array elements + + # Iterate through the PRs in PR_LIST + for pr in $(echo "$PR_LIST" | jq -c '.[]'); do + mergeable=$(echo "$pr" | jq -r '.mergeable') + author=$(echo "$pr" | jq -r '.author.login') + labels=$(echo "$pr" | jq -c '.labels[].name' | tr -d '[]"') + url=$(echo "$pr" | jq -r '.url') + + # CONFLICTING and no 'stale' label + if [ "$mergeable" == "CONFLICTING" ] && [[ ! "$labels" == *"stale"* ]]; then + # Add "stale" label + gh pr edit $url --add-label "stale" + + # Add a comment + gh pr comment $url --body ":wave: Hi, @$author!

We detected conflicts in your PR against the base branch :speak_no_evil:
You may want to sync :arrows_counterclockwise: your branch with upstream!

Ref: [Syncing Your Branch](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/workflow.md#updating-your-branch)" + fi + done diff --git a/.github/workflows/label-signing.yml b/.github/workflows/label-signing.yml new file mode 100644 index 000000000000..5f6b99290e89 --- /dev/null +++ b/.github/workflows/label-signing.yml @@ -0,0 +1,32 @@ +name: Check Signed PR +on: + pull_request: + branches: + - 'develop' + - '4.*' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + pull-requests: write + +jobs: + build: + name: Check Signed Commit + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Check signed commits in PR + uses: 1Password/check-signed-commits-action@v1 + with: + comment: | + You must GPG-sign your work, certifying that you either wrote the work or otherwise have the right to pass it on to an open-source project. See Developer's Certificate of Origin. See [signing][1]. + + **Note that all your commits must be signed.** If you have an unsigned commit, you can sign the previous commits by referring to [gpg-signing-old-commits][2]. + [1]: https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/pull_request.md#signing + [2]: https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/workflow.md#gpg-signing-old-commits diff --git a/.github/workflows/reusable-coveralls.yml b/.github/workflows/reusable-coveralls.yml new file mode 100644 index 000000000000..e8af4347f9f6 --- /dev/null +++ b/.github/workflows/reusable-coveralls.yml @@ -0,0 +1,76 @@ +name: Reusable Coveralls Upload + +on: + workflow_call: + inputs: + php-version: + description: The PHP version the workflow should run + type: string + required: true + +jobs: + coveralls: + runs-on: ubuntu-22.04 + + steps: + - name: Checkout base branch for PR + if: github.event_name == 'pull_request' + uses: actions/checkout@v6 + with: + ref: ${{ github.base_ref }} + + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ inputs.php-version }} + tools: composer + coverage: xdebug + + - name: Download coverage files + uses: actions/download-artifact@v7 + with: + path: build/cov + + - name: Display structure of downloaded files + run: ls -R + working-directory: build/cov + + - name: Get composer cache directory + run: | + echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV + + - name: Cache dependencies + uses: actions/cache@v5 + with: + path: ${{ env.COMPOSER_CACHE_FILES_DIR }} + key: ${{ github.job }}-php-${{ inputs.php-version }}-${{ hashFiles('**/composer.*') }} + restore-keys: | + ${{ github.job }}-php-${{ inputs.php-version }}- + ${{ github.job }}- + + - name: Cache PHPUnit's static analysis cache + uses: actions/cache@v5 + with: + path: build/.phpunit.cache/code-coverage + key: phpunit-code-coverage-${{ hashFiles('**/phpunit.*') }} + restore-keys: | + phpunit-code-coverage- + + - name: Install dependencies + run: composer update --ansi + + - name: Merge coverage files + run: | + jq '.autoload."psr-4" += {"Config\\": "app/Config/"}' composer.json > temp.json && mv temp.json composer.json + composer dump-autoload + vendor/bin/phpcov merge --clover build/logs/clover.xml build/cov + + - name: Upload coverage to Coveralls + run: | + composer global require php-coveralls/php-coveralls + php-coveralls --verbose --exclude-no-stmt --ansi + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/reusable-phpunit-test.yml b/.github/workflows/reusable-phpunit-test.yml new file mode 100644 index 000000000000..86a0d07bd228 --- /dev/null +++ b/.github/workflows/reusable-phpunit-test.yml @@ -0,0 +1,225 @@ +name: Reusable PHPUnit Test + +on: + workflow_call: + inputs: + job-name: + description: Name of the job to appear in GitHub UI + type: string + required: true + php-version: + description: The PHP version the workflow should run + type: string + required: true + job-id: + description: Job ID to be used as part of cache key and artifact name + type: string + required: false + db-platform: + description: The database platform to be tested + type: string + required: false + mysql-version: + description: Version of the mysql Docker image + type: string + required: false + group-name: + description: The @group to test + type: string + required: false + enable-artifact-upload: + description: Whether artifact uploading of coverage results should be enabled + type: boolean + required: false + enable-coverage: + description: Whether coverage should be enabled + type: boolean + required: false + enable-profiling: + description: Whether slow tests should be profiled + type: boolean + required: false + extra-extensions: + description: Additional PHP extensions that are needed to be enabled + type: string + required: false + extra-ini-options: + description: Additional PHP configuration directives that should be appended to the php.ini + type: string + required: false + extra-composer-options: + description: Additional Composer options that should be appended to the `composer update` call + type: string + required: false + extra-phpunit-options: + description: Additional PHPUnit options that should be appended to the `vendor/bin/phpunit` call + type: string + required: false + +env: + NLS_LANG: 'AMERICAN_AMERICA.UTF8' + NLS_DATE_FORMAT: 'YYYY-MM-DD HH24:MI:SS' + NLS_TIMESTAMP_FORMAT: 'YYYY-MM-DD HH24:MI:SS' + NLS_TIMESTAMP_TZ_FORMAT: 'YYYY-MM-DD HH24:MI:SS' + +jobs: + tests: + name: ${{ inputs.job-name }} + runs-on: ubuntu-22.04 + + # Service containers cannot be extracted to caller workflows yet + services: + mysql: + image: mysql:${{ inputs.mysql-version || '8.0' }} + env: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + MYSQL_DATABASE: test + ports: + - 3306:3306 + options: >- + --health-cmd="mysqladmin ping" + --health-interval=10s + --health-timeout=5s + --health-retries=3 + + postgres: + image: postgres + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: test + ports: + - 5432:5432 + options: >- + --health-cmd=pg_isready + --health-interval=10s + --health-timeout=5s + --health-retries=3 + + mssql: + image: mcr.microsoft.com/mssql/server:2022-latest + env: + MSSQL_SA_PASSWORD: 1Secure*Password1 + ACCEPT_EULA: Y + MSSQL_PID: Developer + ports: + - 1433:1433 + options: >- + --health-cmd="/opt/mssql-tools18/bin/sqlcmd -C -S 127.0.0.1 -U sa -P 1Secure*Password1 -Q 'SELECT @@VERSION'" + --health-interval=10s + --health-timeout=5s + --health-retries=3 + + oracle: + image: gvenzl/oracle-xe:21 + env: + ORACLE_RANDOM_PASSWORD: true + APP_USER: ORACLE + APP_USER_PASSWORD: ORACLE + ports: + - 1521:1521 + options: >- + --health-cmd healthcheck.sh + --health-interval 20s + --health-timeout 10s + --health-retries 10 + + redis: + image: redis + ports: + - 6379:6379 + options: >- + --health-cmd "redis-cli ping" + --health-interval=10s + --health-timeout=5s + --health-retries=3 + + memcached: + image: memcached:1.6-alpine + ports: + - 11211:11211 + + steps: + - name: Create database for MSSQL Server + if: ${{ inputs.db-platform == 'SQLSRV' }} + run: sqlcmd -S 127.0.0.1 -U sa -P 1Secure*Password1 -Q "CREATE DATABASE test COLLATE Latin1_General_100_CS_AS_SC_UTF8" + + - name: Install latest ImageMagick + if: ${{ contains(inputs.extra-extensions, 'imagick') }} + run: | + sudo apt-get update + sudo apt-get install --reinstall libgs9-common fonts-noto-mono libgs9:amd64 libijs-0.35:amd64 fonts-urw-base35 ghostscript poppler-data libjbig2dec0:amd64 libopenjp2-7:amd64 fonts-droid-fallback fonts-dejavu-core + sudo apt-get install -y gsfonts libmagickwand-dev imagemagick + sudo apt-get install --fix-broken + + - name: Checkout base branch for PR + if: github.event_name == 'pull_request' + uses: actions/checkout@v6 + with: + ref: ${{ github.base_ref }} + + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ inputs.php-version }} + tools: composer + extensions: gd, ${{ inputs.extra-extensions }} + ini-values: ${{ inputs.extra-ini-options }} + coverage: ${{ env.COVERAGE_DRIVER }} + env: + COVERAGE_DRIVER: ${{ inputs.enable-coverage && 'xdebug' || 'none' }} + + - name: Setup global environment variables + run: | + echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV + echo "ARTIFACT_NAME=${{ inputs.job-id || github.job }}-php-${{ inputs.php-version }}-db-${{ inputs.db-platform || 'none' }}" >> $GITHUB_ENV + + - name: Cache dependencies + uses: actions/cache@v5 + with: + path: ${{ env.COMPOSER_CACHE_FILES_DIR }} + key: ${{ inputs.job-id || github.job }}-php-${{ inputs.php-version }}-db-${{ inputs.db-platform || 'none' }}-${{ hashFiles('**/composer.*') }} + restore-keys: | + ${{ inputs.job-id || github.job }}-php-${{ inputs.php-version }}-db-${{ inputs.db-platform || 'none' }}- + ${{ inputs.job-id || github.job }}-php-${{ inputs.php-version }}- + ${{ inputs.job-id || github.job }}- + + - name: Cache PHPUnit's static analysis cache + if: ${{ inputs.enable-artifact-upload }} + uses: actions/cache@v5 + with: + path: build/.phpunit.cache/code-coverage + key: phpunit-code-coverage-${{ hashFiles('**/phpunit.*') }} + restore-keys: | + phpunit-code-coverage- + + - name: Install dependencies + run: | + composer config --global github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} + composer update --ansi ${{ inputs.extra-composer-options }} + + - name: Compute additional PHPUnit options + run: | + echo "EXTRA_PHPUNIT_OPTIONS=${{ format('{0} {1} {2}', env.GROUP_OPTION, env.COVERAGE_OPTION, inputs.extra-phpunit-options) }}" >> $GITHUB_ENV + env: + COVERAGE_OPTION: ${{ inputs.enable-coverage && format('--coverage-php build/cov/coverage-{0}.cov', env.ARTIFACT_NAME) || '--no-coverage' }} + GROUP_OPTION: ${{ inputs.group-name && format('--group {0}', inputs.group-name) || '' }} + + - name: Run tests + run: script -e -c "vendor/bin/phpunit --color=always ${{ env.EXTRA_PHPUNIT_OPTIONS }}" + env: + DB: ${{ inputs.db-platform }} + TACHYCARDIA_MONITOR_GA: ${{ inputs.enable-profiling && 'enabled' || '' }} + TERM: xterm-256color + + - name: Upload coverage results as artifact + if: ${{ inputs.enable-artifact-upload }} + uses: actions/upload-artifact@v6 + with: + name: ${{ env.ARTIFACT_NAME }} + path: build/cov/coverage-${{ env.ARTIFACT_NAME }}.cov + if-no-files-found: error + retention-days: 1 diff --git a/.github/workflows/reusable-serviceless-phpunit-test.yml b/.github/workflows/reusable-serviceless-phpunit-test.yml new file mode 100644 index 000000000000..bbca4fe2acc8 --- /dev/null +++ b/.github/workflows/reusable-serviceless-phpunit-test.yml @@ -0,0 +1,135 @@ +# Reusable workflow for PHPUnit testing +# without Docker services and databases +name: Reusable Serviceless PHPUnit Test + +on: + workflow_call: + inputs: + job-name: + description: Name of the job to appear in GitHub UI + type: string + required: true + php-version: + description: The PHP version the workflow should run + type: string + required: true + job-id: + description: Job ID to be used as part of cache key and artifact name + type: string + required: false + group-name: + description: The @group to test + type: string + required: false + enable-artifact-upload: + description: Whether artifact uploading of coverage results should be enabled + type: boolean + required: false + enable-coverage: + description: Whether coverage should be enabled + type: boolean + required: false + enable-profiling: + description: Whether slow tests should be profiled + type: boolean + required: false + extra-extensions: + description: Additional PHP extensions that are needed to be enabled + type: string + required: false + extra-ini-options: + description: Additional PHP configuration directives that should be appended to the php.ini + type: string + required: false + extra-composer-options: + description: Additional Composer options that should be appended to the `composer update` call + type: string + required: false + extra-phpunit-options: + description: Additional PHPUnit options that should be appended to the `vendor/bin/phpunit` call + type: string + required: false + +jobs: + tests: + name: ${{ inputs.job-name }} + runs-on: ubuntu-22.04 + + steps: + - name: Install latest ImageMagick + if: ${{ contains(inputs.extra-extensions, 'imagick') }} + run: | + sudo apt-get update + sudo apt-get install --reinstall libgs9-common fonts-noto-mono libgs9:amd64 libijs-0.35:amd64 fonts-urw-base35 ghostscript poppler-data libjbig2dec0:amd64 gsfonts libopenjp2-7:amd64 fonts-droid-fallback fonts-dejavu-core + sudo apt-get install -y imagemagick + sudo apt-get install --fix-broken + + - name: Checkout base branch for PR + if: github.event_name == 'pull_request' + uses: actions/checkout@v6 + with: + ref: ${{ github.base_ref }} + + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ inputs.php-version }} + tools: composer + extensions: gd, ${{ inputs.extra-extensions }} + ini-values: ${{ inputs.extra-ini-options }} + coverage: ${{ env.COVERAGE_DRIVER }} + env: + COVERAGE_DRIVER: ${{ inputs.enable-coverage && 'xdebug' || 'none' }} + + - name: Setup global environment variables + run: | + echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV + echo "ARTIFACT_NAME=${{ inputs.job-id || github.job }}-php-${{ inputs.php-version }}" >> $GITHUB_ENV + + - name: Cache Composer dependencies + uses: actions/cache@v5 + with: + path: ${{ env.COMPOSER_CACHE_FILES_DIR }} + key: ${{ inputs.job-id || github.job }}-php-${{ inputs.php-version }}-${{ hashFiles('**/composer.*') }} + restore-keys: | + ${{ inputs.job-id || github.job }}-php-${{ inputs.php-version }}- + ${{ inputs.job-id || github.job }}- + + - name: Cache PHPUnit's static analysis cache + if: ${{ inputs.enable-artifact-upload }} + uses: actions/cache@v5 + with: + path: build/.phpunit.cache/code-coverage + key: phpunit-code-coverage-${{ hashFiles('**/phpunit.*') }} + restore-keys: | + phpunit-code-coverage- + + - name: Install dependencies + run: | + composer config --global github-oauth.github.com ${{ secrets.GITHUB_TOKEN }} + composer update --ansi ${{ inputs.extra-composer-options }} + + - name: Compute additional PHPUnit options + run: | + echo "EXTRA_PHPUNIT_OPTIONS=${{ format('{0} {1} {2}', env.GROUP_OPTION, env.COVERAGE_OPTION, inputs.extra-phpunit-options) }}" >> $GITHUB_ENV + env: + COVERAGE_OPTION: ${{ inputs.enable-coverage && format('--coverage-php build/cov/coverage-{0}.cov', env.ARTIFACT_NAME) || '--no-coverage' }} + GROUP_OPTION: ${{ inputs.group-name && format('--group {0}', inputs.group-name) || '' }} + + - name: Run tests + run: script -e -c "vendor/bin/phpunit --color=always ${{ env.EXTRA_PHPUNIT_OPTIONS }}" + env: + TACHYCARDIA_MONITOR_GA: ${{ inputs.enable-profiling && 'enabled' || '' }} + TERM: xterm-256color + + - name: Upload coverage results as artifact + if: ${{ inputs.enable-artifact-upload }} + uses: actions/upload-artifact@v6 + with: + name: ${{ env.ARTIFACT_NAME }} + path: build/cov/coverage-${{ env.ARTIFACT_NAME }}.cov + if-no-files-found: error + retention-days: 1 diff --git a/.github/workflows/test-autoreview.yml b/.github/workflows/test-autoreview.yml new file mode 100644 index 000000000000..55300ae5eff5 --- /dev/null +++ b/.github/workflows/test-autoreview.yml @@ -0,0 +1,114 @@ +name: AutoReview + +on: + pull_request: + paths: + - composer.json + - spark + - '**.php' + - .github/workflows/test-autoreview.yml + push: + paths: + - composer.json + - spark + - '**.php' + - .github/workflows/test-autoreview.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + auto-review-tests: + name: Automatic Code Review + uses: ./.github/workflows/reusable-serviceless-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo + with: + job-name: PHP 8.1 + php-version: '8.1' + job-id: auto-review-tests + group-name: AutoReview + + composer-normalize-tests: + name: Check normalized composer.json + runs-on: ubuntu-latest + steps: + - name: Checkout base branch for PR + if: github.event_name == 'pull_request' + uses: actions/checkout@v6 + with: + ref: ${{ github.base_ref }} + + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + + - name: Install dependencies + run: composer update + + - name: Run on root composer.json + id: normalize-root-composer + if: ${{ always() }} + run: | + echo "ROOT_COMPOSER_RESULT<> $GITHUB_OUTPUT + echo "$(composer normalize)" >> $GITHUB_OUTPUT + echo "RCR" >> $GITHUB_OUTPUT + + - name: Run on framework composer.json + id: normalize-framework-composer + if: ${{ always() }} + working-directory: admin/framework + run: | + echo "FRAMEWORK_COMPOSER_RESULT<> $GITHUB_OUTPUT + echo "$(composer normalize)" >> $GITHUB_OUTPUT + echo "FCR" >> $GITHUB_OUTPUT + + - name: Run on starter composer.json + id: normalize-starter-composer + if: ${{ always() }} + working-directory: admin/starter + run: | + echo "STARTER_COMPOSER_RESULT<> $GITHUB_OUTPUT + echo "$(composer normalize)" >> $GITHUB_OUTPUT + echo "SCR" >> $GITHUB_OUTPUT + + - name: Analyse normalization results + run: | + if [[ '${{ steps.normalize-root-composer.conclusion }}' == 'failure' ]]; then + echo 'Normalization of root composer.json encountered a problem.'; + echo 'Please run it locally: `composer normalize`'; + exit 1; + fi + + if [[ ${{ contains(steps.normalize-root-composer.outputs.ROOT_COMPOSER_RESULT, 'Successfully normalized') }} == true ]]; then + echo 'Root composer.json is not yet normalized.'; + exit 1; + fi + + if [[ '${{ steps.normalize-framework-composer.conclusion }}' == 'failure' ]]; then + echo 'Normalization of framework composer.json encountered a problem.'; + echo 'Please run it locally: `composer normalize -d admin/framework`'; + exit 1; + fi + + if [[ ${{ contains(steps.normalize-framework-composer.outputs.FRAMEWORK_COMPOSER_RESULT, 'Successfully normalized') }} == true ]]; then + echo 'Framework composer.json is not yet normalized.'; + exit 1; + fi + + if [[ '${{ steps.normalize-starter-composer.conclusion }}' == 'failure' ]]; then + echo 'Normalization of starter composer.json encountered a problem.'; + echo 'Please run it locally: `composer normalize -d admin/starter`'; + exit 1; + fi + + if [[ ${{ contains(steps.normalize-starter-composer.outputs.STARTER_COMPOSER_RESULT, 'Successfully normalized') }} == true ]]; then + echo 'Starter composer.json is not yet normalized.'; + exit 1; + fi diff --git a/.github/workflows/test-coding-standards.yml b/.github/workflows/test-coding-standards.yml new file mode 100644 index 000000000000..c122f1e25b62 --- /dev/null +++ b/.github/workflows/test-coding-standards.yml @@ -0,0 +1,67 @@ +name: Coding Standards + +on: + push: + paths: + - '**.php' + - 'spark' + - '.github/workflows/test-coding-standards.yml' + pull_request: + paths: + - '**.php' + - 'spark' + - '.github/workflows/test-coding-standards.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + lint: + name: PHP ${{ matrix.php-version }} Lint with PHP CS Fixer + runs-on: ubuntu-22.04 + + strategy: + fail-fast: false + matrix: + php-version: + - '8.1' + - '8.4' + + steps: + - name: Checkout base branch for PR + if: github.event_name == 'pull_request' + uses: actions/checkout@v6 + with: + ref: ${{ github.base_ref }} + + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: tokenizer + coverage: none + + - name: Get composer cache directory + run: echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV + + - name: Cache dependencies + uses: actions/cache@v5 + with: + path: ${{ env.COMPOSER_CACHE_FILES_DIR }} + key: ${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.php-version }}- + ${{ runner.os }}- + + - name: Install dependencies + run: composer update --ansi --no-interaction + + - name: Run lint + run: composer cs diff --git a/.github/workflows/test-deptrac.yml b/.github/workflows/test-deptrac.yml new file mode 100644 index 000000000000..a301f3552d55 --- /dev/null +++ b/.github/workflows/test-deptrac.yml @@ -0,0 +1,86 @@ +# When a PR is opened or a push is made, perform an +# architectural inspection on the code using Deptrac. +name: Deptrac + +on: + pull_request: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**.php' + - 'system/**.php' + - 'composer.json' + - 'depfile.yaml' + - '.github/workflows/test-deptrac.yml' + push: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**.php' + - 'system/**.php' + - 'composer.json' + - 'depfile.yaml' + - '.github/workflows/test-deptrac.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + name: Architectural Inspection + runs-on: ubuntu-22.04 + steps: + - name: Checkout base branch for PR + if: github.event_name == 'pull_request' + uses: actions/checkout@v6 + with: + ref: ${{ github.base_ref }} + + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + tools: composer + extensions: intl, json, mbstring, gd, mysqlnd, xdebug, xml, sqlite3 + + - name: Validate composer.json + run: composer validate --strict + + - name: Get composer cache directory + run: echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV + + - name: Cache dependencies + uses: actions/cache@v5 + with: + path: ${{ env.COMPOSER_CACHE_FILES_DIR }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Create Deptrac cache directory + run: mkdir -p build/ + + - name: Cache Deptrac results + uses: actions/cache@v5 + with: + path: build + key: ${{ runner.os }}-deptrac-${{ github.sha }} + restore-keys: ${{ runner.os }}-deptrac- + + - name: Install dependencies + run: composer update --ansi --no-interaction + + - name: Run architectural inspection + run: | + composer require --dev deptrac/deptrac + vendor/bin/deptrac analyze --cache-file=build/deptrac.cache + env: + GITHUB_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test-file-permissions.yml b/.github/workflows/test-file-permissions.yml new file mode 100644 index 000000000000..c6fed8f71d1b --- /dev/null +++ b/.github/workflows/test-file-permissions.yml @@ -0,0 +1,24 @@ +name: Check File Permissions + +on: + pull_request: + push: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + permission-check: + name: Check File Permission + runs-on: ubuntu-22.04 + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Detect unnecessary execution permissions + run: php utils/check_permission_x.php diff --git a/.github/workflows/test-phpcpd.yml b/.github/workflows/test-phpcpd.yml new file mode 100644 index 000000000000..1de4c8167b9a --- /dev/null +++ b/.github/workflows/test-phpcpd.yml @@ -0,0 +1,42 @@ +# When a PR is opened or a push is made, check code +# for duplication with PHP Copy/Paste Detector. +name: PHPCPD + +on: + pull_request: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**.php' + - 'public/**.php' + - 'system/**.php' + - '.github/workflows/test-phpcpd.yml' + push: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**.php' + - 'public/**.php' + - 'system/**.php' + - '.github/workflows/test-phpcpd.yml' + +jobs: + phpcpd: + uses: codeigniter4/.github/.github/workflows/phpcpd.yml@main + with: + dirs: "app/ public/ system/" + options: >- + --exclude system/Test + --exclude system/ThirdParty + --exclude system/Database/SQLSRV/Builder.php + --exclude system/Database/SQLSRV/Forge.php + --exclude system/Database/MySQLi/Builder.php + --exclude system/Database/OCI8/Builder.php + --exclude system/Database/Postgre/Builder.php + --exclude system/Debug/Exceptions.php + --exclude system/HTTP/SiteURI.php + --exclude system/Validation/Rules.php + --exclude system/Autoloader/Autoloader.php + --exclude system/Config/Filters.php diff --git a/.github/workflows/test-phpstan.yml b/.github/workflows/test-phpstan.yml new file mode 100644 index 000000000000..5634b634d482 --- /dev/null +++ b/.github/workflows/test-phpstan.yml @@ -0,0 +1,94 @@ +# When a PR is opened or a push is made, perform +# a static analysis check on the code using PHPStan. +name: PHPStan + +on: + pull_request: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'utils/**.php' + - composer.json + - phpstan.neon.dist + - phpstan-baseline.php + - '.github/workflows/test-phpstan.yml' + + push: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'utils/**.php' + - composer.json + - phpstan.neon.dist + - phpstan-baseline.php + - '.github/workflows/test-phpstan.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + name: PHP ${{ matrix.php-versions }} Static Analysis + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + steps: + - name: Checkout base branch for PR + if: github.event_name == 'pull_request' + uses: actions/checkout@v6 + with: + ref: ${{ github.base_ref }} + + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + extensions: intl + coverage: none + + - name: Use latest Composer + run: composer self-update + + - name: Validate composer.json + run: composer validate --strict + + - name: Get composer cache directory + run: echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV + + - name: Cache dependencies + uses: actions/cache@v5 + with: + path: ${{ env.COMPOSER_CACHE_FILES_DIR }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Create PHPStan result cache directory + run: mkdir -p build/phpstan + + - name: Cache PHPStan result cache directory + uses: actions/cache@v5 + with: + path: build/phpstan + key: ${{ runner.os }}-phpstan-${{ github.sha }} + restore-keys: ${{ runner.os }}-phpstan- + + - name: Install dependencies + run: composer update --ansi --no-interaction + + - name: Run static analysis + run: composer phpstan:check diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml new file mode 100644 index 000000000000..62a8ab0e4338 --- /dev/null +++ b/.github/workflows/test-phpunit.yml @@ -0,0 +1,181 @@ +name: PHPUnit + +on: + push: + branches: + - develop + - '4.*' + paths: + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'spark' + - composer.json + - phpunit.xml.dist + - .github/workflows/test-phpunit.yml + - .github/workflows/reusable-phpunit-test.yml + + pull_request: + branches: + - develop + - '4.*' + paths: + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'spark' + - composer.json + - phpunit.xml.dist + - .github/workflows/test-phpunit.yml + - .github/workflows/reusable-phpunit-test.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + # Any environment variables set in an env context defined at the workflow level + # in the caller workflow are not propagated to the called workflow. + coverage-php-version: + name: Setup PHP Version for Code Coverage + runs-on: ubuntu-22.04 + outputs: + version: ${{ steps.coverage-php-version.outputs.version }} + steps: + - id: coverage-php-version + run: | + echo "version=8.2" >> $GITHUB_OUTPUT + + sanity-tests: + name: Others + needs: coverage-php-version + + strategy: + matrix: + php-version: + - '8.1' + - '8.2' + - '8.3' + - '8.4' + + uses: ./.github/workflows/reusable-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo + with: + job-name: Sanity Tests + php-version: ${{ matrix.php-version }} + job-id: sanity-tests + group-name: Others + enable-artifact-upload: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + enable-coverage: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + enable-profiling: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + extra-extensions: imagick, redis, memcached + extra-composer-options: ${{ matrix.composer-option }} + + database-live-tests: + name: DatabaseLive + needs: + - coverage-php-version + - sanity-tests + + strategy: + fail-fast: false + matrix: + php-version: + - '8.1' + - '8.2' + - '8.3' + - '8.4' + db-platform: + - MySQLi + - OCI8 + - Postgre + - SQLSRV + - SQLite3 + mysql-version: + - '8.0' + include: + - php-version: '8.1' + db-platform: MySQLi + mysql-version: '5.7' + + uses: ./.github/workflows/reusable-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo + with: + job-name: '' + php-version: ${{ matrix.php-version }} + job-id: database-live-tests + db-platform: ${{ matrix.db-platform }} + mysql-version: ${{ matrix.mysql-version }} + group-name: DatabaseLive + enable-artifact-upload: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + enable-coverage: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + enable-profiling: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + extra-extensions: mysqli, oci8, pgsql, sqlsrv, sqlite3 + extra-composer-options: ${{ matrix.composer-option }} + + separate-process-tests: + name: SeparateProcess + needs: + - coverage-php-version + - sanity-tests + + strategy: + matrix: + php-version: + - '8.1' + - '8.2' + - '8.3' + - '8.4' + + uses: ./.github/workflows/reusable-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo + with: + job-name: '' + php-version: ${{ matrix.php-version }} + job-id: separate-process-tests + group-name: SeparateProcess + enable-artifact-upload: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + enable-coverage: true # needs xdebug for assertHeaderEmitted() tests + enable-profiling: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + extra-extensions: mysqli, oci8, pgsql, sqlsrv-5.10.1, sqlite3 + extra-composer-options: ${{ matrix.composer-option }} + + cache-live-tests: + name: CacheLive + needs: + - coverage-php-version + - sanity-tests + + strategy: + matrix: + php-version: + - '8.1' + - '8.2' + - '8.3' + - '8.4' + + uses: ./.github/workflows/reusable-phpunit-test.yml # @TODO Extract to codeigniter4/.github repo + with: + job-name: Cache Live Tests + php-version: ${{ matrix.php-version }} + job-id: cache-live-tests + group-name: CacheLive + enable-artifact-upload: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + enable-coverage: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + enable-profiling: ${{ matrix.php-version == needs.coverage-php-version.outputs.version }} + extra-extensions: redis, memcached + extra-composer-options: ${{ matrix.composer-option }} + + coveralls: + name: Upload coverage results to Coveralls + if: github.repository_owner == 'codeigniter4' + needs: + - coverage-php-version + - sanity-tests + - cache-live-tests + - database-live-tests + - separate-process-tests + + uses: ./.github/workflows/reusable-coveralls.yml # @TODO Extract to codeigniter4/.github repo + with: + php-version: ${{ needs.coverage-php-version.outputs.version }} diff --git a/.github/workflows/test-psalm.yml b/.github/workflows/test-psalm.yml new file mode 100644 index 000000000000..a2ad9668bd91 --- /dev/null +++ b/.github/workflows/test-psalm.yml @@ -0,0 +1,72 @@ +name: Psalm + +on: + pull_request: + branches: + - develop + - '4.*' + paths: + - '**.php' + - 'composer.*' + - 'psalm*' + - '.github/workflows/test-psalm.yml' + push: + branches: + - develop + - '4.*' + paths: + - '**.php' + - 'composer.*' + - 'psalm*' + - '.github/workflows/test-psalm.yml' + +jobs: + build: + name: Psalm Analysis + runs-on: ubuntu-latest + if: (! contains(github.event.head_commit.message, '[ci skip]')) + + steps: + - name: Checkout base branch for PR + if: github.event_name == 'pull_request' + uses: actions/checkout@v6 + with: + ref: ${{ github.base_ref }} + + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + extensions: intl, json, mbstring, xml, mysqli, oci8, pgsql, sqlsrv, sqlite3 + coverage: none + env: + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Get composer cache directory + run: echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV + + - name: Cache composer dependencies + uses: actions/cache@v5 + with: + path: ${{ env.COMPOSER_CACHE_FILES_DIR }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Create Psalm cache directory + run: mkdir -p build/psalm + + - name: Cache Psalm results + uses: actions/cache@v5 + with: + path: build/psalm + key: ${{ runner.os }}-psalm-${{ github.sha }} + restore-keys: ${{ runner.os }}-psalm- + + - name: Install dependencies + run: composer update --ansi --no-interaction + + - name: Run Psalm analysis + run: utils/vendor/bin/psalm diff --git a/.github/workflows/test-rector.yml b/.github/workflows/test-rector.yml new file mode 100644 index 000000000000..72bbf8198875 --- /dev/null +++ b/.github/workflows/test-rector.yml @@ -0,0 +1,94 @@ +# When a PR is opened or a push is made, perform +# a static analysis check on the code using Rector. +name: Rector + +on: + pull_request: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'utils/**.php' + - '.github/workflows/test-rector.yml' + - composer.json + - rector.php + - '**.neon.dist' + + push: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'utils/**.php' + - '.github/workflows/test-rector.yml' + - composer.json + - rector.php + - '**.neon.dist' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + name: PHP ${{ matrix.php-versions }} Analyze code (Rector) + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + php-versions: ['8.1', '8.4'] + steps: + - name: Checkout base branch for PR + if: github.event_name == 'pull_request' + uses: actions/checkout@v6 + with: + ref: ${{ github.base_ref }} + + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: intl + + - name: Use latest Composer + run: composer self-update + + - name: Validate composer.json + run: composer validate --strict + + - name: Get composer cache directory + run: echo "COMPOSER_CACHE_FILES_DIR=$(composer config cache-files-dir)" >> $GITHUB_ENV + + - name: Cache dependencies + uses: actions/cache@v5 + with: + path: ${{ env.COMPOSER_CACHE_FILES_DIR }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer update --ansi --no-interaction + + - name: Rector Cache + uses: actions/cache@v5 + with: + path: /tmp/rector + key: ${{ runner.os }}-rector-${{ github.run_id }} + restore-keys: ${{ runner.os }}-rector- + + - run: mkdir -p /tmp/rector + + - name: Run static analysis + run: vendor/bin/rector process --dry-run --no-progress-bar diff --git a/.github/workflows/test-scss.yml b/.github/workflows/test-scss.yml new file mode 100644 index 000000000000..71ca99253872 --- /dev/null +++ b/.github/workflows/test-scss.yml @@ -0,0 +1,58 @@ +name: SCSS Compilation + +on: + pull_request: + branches: + - 'develop' + - '4.*' + paths: + - '**.scss' + - '**.css' + - '.github/workflows/test-scss.yml' + + push: + branches: + - 'develop' + - '4.*' + paths: + - '**.scss' + - '**.css' + - '.github/workflows/test-scss.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + build: + name: Compilation of SCSS (Dart Sass) + runs-on: ubuntu-22.04 + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup Node + uses: actions/setup-node@v6.0.0 + with: + # node version based on dart-sass test workflow + node-version: 16 + + - name: Install Dart Sass + run: | + npm install --global sass + sass --version + + - name: Run Dart Sass + run: sass --no-source-map admin/css/debug-toolbar/toolbar.scss system/Debug/Toolbar/Views/toolbar.css + + - name: Check for changed CSS files + run: | + if [[ -n "$(git status --porcelain 2>/dev/null)" ]]; then + echo "Your changes to the SCSS files did not match the expected CSS output." + git diff-files --patch + exit 1 + fi diff --git a/.github/workflows/test-userguide.yml b/.github/workflows/test-userguide.yml new file mode 100644 index 000000000000..0405af7cd6d7 --- /dev/null +++ b/.github/workflows/test-userguide.yml @@ -0,0 +1,44 @@ +# When a Pull Request is opened that modifies +# the User Guide source, build the User Guide +# with Sphinx and let the contributor know of +# any errors. +name: Test User Guide + +on: + pull_request: + paths: + - 'user_guide_src/**' + - '.github/workflows/test-userguide.yml' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + syntax_check: + name: Check User Guide syntax + runs-on: ubuntu-22.04 + + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Setup Python + uses: actions/setup-python@v6 + 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 diff --git a/.gitignore b/.gitignore index bafdbd3df9d4..988be09b1948 100644 --- a/.gitignore +++ b/.gitignore @@ -42,30 +42,36 @@ $RECYCLE.BIN/ # These should never be under version control, # as it poses a security risk. .env -application/.env +.vagrant +Vagrantfile #------------------------- # Temporary Files #------------------------- writable/cache/* !writable/cache/index.html -!writable/cache/.htaccess writable/logs/* !writable/logs/index.html -!writable/logs/.htaccess + +writable/session/* +!writable/session/index.html writable/uploads/* !writable/uploads/index.html -!writable/uploads/.htaccess + +writable/debugbar/* +!writable/debugbar/index.html + +writable/**/*.db +writable/**/*.sqlite + +php_errors.log #------------------------- # User Guide Temp Files #------------------------- user_guide_src/build/* -user_guide_src/cilexer/build/* -user_guide_src/cilexer/dist/* -user_guide_src/cilexer/pycilexer.egg-info/* #------------------------- # Test Files @@ -111,8 +117,13 @@ nb-configuration.xml *.stTheme.cache *.sublime-workspace *.sublime-project +.phpintel /api/ # Visual Studio Code .vscode/ +/results/ +/phpunit*.xml + +/.php-cs-fixer.php diff --git a/application/Database/Migrations/.gitkeep b/.nojekyll similarity index 100% rename from application/Database/Migrations/.gitkeep rename to .nojekyll diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 000000000000..ad6ffacb8f0c --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use CodeIgniter\CodingStandard\CodeIgniter4; +use Nexus\CsConfig\Factory; +use PhpCsFixer\Finder; + +$finder = Finder::create() + ->files() + ->in([ + __DIR__ . '/system', + __DIR__ . '/utils', + ]) + ->exclude([ + 'Pager/Views', + 'ThirdParty', + 'Validation/Views', + ]) + ->append([ + __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', + ]); + +$overrides = []; + +$options = [ + 'cacheFile' => 'build/.php-cs-fixer.cache', + 'finder' => $finder, +]; + +return Factory::create(new CodeIgniter4(), $overrides, $options)->forLibrary( + 'CodeIgniter 4 framework', + 'CodeIgniter Foundation', + 'admin@codeigniter.com', +); diff --git a/.php-cs-fixer.no-header.php b/.php-cs-fixer.no-header.php new file mode 100644 index 000000000000..f3bc97dc78ac --- /dev/null +++ b/.php-cs-fixer.no-header.php @@ -0,0 +1,39 @@ + + * + * 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__ . '/admin', + __DIR__ . '/app', + __DIR__ . '/public', + ]) + ->exclude(['Views/errors/html']) + ->append([ + __DIR__ . '/admin/starter/builds', + ]); + +$overrides = [ + 'header_comment' => false, +]; + +return $config + ->setFinder($finder) + ->setCacheFile('build/.php-cs-fixer.no-header.cache') + ->setRules(array_merge($config->getRules(), $overrides)); diff --git a/.php-cs-fixer.tests.php b/.php-cs-fixer.tests.php new file mode 100644 index 000000000000..09ea5a62c55a --- /dev/null +++ b/.php-cs-fixer.tests.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use PhpCsFixer\Config; +use PhpCsFixer\Finder; +use Utils\PhpCsFixer\CodeIgniterRuleCustomisationPolicy; + +/** @var Config $config */ +$config = require __DIR__ . '/.php-cs-fixer.dist.php'; + +$finder = Finder::create() + ->files() + ->in([ + __DIR__ . '/tests', + ]) + ->notPath([ + '_support/View/Cells/multiplier.php', + '_support/View/Cells/colors.php', + '_support/View/Cells/addition.php', + ]); + +$overrides = [ + 'phpdoc_to_return_type' => true, + 'void_return' => true, +]; + +return $config + ->setRuleCustomisationPolicy(new CodeIgniterRuleCustomisationPolicy()) + ->setFinder($finder) + ->setCacheFile('build/.php-cs-fixer.tests.cache') + ->setRules(array_merge($config->getRules(), $overrides)); diff --git a/.php-cs-fixer.user-guide.php b/.php-cs-fixer.user-guide.php new file mode 100644 index 000000000000..6b925ee8b0b7 --- /dev/null +++ b/.php-cs-fixer.user-guide.php @@ -0,0 +1,48 @@ + + * + * 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/.php_cs b/.php_cs deleted file mode 100644 index 469b8a192455..000000000000 --- a/.php_cs +++ /dev/null @@ -1,38 +0,0 @@ -exclude('ThirdParty') - ->in('system'); - -return Symfony\CS\Config\Config::create() - ->level(Symfony\CS\FixerInterface::PSR1_LEVEL) - ->fixers(array( - 'class_definition', - 'eof_ending', - 'function_call_space', - 'linefeed', - 'lowercase_constants', - 'lowercase_keywords', - 'method_argument_space', - 'no_trailing_whitespace_in_comment', - 'parenthesis', - 'php_closing_tag', - 'trailing_spaces', - 'visibility', - 'array_element_no_space_before_comma', - 'array_element_white_space_after_comma', - 'concat_without_spaces', - 'include', - 'operators_spaces', - 'spaces_before_semicolon', - 'ternary_spaces', - 'unary_operators_spaces', - 'spaces_cast', - 'whitespacy_lines', - 'align_double_arrow', - 'align_equals', - 'logical_not_operators_with_spaces', - 'logical_not_operators_with_successor_space', - 'multiline_spaces_before_semicolon', - )) - ->finder($finder); diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1189c5b9bfd0..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,35 +0,0 @@ -language: php - -php: - - 7 - - 7.1 - -global: - - CI=true - - CI_ENV=testing - -# Recommended by Travis support -sudo: required -dist: precise - -env: - - DB=mysqli - - DB=postgres - -services: - - mysql - - postgresql - -script: - - php vendor/bin/phpunit -v - -before_install: - - mysql -e "create database IF NOT EXISTS test;" -uroot; - - mysql -e "SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = 'test';" -uroot - - psql -c 'create database test;' -U postgres - -before_script: - - composer install --prefer-source - -after_success: - - travis_retry php vendor/bin/coveralls diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000000..f1e51255081e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,850 @@ +# Changelog + +## [v4.6.4](https://github.com/codeigniter4/CodeIgniter4/tree/v4.6.4) (2025-12-12) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.6.3...v4.6.4) + +### Fixed Bugs + +* fix: prevent non-shared DB instances from polluting shared cache by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9679 +* fix: `Connection::getFieldData()` default value convention for `SQLSRV` and `OCI8` by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9680 +* fix: `Forge::modifyColumn()` for Postgre handler by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9676 +* fix: setting `created_at` field in `Model::replace()` method by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9693 +* fix: Casting in insertBatch and updateBatch methods. by @patel-vansh in https://github.com/codeigniter4/CodeIgniter4/pull/9698 +* fix: `compileOrderBy()` method by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9697 +* fix: SQLite3 password handling for empty string by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9729 +* fix: TypeError in `valid_base64` rule when checking invalid base64 strings by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9733 +* fix: debug toolbar logs collector behavior on `isEmpty()` by @mjomble in https://github.com/codeigniter4/CodeIgniter4/pull/9724 +* fix: crash in `toggleViewsHints` - `debugDiv.appendChild` (`toolbar.js`) by @mjomble in https://github.com/codeigniter4/CodeIgniter4/pull/9735 +* fix: cannot read properties of null in `toggleViewsHints` (`toolbar.js`) by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9736 +* fix: type error in controlled cell by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9784 +* fix: handle resources and closures in JSON exception responses by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9788 +* fix: quote reserved keyword `timestamp` used as a field name for session table by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9805 +* fix: Add an IDs for toolbar form fields by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9823 +* fix: disable echo in the preload file by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9825 +* fix(cache): prevent Redis error when `deleteMatching()` finds no keys by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9829 + +### Refactoring + +* refactor: change `$request` to `CLIRequest|IncomingRequest` in `ResponseTrait` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9658 +* refactor: fix phpdoc and improve code in `Language` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9656 +* refactor: remove redundant property declarations in `BaseController` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9659 +* refactor: update `CheckPhpIni` code by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9672 +* refactor: Improve types for phpstan by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9685 +* refactor: fix phpstan issues on magic properties by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9728 +* refactor: use `superglobals` service in the `UserAgent` class by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9783 + +## [v4.6.3](https://github.com/codeigniter4/CodeIgniter4/tree/v4.6.3) (2025-08-02) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.6.2...v4.6.3) + +### Fixed Bugs + +* fix: CID check in Email class by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9645 +* fix: SMTP connection resource validation in `Email` class destructor by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9648 + +### Refactoring + +* refactor: update preload script to exclude `util_bootstrap` by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9649 +* refactor: phpdoc for `Config\Filters::$globals` by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9652 + +## [v4.6.2](https://github.com/codeigniter4/CodeIgniter4/tree/v4.6.2) (2025-07-26) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.6.1...v4.6.2) + +### Security + +* **ImageMagickHandler**: *Command Injection Vulnerability in ImageMagick Handler* + Fixes a vulnerability relating to uses of `ImageMagickHandler`'s `resize()` or `text()` methods + where an attacker can upload malicious filenames containing shell metacharacters that get executed when + the image is processed or when text is added to the image. + + See the [security advisory](https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-9952-gv64-x94c) + for details. Credits to @vicevirus for reporting the issue. + +### Fixed Bugs + +* chore: add missing EscaperInterface to the AutoloadConfig by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9561 +* fix: remove service dependency from sanitize_filename() helper function by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9560 +* fix: use native PHP truthiness for condition evaluation in when()/whenNot() by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9576 +* fix: add error handling for corrupted cache files in `FileHandler` by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9586 +* fix: correct `getHostname()` fallback logic in `Email` class by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9587 +* fix: encapsulation violation in `BasePreparedQuery` class by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9603 +* fix: URI authority generation for schemes without default ports by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9605 +* fix: correct path parsing in `SiteURIFactory::parseRequestURI()` by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9613 +* fix: support for multibyte folder names when the app is served from a subfolder by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9615 +* fix: use correct 24-hour time format in development error page. by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/9628 +* fix: improve CURLRequest intermediate HTTP response handling by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9627 +* fix: ensure `make:test` works on Windows by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9635 +* fix: ensure `make:test` generates test files ending in `Test` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9636 +* fix: `make:test` requires 3 inputs after entering an empty class name by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9637 +* fix: add filename parameters to inline Content-Disposition headers by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9638 + +### Refactoring + +* refactor: add `system/util_bootstrap.php` to curb overreliance to `system/Test/bootstrap.php` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9562 +* refactor: update places to use `system/util_bootstrap.php` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9568 +* refactor: more accurate array PHPDocs of Cookie by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9569 +* refactor: use native phpdocs wherever possible by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9571 +* refactor: fix `notIdentical.alwaysTrue` error by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9579 +* refactor: fix phpstan errors in `Events` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9580 +* refactor: fix non-booleans in if conditions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9578 +* refactor: fix and micro-optimize code in `Format` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9583 +* refactor: fix various phpstan errors in Log component by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9581 +* refactor: partial fix errors on Email by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9582 +* refactor: fix phpstan errors in `ResponseTrait` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9591 +* refactor: precise PHPDocs for Autoloader by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9593 +* refactor: fix phpstan errors in mock classes by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9594 +* refactor: fix various phpstan errors in Cache by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9610 +* fix: apply rector rule TernaryImplodeToImplodeRector by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9614 +* refactor: `Console::showHeader()` call `date()` only once by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9616 + +## [v4.6.1](https://github.com/codeigniter4/CodeIgniter4/tree/v4.6.1) (2025-05-02) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.6.0...v4.6.1) + +### Fixed Bugs + +* fix(CURLRequest): multiple header sections after redirects by @ducng99 in https://github.com/codeigniter4/CodeIgniter4/pull/9426 +* fix: set headers for CORS by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9437 +* fix: upsert with composite unique index by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9454 +* fix: `getVersion()` for OCI8 and SQLSRV drivers by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9471 +* fix: Toolbar when `maxHistory` is set to `0` by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9506 +* fix: `Session::markAsTempdata()` adding wrong TTL by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9536 +* fix: added "application/octet-stream" to the "stl" mime type in the M… by @Franky5831 in https://github.com/codeigniter4/CodeIgniter4/pull/9543 + +### Refactoring + +* refactor: get upper first protocol only one call in Email by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9449 +* refactor: PHPDocs in `env()` by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9468 +* refactor: remove lowercase event name for logging by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9483 +* refactor: OCI8 `limit()` method by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9472 +* refactor: deprecate redundant `FileHandler` cache methods by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9511 +* refactor: fix `variable.undefined` (and other) errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9513 +* refactor: fix `return.unusedType` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9514 +* refactor: add `CITestStreamFilter` to phpstan-analysed list and fix errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9515 +* refactor: fix `property.protected` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9517 +* refactor: fix `function.alreadyNarrowedType` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9518 +* refactor: fix `empty.property` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9519 +* refactor: import FQCNs by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9520 +* refactor: fix `isset.property` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9522 +* refactor: fix `missingType.return` errors by @warcooft in https://github.com/codeigniter4/CodeIgniter4/pull/9523 +* refactor: fix `nullCoalesce.variable` errors by @warcooft in https://github.com/codeigniter4/CodeIgniter4/pull/9524 +* refactor: fix phpstan errors in `URI` and `SiteURI` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9525 +* refactor: fix `@readonly` property errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9529 +* refactor: fix `missingType.return` errors in system files by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9530 +* refactor: fix `codeigniter.modelArgumentType` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9533 +* refactor: fix `Session` and `SessionInterface` code by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9535 + +## [v4.6.0](https://github.com/codeigniter4/CodeIgniter4/tree/v4.6.0) (2025-01-19) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.8...v4.6.0) + +### Breaking Changes + +* refactor: remove deprecated failValidationError() in API\ResponseTrait by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8793 +* refactor: remove depreacted ResponseInterface::getReason() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8841 +* refactor: remove deprecated Logger::cleanFilenames() and TestLogger::cleanup() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8843 +* fix: Exception rework by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8728 +* fix: DefinedRouteCollector to use RouteCollectionInterface by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8911 +* fix: View::renderSection() return type by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8965 +* feat: [Filters] enables a filter to run more than once with different arguments by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8977 +* fix: add check for duplicate Registrar Auto-Discovery runs by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9073 +* fix: Time loses microseconds by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9081 +* feat: fix spark db:table causes errors with table name including special chars by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8748 +* [4.6] fix: Time::createFromTimestamp() change for PHP 8.4 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9105 +* fix: Time::setTimestamp()'s different behavior than DateTime by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9106 +* [4.6] fix: inconsistency in detailed error reporting by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9144 +* [4.6] feat: force PHP default 32 chars length at 4 bits to Session ID by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9139 +* fix: prioritize headers set by the `Response` class by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9235 + +### Fixed Bugs + +* [4.6] fix: add validation message for min_dims by @christianberkman in https://github.com/codeigniter4/CodeIgniter4/pull/8988 +* fix: [Filters] normalize `$filters` arguments by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8994 +### Enhancements +* feat: [FileCollection] add function to reatain multiple patterns by @christianberkman in https://github.com/codeigniter4/CodeIgniter4/pull/8960 +* feat: [Validation] add `min_dims` rule in FileRules by @christianberkman in https://github.com/codeigniter4/CodeIgniter4/pull/8966 +* feat: add `foundRows` option for MySQLi config by @ducng99 in https://github.com/codeigniter4/CodeIgniter4/pull/8979 +* feat: `spark filter:check` shows filter classnames by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8985 +* feat: add BaseConnection::resetTransStatus() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8767 +* feat: add Services::resetServicesCache() to reset services cache by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9012 +* feat: add "400 Bad Request" page for end users by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9044 +* feat: add directives to `phpini:check` command by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9117 +* feat: multiple hostname routing by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9150 +* [4.6] feat: workaround for implicit nullable deprecations in PHP 8.4 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9140 +* feat: support CURL HTTP3 by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9145 +* feat: design info environment top in `error_exception` by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9241 +* feat: [Validation] add support for `$dbGroup` as parameter in `is_unique` and `is_not_unique` by @maniaba in https://github.com/codeigniter4/CodeIgniter4/pull/9216 +* feat: added the `namespace` option to the `publish` command by @dimtrovich in https://github.com/codeigniter4/CodeIgniter4/pull/9278 +* chore: update `Kint` to v6.0 by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9289 +* feat: CURL option `force_ip_resolve` by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9194 +* feat: add SQLite3 config synchronous by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9202 +* feat: Differentiate between kilobyte/kibibyte and megabyte/mebibyte by @ThomasMeschke in https://github.com/codeigniter4/CodeIgniter4/pull/9277 +* feat: Strict locale negotiation by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9360 +* fix: Add support for multibyte strings by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9372 +* feat: add page start end total to `PagerRenderer` by @murilohpucci in https://github.com/codeigniter4/CodeIgniter4/pull/9371 +* feat: New command `lang:sync` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9023 +* feat: additional `opcache` setting in check php.ini by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9032 + +### Refactoring + +* [4.6] refactor: Validation rules and tests by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8975 +* [4.6] refactor: add `: void` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9013 +* refactor: remove dependency on BaseConnection in TableName by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9104 +* refactor: add return type to closuer in FilterCheck by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9190 +* refactor: Remove deprecated `RedirectException` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9399 +* refactor: Remove deprecated `EVENT_PRIORITY_*` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9401 +* refactor: Remove deprecated `View::$currentSection` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9403 +* refactor: Remove deprecated `Cache::$storePath` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9404 +* refactor: Remove deprecated `Config\Format::getFormatter()` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9405 +* refactor: Remove deprecation related to cookies by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9406 + +## [v4.5.8](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.8) (2025-01-19) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.7...v4.5.8) + +### Security + +* **HTTP** *Validation of header name and value*: Fixed a potential vulnerability on lack of proper header validation + for its name and value. See the [security advisory](https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-x5mq-jjr3-vmx6) + for more information. Credits to @neznaika0 for reporting. +* **Security** fix: ensure csrf token is string by @datlechin in https://github.com/codeigniter4/CodeIgniter4/pull/9365 + +### Fixed Bugs + +* fix: gather affected rows after query call failed by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9363 + +### Refactoring + +* refactor: use more strict result check on preg_match_all() result by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9361 +* refactor: Fix phpstan if.condNotBoolean by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9368 +* refactor: Fix phpstan when delete string key by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9369 +* refactor: Fix phpstan greaterOrEqual.invalid by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9370 +* refactor: Fix phpstan nullCoalesce by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9374 +* refactor: Fix phpstan isset offset by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9383 +* refactor: Fix phpstan return.missing by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9382 +* refactor: Fix phpstan booleanAnd.rightAlwaysTrue by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9367 +* refactor: Fix phpstan codeigniter.configArgumentInstanceof by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9390 +* refactor: Use `strtolower` with `str_contains`/`str_**_with` as replacement for `stripos` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9414 + +## [v4.5.7](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.7) (2024-12-31) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.6...v4.5.7) + +### Fixed Bugs + +* fix: handle namespaced helper found on Common helper by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9354 +* fix: `Forge::dropColumn()` always returns `false` on SQLite3 driver by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9351 + +### Refactoring + +* refactor: enable AddArrowFunctionReturnTypeRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9343 + +## [v4.5.6](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.6) (2024-12-28) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.5...v4.5.6) + +### Fixed Bugs + +* fix: auto_link() converts invalid strings like `://codeigniter.com` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9180 +* fix: change session start log level by @element-code in https://github.com/codeigniter4/CodeIgniter4/pull/9221 +* fix: `getValidated()` when validation multiple asterisk by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9220 +* fix: Parser - Equal key name replace conflict by @CosDiabos in https://github.com/codeigniter4/CodeIgniter4/pull/9246 +* fix: case-insensitivity in the `like()` method when in use with accented characters by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9238 +* fix: TypeError for routes when translateURIDashes is enabled by @maniaba in https://github.com/codeigniter4/CodeIgniter4/pull/9209 +* fix: `fetchGlobal()` with numeric key by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9251 +* fix: curl request crashes with params that give an int once hexed. by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/9198 +* docs: allow boolean values in the model for PHPStan by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/9276 +* fix: respect complex language strings when using validation by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9201 +* fix: `DownloadResponse` cache headers by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9237 +* docs: fix `@param` `ResponseInterface::setJSON()` also accepts objects by @JulianAtkins in https://github.com/codeigniter4/CodeIgniter4/pull/9287 +* fix: [CURLRequest] body contains "HTTP/1.0 200 Connection established" by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/9285 +* fix: `Postgre\Connection::reconnect()` `TypeError` in `pg_ping()` by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/9279 +* fix: primary key mapping in the model for the entity by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9307 +* fix: check if defined `WRITEPATH` exists by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9317 +* fix: handling binary data for prepared statement by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/9337 + +### Refactoring + +* refactor: enable TypedPropertyFromAssignsRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9184 +* refactor: enable ClosureReturnTypeRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9187 +* refactor: remove unnecessary `is_countable()` check in `getMethodParams()` by @datamweb in https://github.com/codeigniter4/CodeIgniter4/pull/9206 +* refactor: add more readonly property definitions on AutoRouteCollector and SiteURI by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9210 +* refactor: starter key handling in SodiumHandler by @datamweb in https://github.com/codeigniter4/CodeIgniter4/pull/9207 +* refactor: enable rector code quality level 14 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9232 +* refactor: cleanup `DatabaseHandler::gc()` for session by @grimpirate in https://github.com/codeigniter4/CodeIgniter4/pull/9230 +* refactor: enable rector code quality level 15 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9243 +* refactor: enable SimplifyBoolIdenticalTrueRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9244 +* refactor: enable FlipTypeControlToUseExclusiveTypeRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9253 +* refactor: flip assert and actual value position on tests by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9260 +* perf: Improve call as `service()` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9248 +* refactor: use compare empty array on Forge on keys property by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9267 +* refactor: Fix `phpstan` errors related to `Autoloader` by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/9249 +* refactor: use `Superglobals` in setting 'REQUEST_METHOD' in `FeatureT… by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9294 +* refactor: use `baseURI` instead of `base_uri` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9296 +* refactor: Apply code quality level 31 for rector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9303 +* refactor: rename `stdclass` to `stdClass` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9312 +* refactor: fix `phpDoc.parseError` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9313 +* refactor: fix `method.nameCase` errors by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9315 +* refactor: rename `controller` to `Controller` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9314 +* refactor: fix implicit array creation by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9316 +* refactor: follow up implicit variable array by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/9319 +* refactor: split phpstan-baseline into smaller files by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9299 +* refactor: upgrade to use phpstan 2 and rector 2 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9322 +* refactor: fix `Forge::processIndexes()` for empty `$this->fields` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9330 +* refactor: `Reflection*::setAccessible()` is now no-op in PHP 8.1 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9331 +* refactor: add `@throws RedirectException` in `Controller::initController` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9327 +* refactor: fix warning on new static usage by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9342 +* refactor: fix used void return type by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9341 +* refactor: enable instanceof and strictBooleans rector set by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9339 + +## [v4.5.5](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.5) (2024-09-07) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.4...v4.5.5) + +### Fixed Bugs + +* fix: Validation rule `differs`/`matches` with dot array by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9103 +* fix: update preload.php by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9111 +* fix: [Validation] TypeError when using numeric field names by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9142 +* fix: `auto_link()` regexp by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9169 + +### Refactoring + +* refactor: reduce_multiples() and fix user guide by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9099 +* refactor: enable AddMethodCallBasedStrictParamTypeRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9156 +* refactor: BaseBuilder by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9157 +* refactor: improve error message for missing PHP DB extensions by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9160 +* refactor: fix typo in BaseConnection.php by @ThomasMeschke in https://github.com/codeigniter4/CodeIgniter4/pull/9170 + +## [v4.5.4](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.4) (2024-07-27) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.3...v4.5.4) + +### Fixed Bugs + +* fix: [OCI8] Easy Connect string validation by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9006 +* fix: [QueryBuilder] select() with RawSql may cause TypeError by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9009 +* fix: [QueryBuilder] `select()` does not escape after `NULL` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9010 +* fix: allow string as parameter to CURLRequest version by @tangix in https://github.com/codeigniter4/CodeIgniter4/pull/9021 +* fix: `spark phpini:check` may cause TypeError by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9026 +* fix: Prevent invalid session handlers by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9036 +* fix: DebugBar CSS for daisyUI by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9046 +* docs: `referrer` is undefined by @totoprayogo1916 in https://github.com/codeigniter4/CodeIgniter4/pull/9059 +* fix: filters passed to the ``$routes->group()`` are not merged into the filters passed to the inner routes by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/9064 + +### Refactoring + +* refactor: use first class callable on function call by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9004 +* refactor: enable AddClosureVoidReturnTypeWhereNoReturnRector to add void return on closure by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9008 +* refactor: enable AddFunctionVoidReturnTypeWhereNoReturnRector to add void to functions by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9014 +* refactor: Enable phpunit 10 attribute Rector rules by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/9015 +* refactor: fix `Throttler::check()` $tokens by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/9067 + +## [v4.5.3](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.3) (2024-06-25) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.2...v4.5.3) + +### Fixed Bugs + +* fix: `RedisHandler::deleteMatching()` not deleting matching keys if cache prefix is used by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8952 +* fix: TypeError in DefinedRouteCollector::collect() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8957 +* fix: `migrate:rollback -b` does not work due to TypeError by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8958 +* fix: [Validation] `if_exist` does not work with array data by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8959 +* chore: add `Config` namespace to appstarter autoload.psr4 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8963 +* fix: `spark routes` may show BadRequestException when a route has a regexp by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8974 +* docs: fix incorrect description for route group filter by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8978 +* fix: return and param types of BaseConnection by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8983 +* fix: precedence of command classes with the same `$name` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8898 +* fix: [OCI8] if conditions to build DSN by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8986 +* fix: [Auto Routing Improved] Default Method Fallback does not work with `$translateUriToCamelCase` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8980 +* fix: `command()` may execute `rewrite.php` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8995 + +### Refactoring + +* refactor: BaseBuilder::orderBy() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8970 +* refactor: using phpunit 10 assertObjectHasNotProperty() and assertObjectHasProperty() by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/8991 + +## [v4.5.2](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.2) (2024-06-10) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.1...v4.5.2) + +### Fixed Bugs + +* chore: fix phpunit.xml.dist for appstarter by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8785 +* fix: update `preload.php` for 4.5 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8805 +* fix: [ErrorException] Undefined array key in `spark phpini:check` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8804 +* fix: incorrect Security exception message by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8818 +* fix: [QueryBuilder] TypeError in join() with BETWEEN by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8792 +* fix: [SQLSRV] Query Builder always sets `""."".` to the table name. by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/8786 +* fix: remove unused undefined param $raw in MockCache::save() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8847 +* fix: FileCollection pseudo-regex by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8868 +* fix: [Model] casting may throw InvalidArgumentException: Invalid parameter: nullable by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8870 +* fix: [Model] casting causes TypeError when finding no record by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8871 +* fix: correct property default values in Email by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8855 +* fix: CLI::promptByMultipleKeys() and prompt() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8873 +* fix: [Postgres] show missing error message by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8913 +* fix: TypeError in number_to_amount() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8932 +* fix: Model::find() returns incorrect data with casting by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8933 + +### Refactoring + +* refactor: remove unused path parameter on PhpStreamWrapper::stream_open() by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/8926 + +## [v4.5.1](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.1) (2024-04-14) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.5.0...v4.5.1) + +### Fixed Bugs + +* fix: TypeError in form() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8736 +* fix: [DebugBar] TypeError in Toolbar by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8727 +* fix: TypeError when Time is passed to Model by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8738 +* docs: added Config\Feature::$oldFilterOrder to app/Config/Feature.php… by @mullernato in https://github.com/codeigniter4/CodeIgniter4/pull/8749 +* fix: Factories::get() cannot get defined classes by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8744 +* fix: `BaseConnection::escape()` does not accept Stringable by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8756 +* fix: [CURLRequest] `getHeaderLine('Content-Type')` causes InvalidArgumentException by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8760 +* fix: [CURLRequest] construct param $config is not used by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8761 +* fix: [FileLocator] Cannot declare class XXX, because the name is already in use by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8745 +* fix: [DebugBar] Toolbar display may be broken by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8772 +* fix: Cannot declare class CodeIgniter\Config\Services, because the name is already in use by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8776 +* docs: fix Postgre DSN sample by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8774 + +### Refactoring + +* test: refactor Config/Registrar.php by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8731 +* test: add return void by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8746 +* refactor: system/CLI/BaseCommand.php by @mcsaygili in https://github.com/codeigniter4/CodeIgniter4/pull/8741 +* refactor: system/View/Plugins.php by @mcsaygili in https://github.com/codeigniter4/CodeIgniter4/pull/8742 +* refactor: fix method name `ValidationErrors` in View\Plugins by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8758 +* refactor: system/Debug/Toolbar/Collectors/Routes.php by @mcsaygili in https://github.com/codeigniter4/CodeIgniter4/pull/8751 +* refactor: improve error message in BaseExceptionHandler by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8766 +* refactor: FabricatorModel by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8770 + +## [v4.5.0](https://github.com/codeigniter4/CodeIgniter4/tree/v4.5.0) (2024-04-07) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.8...v4.5.0) + +### Breaking Changes + +* refactor: always use multiple filters by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7903 +* fix: update psr/log to v2 and fix Logger interface by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7967 +* fix: incorrect return type for Model::objectToRawArray() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7986 +* fix: filter exec order by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7955 +* refactor: Remove deprecated Config\Config by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8016 +* fix: `FileLocator::findQualifiedNameFromPath()` behavior by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8010 +* refactor: remove deprecated methods in Model by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8032 +* fix: route options are not merged (outer filter is merged with inner filter) by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8033 +* fix: route options are not merged (inner filter overrides outer filter) by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7981 +* feat: FileLocator caching by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8017 +* refactor: remove deprecated properties and methods in CodeIgniter class by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8050 +* fix: make Factories final by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8056 +* refactor: remove deprecated test classes by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8057 +* refactor: make IncomingRequest::$uri protected by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8067 +* refactor: remove deprecated spark commands by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8086 +* refactor: remove deprecated Request::isValidIP() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8090 +* fix: set_cookie() $expire type by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8080 +* fix: remove traditional validation rule param types (1/2) by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8078 +* fix: filters are executed when controller does not exist with Auto Routing (Legacy). by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/7925 +* fix: remove traditional validation rule param types (2/2) by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8124 +* refactor: remove deprecated ModelFactory by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8139 +* refactor: remove deprecated properties in Response by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8142 +* fix: remove deprecated upper functionality in `Request::getMethod()` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8186 +* feat: new Required Filters by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8053 +* refactor: remove deprecated CastException exception by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8469 +* refactor: remove deprecated MockSecurityConfig by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8472 +* refactor: remove deprecated CodeIgniter\Entity by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8497 +* refactor: remove deprecated Cache\Exceptions\ExceptionInterface by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8498 +* fix: API\ResponseTrait can't return string as JSON by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8490 +* feat: Validation::run() accepts DB connection by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8499 +* feat: 404 Override sets 404 by default by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8535 +* refactor: remove deprecated const SPARKED by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8559 +* refactor: remove deprecated BaseService::discoverServices() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8589 +* fix: move Kint loading to Autoloader by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8603 +* feat: add Boot class by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8604 + +### Fixed Bugs + +* fix: error on `Config\Kint` with Config Caching by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8003 +* fix: route key lowercase HTTP verbs by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8235 +* fix: use `addHeader()` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8240 +* fix: QueryBuilder limit(0) bug by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8280 +* fix: SQLite3 may not throw DatabaseException by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8467 +* [4.5] fix: DEBUG-VIEW comments are not output by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8523 +* [4.5] fix: $db->dateFormat merge by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8539 +* [4.5] fix: spark does not work with composer install --no-dev by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8534 +* [4.5] fix: Composer autoload.psr4 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8569 +* [4.5] fix: errors when not updating Config\Feature by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8570 +* [4.5] fix: TypeError in Filters by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8683 + +### New Features + +* feat: Language translations finder and update by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/7896 + +### Enhancements + +* feat: domparser - ability to write more advanced expressions by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/7946 +* feat: [Validation] Callable Rules by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7933 +* perf: autoloader by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8005 +* feat: db:table shows db config by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7972 +* feat: add `{memory_usage}` replacement by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8008 +* perf: replace $locator->getClassname() with findQualifiedNameFromPath() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8012 +* feat: add Method/Route logging in exceptionHandler() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8108 +* feat: add `config:check` command to check Config vaules by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8110 +* feat: one generator command could have multiple views by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8119 +* feat: improve CLI input testability by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7978 +* feat: add ArrayHelper::dotKeyExists() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8131 +* feat: add CSP clearDirective() to clear existing directive by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8220 +* feat: [Validation] add `field_exists` rule by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8123 +* feat: add Message::addHeader() to add header with the same name by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8194 +* feat: `spark filter:check` shows "Required Filters" by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8236 +* feat: [Commands] `lang:find` show bad keys when scanning (v2) by @neznaika0 in https://github.com/codeigniter4/CodeIgniter4/pull/8285 +* feat: add `--dbgroup` option to `spark db:table` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8292 +* feat: [Auto Routing Improved] add option to translate uri to camel case by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8321 +* feat: `spark routes` shows "Required Filters" by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8237 +* feat: HTTP method-aware web page caching by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8364 +* feat: `spark make:test` creates test files in `/tests/` directory v2 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8388 +* feat: [Routing] add option to pass multiple URI segments to one Controller parameter by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8348 +* feat: add DataConverter to convert types by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8230 +* feat: [Model] add option $updateOnlyChanged by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8455 +* feat: add event points for spark commands by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8496 +* feat: 404 controller also can get PageNotFoundException message by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8491 +* feat: add DB config `dateFormat` to provide default date/time formats by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8525 +* feat: use $db->dateFormat in Model by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8538 +* feat: permit __invoke() method as Controller default method by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8533 +* feat: add Model field casting by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8243 +* feat: add spark command to check php.ini by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8581 +* feat: improve Redis Session by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8578 +* feat: add Config\Optimize by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8605 +* feat: support database name with dots by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8664 +* feat: add `spark optimize` command by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8610 +* feat: add CORS filter by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8649 +* feat: Support faker modifiers on Fabricator by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8671 +* feat: environment-specific Config\Security::$redirect by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8673 +* feat: `spark config:check` detects Config Caching by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8711 + +### Refactoring + +* Drop PHP 7.4 support by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7924 +* [4.5] refactor: remove unused `use` in Model by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8045 +* [4.5] refactor: remove BaseModel assert() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8046 +* [4.5] refactor: Filters by rector by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8071 +* perf: defer instantiation of Validation in Model by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8087 +* refactor: fix types by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8091 +* refactor: move ArrayHelper class by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8130 +* [4.5] refactor: fix types by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8138 +* refactor: fix param types by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8175 +* refactor: Validation rule field_exists by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8242 +* refactor: `TestResponse` is now a class of its own by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8264 +* refactor: fix TypeError in strict mode by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8270 +* refactor: add `declare(strict_types=1)` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8072 +* refactor: remove deprecated Controller::loadHelpers() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8286 +* refactor: remove deprecated methods in Security by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8287 +* refactor: HTTP verbs in Router by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8317 +* refactor: remove unused exception classes by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8468 +* [4.5] refactor: add `declare(strict_types=1)` to ForgeModifyColumnTest by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8502 +* [4.5] refactor: use local variables in Model by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8565 +* refactor: remove unnecessary BaseService::$services assignment by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8609 +* perf: add Factories::get() v2 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8600 +* perf: add Services::get() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8607 +* refactor: remove deprecated items in Request by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8617 +* refactor: followup performance `service()` by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/8623 +* [4.5] refactor: add declare(strict_types=1) in BadRequestException by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8682 +* refactor: DB config properties by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8693 +* refactor: upgrade to PHP 8.1 with rector by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8354 +* refactor: update PHPUnit to 10 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8069 + +## [v4.4.8](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.8) (2024-04-07) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.7...v4.4.8) + +### Fixed Bugs + +* fix: [ImageMagickHandler] early terminate processing of invalid library path by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8680 +* docs: fix PHPDoc types in BaseModel by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8679 +* fix: the error view is determined by Exception code by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8689 +* fix: `Pager::only([])` does not work by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8702 +* refactor: remove unneeded code in SQLite3\Table and fix PHPDoc types in Database by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8703 +* docs: fix return type in BaseResult by @Pebryan354 in https://github.com/codeigniter4/CodeIgniter4/pull/8709 + +### Refactoring + +* refactor: simplify ImageMagickHandler::getVersion() by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8681 +* refactor: [Rector] Apply ExplicitBoolCompareRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/8704 + +## [v4.4.7](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.7) (2024-03-29) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.6...v4.4.7) + +### SECURITY + +* **Language:** *Language class DoS Vulnerability* was fixed. See the + [Security advisory](https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-39fp-mqmm-gxj6) + for more information. +* **URI Security:** The feature to check if URIs do not contain not permitted + strings has been added. This check is equivalent to the URI Security found in + CodeIgniter 3. This is enabled by default, but upgraded users need to add + a setting to enable it. +* **Filters:** A bug where URI paths processed by Filters were not URL-decoded + has been fixed. + +### Breaking Changes +* fix: Time::difference() DST bug by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8661 + +### Fixed Bugs +* fix: [Validation] FileRules cause error if getimagesize() returns false by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8592 +* fix: isWriteType() to recognize CTE; always excluding RETURNING by @markconnellypro in https://github.com/codeigniter4/CodeIgniter4/pull/8599 +* fix: duplicate Cache-Control header with Session by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8601 +* fix: [DebugBar] scroll to top by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/8595 +* fix: Model::shouldUpdate() logic by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8614 +* fix: esc() for 'raw' context by @Cleric-K in https://github.com/codeigniter4/CodeIgniter4/pull/8633 +* docs: fix incorrect CURLRequest allow_redirects description by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8653 +* fix: Model::set() does not accept object by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8670 + +### Refactoring +* refactor: replace PHP_VERSION by PHP_VERSION_ID by @justbyitself in https://github.com/codeigniter4/CodeIgniter4/pull/8618 +* refactor: apply early return pattern by @justbyitself in https://github.com/codeigniter4/CodeIgniter4/pull/8621 +* refactor: move footer info to top in error_exception.php by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8626 + +## [v4.4.6](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.6) (2024-02-24) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.5...v4.4.6) + +### Breaking Changes + +* fix: Time::createFromTimestamp() returns Time with UTC by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8544 + +### Fixed Bugs + +* fix: [OCI8] getFieldData() returns incorrect `default` value by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8459 +* fix: [SQLite3] getFieldData() returns incorrect `primary_key` values by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8460 +* fix: [OCI8][Postgre][SQLSRV][SQLite3] change order of properties returned by getFieldData() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8481 +* docs: fix supported SQL Server version by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8489 +* fix: [SQLite3] Forge::modifyColumn() messes up table by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8457 +* docs: fix incorrect @return type in `ResultInterface-getCustomRowObject()` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8503 +* fix: [Postgre] updateBatch() breaks `char` type data by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8524 +* fix: DebugBar block by CSP by @YapsBridging in https://github.com/codeigniter4/CodeIgniter4/pull/8411 +* docs: fix `@phpstan-type` in Model by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8543 +* fix: [CURLRequest] Multiple HTTP 100 return by API. by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/8466 +* fix: PHPDoc types in controller.tpl.php by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8561 +* fix: [Session] Redis session race condition by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8323 + +### Refactoring + +* test: refactor ImageMagickHandlerTest by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8461 +* test: refactor GetFieldDataTest by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8480 +* refactor: use ternary operators in Helpers by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/8529 +* refactor: use official site URLs by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8541 +* refactor: remove redundant URL helper loading by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8556 +* refactor: small improvement in `loadInNamespace` Autoloader by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/8553 + +## [v4.4.5](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.5) (2024-01-27) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.4...v4.4.5) + +### Fixed Bugs + +* fix: bug 4.4.4 `spark serve` not working when using Session in Routes.php by @ALTITUDE-DEV-FR in https://github.com/codeigniter4/CodeIgniter4/pull/8389 +* fix: `highlightFile()` in `BaseExceptionHandler` for PHP 8.3 by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/8401 +* fix: [Validation] DotArrayFilter returns incorrect array when numeric index array is passed by @grimpirate in https://github.com/codeigniter4/CodeIgniter4/pull/8425 +* fix: OCI8 Forge always sets NOT NULL when BOOLEAN is specified by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8440 +* fix: DB Seeder may use wrong DB connection during testing by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8447 +* fix: [Postgre] QueryBuilder::updateBatch() does not work (No API change) by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8439 +* fix: [Postgre] QueryBuilder::deleteBatch() does not work by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8451 +* fix: [Email] setAttachmentCID() does not work with buffer string by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8446 +* fix: add undocumented Model $allowEmptyInserts by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8456 + +### Refactoring + +* refactor: remove overrides for coding-standard v1.7.12 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8386 +* refactor: Table class to fix phpstan errors by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8402 +* fix: typo in pager default_simple by @jasonliang-dev in https://github.com/codeigniter4/CodeIgniter4/pull/8407 +* refactor: improve Forge variable names by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8434 + +## [v4.4.4](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.4) (2023-12-28) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.3...v4.4.4) + +### Breaking Changes + +* fix: Validation rule with `*` gets incorrect values as dot array syntax by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8129 +* fix: validation rule `matches` and `differs` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8122 +* fix: [CURLRequest] skip hostname checks if options 'verify' false by @NicolaeIotu in https://github.com/codeigniter4/CodeIgniter4/pull/8258 +* fix: get_filenames() does not follow symlinks by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8298 + +### Fixed Bugs + +* fix: change make:command default $group to `App` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8109 +* fix: typo in help message in `spark filter:check` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8118 +* fix: Hot reloading when session is enabled by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/8112 +* fix: make:cell help message by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8133 +* fix: [DebugBar] dark mode timeline "Controller" by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8125 +* fix: PHPDoc types in controller.tpl.php by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8144 +* fix: `@return` in filter.tpl.php by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8145 +* fix: when request body is `0`, $body will be null by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8161 +* fix: `spark routes` outputs `` only when {locale} with `useSupportedLocalesOnly(true)` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8167 +* fix: Undefined array key error in `spark db:table` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8173 +* fix: force_https() redirects to wrong URL when baseURL has subfolder by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8191 +* fix: Validation raises TypeError when invalid JSON comes by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8153 +* fix: FilterTestTrait Undefined variable $filterClasses by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8195 +* fix: Image::save() causes error with webp by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8210 +* fix issue where running FileLocator::getClassname() on a directory would cause a PHP error by @colethorsen in https://github.com/codeigniter4/CodeIgniter4/pull/8216 +* fix: make Request::getEnv() deprecated by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8234 +* fix: ExceptionHandler displays incorrect Exception classname by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8239 +* fix: [Cache] Double prefix for increment in FileHandler by @il-coder in https://github.com/codeigniter4/CodeIgniter4/pull/8255 +* docs: fix Database Utility Class `getXMLFromResult()` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8276 +* fix: autoload helpers in test bootstrap by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8275 +* fix: Model handling of Entity $primaryKey casting by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8282 +* fix: Handle non-array JSON in validation by @woodongwong in https://github.com/codeigniter4/CodeIgniter4/pull/8288 +* fix: DEPRECATED error in Honeypot by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8316 +* fix: [Auto Routing Improved] `spark routes` shows incorrect routes when translateURIDashes is enabled by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8320 +* fix: migrations not using custom DB connection of migration runner by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8221 +* Always return a new instance of a Cell by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/8330 +* fix: DOMParser cannot see element with `id="0"` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8360 + +### Refactoring + +* [Rector] Apply SingleInArrayToCompareRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/8102 +* refactor: RedisHandler ttl() calls by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8155 +* [Testing] Use assertEqualsWithDelta() when possible by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/8158 +* refactor: replace non-boolean if conditions in Model by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8193 +* refactor: View classes to fix PHPStan errors by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8208 +* refactor: Model by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8260 +* replace -1 with E_ALL in error_reporting calls by @ThomasMeschke in https://github.com/codeigniter4/CodeIgniter4/pull/8212 +* refactor: apply SimplifyEmptyCheckOnEmptyArrayRector by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8341 +* refactor: apply DisallowedEmptyRuleFixerRector by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8344 +* refactor: rely on $config property in ViewDecoratorTrait by @mostafakhudair in https://github.com/codeigniter4/CodeIgniter4/pull/8021 +* refactor: replace empty() Part 1 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8345 + +## [v4.4.3](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.3) (2023-10-26) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.2...v4.4.3) + +### SECURITY + +* *Detailed Error Report is Displayed in Production Environment* was fixed. See the [Security advisory](https://github.com/codeigniter4/CodeIgniter4/security/advisories/GHSA-hwxf-qxj7-7rfj) for more information. + +### Fixed Bugs + +* fix: FilterTestTrait::getFilterCaller() does not support Filter classes as array by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8058 +* fix: add dbgroup to model template only when specified as an option by @sammyskills in https://github.com/codeigniter4/CodeIgniter4/pull/8077 +* Update phpstan-codeigniter and fix errors on Modules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/8036 +* fix: [Validation] exact_length does not pass int values by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8088 +* fix: [Table] field named `data` will produce bugged output by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/8054 +* docs: fix event points descriptions by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8076 +* docs: fix helper loading by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8084 + +## [v4.4.2](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.2) (2023-10-19) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.1...v4.4.2) + +### Fixed Bugs + +* Fix: [Session] the problem of secondary retrieving values ​​in RedisHandler by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/7887 +* fix: `spark migrate` `-g` option by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7894 +* fix: [DebugBar] dark mode `timeline-color-open` color text on `Debug` by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/7907 +* fix: base_url()/site_url() does not work on CLI by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7901 +* Fix: Routing::loadRoutes() in windows do not validate correctly $routesFiles by @pjsde in https://github.com/codeigniter4/CodeIgniter4/pull/7930 +* fix: Services::request() should call AppServices instead static by @pjsde in https://github.com/codeigniter4/CodeIgniter4/pull/7985 +* fix: lang() may return false by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7966 +* fix: CI returns "200 OK" when PageNotFound by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8011 +* fix: spark may not show exceptions or show backtrace as json by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7962 +* fix: CLI prompt validation message by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7977 +* fix: CSP style nonce is added even if honeypot is not attached by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8025 +* fix: named routes don't work with spark by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8028 +* fix: add a primary key to an existing table by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/8031 +* fix: reverse route for `''` is not `false` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8024 +* fix: `spark routes` may show incorrect route names by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8040 +* fix: Factories caching bug by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8037 +* fix: file sort order in Files DebugBar by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8048 + +### Enhancements + +* fix: check for CSRF token in the raw body by @michalsn in https://github.com/codeigniter4/CodeIgniter4/pull/7915 + +### Refactoring + +* fix: add types to View $filters and $plugins by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/7885 +* test: use PHP_VERSION_ID instead of PHP_VERSION by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7913 +* [PHP 8.3] refactor: ReflectionProperty::setValue() signature deprecation by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7911 +* refactor: remove unneeded arguments to session by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/7919 +* fix: types for common functions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/7917 +* Refactor: Apply PHPStan rule "Short ternary operator is not allowed" to RouteCollection by @pjsde in https://github.com/codeigniter4/CodeIgniter4/pull/7947 +* refactor: remove $_SESSION from methods and functions by @pjsde in https://github.com/codeigniter4/CodeIgniter4/pull/7982 +* refactor: if condition in OCI8/Connection.php by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7994 +* style: remove unnecessary () in Toolbar by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8013 +* refactor: replace deprecated `Services::request(config, false)` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7998 +* refactor: delete duplicate code for Composer loading by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/8004 +* [Rector] Apply BooleanInIfConditionRuleFixerRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/7951 + +## [v4.4.1](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.1) (2023-09-05) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.4.0...v4.4.1) + +### Fixed Bugs + +* docs: add missing Config updates for Hot Reloading by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7862 +* fix: auto route legacy does not work by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7871 +* fix: Factories may not return shared instance by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7868 +* fix: replace `config(DocTypes::class)` with `new DocTypes()` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7872 +* fix: FeatureTest may cause risky tests by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7867 +* fix: reverse routing causes ErrorException by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7880 +* fix: Email library forces to switch to TLS when setting port 465 by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7883 +* fix: [DebugBar] make CSS rotate class less broad by @sanchawebo in https://github.com/codeigniter4/CodeIgniter4/pull/7882 +* fix: FeatureTest fails when forceGlobalSecureRequests is true by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7890 + +## [v4.4.0](https://github.com/codeigniter4/CodeIgniter4/tree/v4.4.0) (2023-08-25) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.3.8...v4.4.0) + +### Breaking Changes + +* fix: URI::setSegment() accepts the last +2 segment without Exception by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7251 +* feat: custom exception handler by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7087 +* Clean router config by @lonnieezell in https://github.com/codeigniter4/CodeIgniter4/pull/7380 +* feat: add ValidationInterface::getValidated() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7429 +* [4.4] refactor: moving RedirectException. by @iRedds in https://github.com/codeigniter4/CodeIgniter4/pull/7545 +* Remove Config\App Session items by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7255 +* perf: RouteCollection $routes optimization by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7175 +* Remove Config\App Security items by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7630 +* refactor: extract ResponseCache class for Web Page Caching by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7644 +* fix: change Services::session() config param type by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7671 +* feat: add Factories::define() to explicitly override a class by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7733 +* Return signatures of Autoloader's loaders should be void by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/7747 +* fix: remove instantiation of Response in `Services::exceptions()` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7670 +* refactor: move callExit() to index.php by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7800 +* rework: URI creation and URL helper by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7282 + +### Fixed Bugs + +* fix: incorrect segment number in URI::getSegment() exception message by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7267 +* fix: can't change and override valid locales by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7309 +* fix: Validation::check() does not accept array rules by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7424 +* fix: directory separator from routing file. by @ping-yee in https://github.com/codeigniter4/CodeIgniter4/pull/7487 +* [4.4] Fix output buffering by @iRedds in https://github.com/codeigniter4/CodeIgniter4/pull/7500 +* fix: [Auto Routing Improved] one controller method has more than one URI when $translateURIDashes is true by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7422 +* fix: [4.4] merge Exception::maskSensitiveData() fix into BaseExceptionHandler by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7736 + +### New Features + +* feat: Hot Reloading by @lonnieezell in https://github.com/codeigniter4/CodeIgniter4/pull/7489 + +### Enhancements + +* feat: `renderSection` option to retained data by @addngr in https://github.com/codeigniter4/CodeIgniter4/pull/7126 +* feat: [Auto Routing Improved] fallback to default method by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7162 +* feat: Filter Arguments with $filters in Config\Filters by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7159 +* feat: New method DownloadResponse::inline() by @iRedds in https://github.com/codeigniter4/CodeIgniter4/pull/7207 +* feat: add `--host` option to `spark routes` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7213 +* feat: add `Entity::injectRawData()` to avoid name collision by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7208 +* feat: [MySQLi] add config to use MYSQLI_OPT_INT_AND_FLOAT_NATIVE by @kai890707 in https://github.com/codeigniter4/CodeIgniter4/pull/7265 +* feat: add new setter/getter for Entity by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7230 +* feat: [SQLSRV] getFieldData() supports nullable by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7301 +* feat: HTML Table data keys synchronize order with Heading keys by @rumpfc in https://github.com/codeigniter4/CodeIgniter4/pull/7409 +* feat: [Validation] add method to get the validated data by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7420 +* feat: [Auto Routing Improved] Module Routing by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7416 +* feat: function array_group_by by @rumpfc in https://github.com/codeigniter4/CodeIgniter4/pull/7438 +* feat: add Session::close() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7508 +* feat: `GDHandler` make `WebP` with option quality by @ddevsr in https://github.com/codeigniter4/CodeIgniter4/pull/7506 +* feat: [Auto Routing Improved] fallback to default controller's default method by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7406 +* Add access to `full_path` index of uploaded files by @JamminCoder in https://github.com/codeigniter4/CodeIgniter4/pull/7541 +* [4.4] Rework redirect exception by @iRedds in https://github.com/codeigniter4/CodeIgniter4/pull/7610 +* feat: [CURLRequest] add option for Proxy by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7632 +* feat: improve View route output by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7646 +* feat: add SiteURI class by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7252 +* feat: add SiteURIFactory by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7256 +* feat: [Factories] Config caching by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7696 + +### Refactoring + +* refactor: remove Cookie config items in Config\App by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7221 +* refactor: deprecate $request and $response in Exceptions::__construct() by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7232 +* refactor: use config(Cache::class) in CodeIgniter by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7297 +* [4.4] refactor: a single point of sending the Response. by @iRedds in https://github.com/codeigniter4/CodeIgniter4/pull/7519 +* refactor: [Entity] fix incorrect return value by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7544 +* [4.4] refactor: use ::class to config() param by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7619 +* refactor: drop support for `Config\App::$proxyIPs = ''` by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7621 +* refactor: extract DefinedRouteCollector by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7653 +* refactor: remove uneeded `if` in Commands\Utilities\Routes by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7661 +* refactor: [4.4] add types for phpstan by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/7723 +* Remove trimming logic of `Autoloader::loadClass()` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/7763 + +See [CHANGELOG_4.3.md](./changelogs/CHANGELOG_4.3.md) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000000..047a477a2945 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,46 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at admin@codeigniter.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000000..3688517a265a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,6 @@ +# Contributing to CodeIgniter4 + +CodeIgniter is a community driven project and accepts contributions of +code and documentation from the community. + +If you'd like to contribute, please read the [Contributing to CodeIgniter](./contributing/README.md). diff --git a/DCO.txt b/DCO.txt deleted file mode 100644 index a404c0d38b0d..000000000000 --- a/DCO.txt +++ /dev/null @@ -1,25 +0,0 @@ -Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -(1) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -(2) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -(3) The contribution was provided directly to me by some other - person who certified (1), (2) or (3) and I have not modified - it. - -(4) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000000..24728f607f02 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2014-2019 British Columbia Institute of Technology +Copyright (c) 2019-present CodeIgniter Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md index d4937f483c3c..77419c2a2348 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,39 @@ # CodeIgniter 4 Development -[![Build Status](https://travis-ci.org/bcit-ci/CodeIgniter4.svg?branch=develop)](https://travis-ci.org/bcit-ci/CodeIgniter4) -[![Coverage Status](https://coveralls.io/repos/github/bcit-ci/CodeIgniter4/badge.svg?branch=develop)](https://coveralls.io/github/bcit-ci/CodeIgniter4?branch=develop) +[![PHPUnit](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/test-phpunit.yml/badge.svg)](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/test-phpunit.yml) +[![PHPStan](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/test-phpstan.yml/badge.svg)](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/test-phpstan.yml) +[![Psalm](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/test-psalm.yml/badge.svg)](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/test-psalm.yml) +[![Coverage Status](https://coveralls.io/repos/github/codeigniter4/CodeIgniter4/badge.svg?branch=develop)](https://coveralls.io/github/codeigniter4/CodeIgniter4?branch=develop) +[![Downloads](https://poser.pugx.org/codeigniter4/framework/downloads)](https://packagist.org/packages/codeigniter4/framework) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/codeigniter4/CodeIgniter4)](https://packagist.org/packages/codeigniter4/framework) +[![GitHub stars](https://img.shields.io/github/stars/codeigniter4/CodeIgniter4)](https://packagist.org/packages/codeigniter4/framework) +[![GitHub license](https://img.shields.io/github/license/codeigniter4/CodeIgniter4)](https://github.com/codeigniter4/CodeIgniter4/blob/develop/LICENSE) +[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/codeigniter4/CodeIgniter4/pulls)
## What is CodeIgniter? -CodeIgniter is a PHP full-stack web framework that is light, fast, flexible, and secure. -More information can be found at the [official site](http://codeigniter.com). -This repository holds the pre-alpha code for CodeIgniter 4 only. -Version 4 is a complete rewrite to bring the quality and the code into a more modern version, -while still keeping as many of the things intact that has made people love the framework over the years. +CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure. +More information can be found at the [official site](https://codeigniter.com). -**This is pre-release code and should not be used in production sites.** +This repository holds the source code for CodeIgniter 4 only. +Version 4 is a complete rewrite to bring the quality and the code into a more modern version, +while still keeping as many of the things intact that has made people love the framework over the years. -More information about the plans for version 4 can be found in [the announcement](http://forum.codeigniter.com/thread-62615.html) on the forums. +More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums. + +### Documentation + +The [User Guide](https://codeigniter.com/user_guide/) is the primary documentation for CodeIgniter 4. + +You will also find the [current **in-progress** User Guide](https://codeigniter4.github.io/CodeIgniter4/). +As with the rest of the framework, it is a work in progress, and will see changes over time to structure, explanations, etc. + +You might also be interested in the [API documentation](https://codeigniter4.github.io/api/) for the framework components. ## Important Change with index.php -index.php is no longer in the root of the project! It has been moved inside the *public* folder, +`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 @@ -26,19 +41,24 @@ not to the project root. A better practice would be to configure a virtual host framework are exposed. **Please** read the user guide for a better explanation of how CI4 works! -The user guide updating and deployment is a bit awkward at the moment, but we are working on it! ## Repository Management -We use Github issues to track **BUGS** and to track approved **DEVELOPMENT** work packages. -We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss -FEATURE REQUESTS. + +CodeIgniter is developed completely on a volunteer basis. As such, please give up to 7 days +for your issues to be reviewed. If you haven't heard from one of the team in that time period, +feel free to leave a comment on the issue so that it gets brought back to our attention. + +> [!IMPORTANT] +> We use GitHub issues to track **BUGS** and to track approved **DEVELOPMENT** work packages. +> We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss +> FEATURE REQUESTS. If you raise an issue here that pertains to support or a feature request, it will be closed! If you are not sure if you have found a bug, raise a thread on the forum first - someone else may have encountered the same thing. -Before raising a new Github issue, please check that your bug hasn't already -been reported or fixed. +Before raising a new GitHub issue, please check that your bug hasn't already +been reported or fixed. We use pull requests (PRs) for CONTRIBUTIONS to the repository. We are looking for contributions that address one of the reported bugs or @@ -51,21 +71,39 @@ Remember that some components that were part of CodeIgniter 3 are being moved to optional packages, with their own repository. ## Contributing -We **are** accepting contributions from the community, specifically those identified as part of phase 2. -We will try to manage the process somewhat, by adding a "Help wanted" label to those that we are -specifically interested in at any point in time. Join the discussion for those issues, and let us know -if you want to take the lead for one of them. +We **are** accepting contributions from the community! It doesn't matter whether you can code, write documentation, or help find bugs, +all contributions are welcome. -We are not looking for out-of-scope contributions, only those that would be considered part of our controlled evolution! +Please read the [*Contributing to CodeIgniter*](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/README.md). -Please read the *Contributing to CodeIgniter* section in the user guide +CodeIgniter has had thousands on contributions from people since its creation. This project would not be what it is without them. + + + + + +Made with [contrib.rocks](https://contrib.rocks). ## Server Requirements -PHP version 7 or higher is required, with the following extensions installed: -- intl +PHP version 8.1 or higher is required, with the following extensions installed: + +- [intl](http://php.net/manual/en/intl.requirements.php) +- [mbstring](http://php.net/manual/en/mbstring.installation.php) +> [!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. +> - If you are still using PHP 7.4 or 8.0, you should upgrade immediately. +> - The end of life date for PHP 8.1 will be December 31, 2025. + +Additionally, make sure that the following extensions are enabled in your PHP: + +- json (enabled by default - don't turn it off) +- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL +- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library ## Running CodeIgniter Tests -Information on running CodeIgniter test suite can be found in the [README.md](tests/README.md) file in the tests directory. + +Information on running the CodeIgniter test suite can be found in the [README.md](tests/README.md) file in the tests directory. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000000..87b894ee713c --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +The development team and community take all security issues seriously. **Please do not make public any uncovered flaws.** + +## Reporting a Vulnerability + +Thank you for improving the security of our code! Any assistance in removing security flaws will be acknowledged. + +**Please report security flaws by emailing the development team directly: security@codeigniter.com**. + +The lead maintainer will acknowledge your email within 48 hours, and will send a more detailed response within 48 hours indicating +the next steps in handling your report. After the initial reply to your report, the security team will endeavor to keep you informed of the +progress towards a fix and full announcement, and may ask for additional information or guidance. + +## Disclosure Policy + +When the security team receives a security bug report, they will assign it to a primary handler. +This person will coordinate the fix and release process, involving the following steps: + +- Confirm the problem and determine the affected versions. +- Audit code to find any potential similar problems. +- Prepare fixes for all releases still under maintenance. These fixes will be released as fast as possible. +- Publish security advisories at https://github.com/codeigniter4/CodeIgniter4/security/advisories + +## Comments on this Policy + +If you have suggestions on how this process could be improved please submit a Pull Request. diff --git a/admin/README.md b/admin/README.md new file mode 100644 index 000000000000..1f5dd89bfcd1 --- /dev/null +++ b/admin/README.md @@ -0,0 +1,87 @@ +# CodeIgniter 4 Admin + +This folder contains tools or docs useful for project maintainers. + +## Repositories inside https://github.com/codeigniter4 + +- **CodeIgniter4** is the main development repository. + It supports issues and pull requests, and has a rule to enforce GPG-signed commits. + In addition to the framework source, it includes unit testing and documentation source. + The three repositories following are built from this one as part of the release workflow. + This repo is meant to be forked by contributors. +- **framework** is the released developer repository. + It contains all the main pieces of the framework that developers would use to + build their apps, but not the framework unit testing or the user guide source. + It is meant to be downloaded by developers, or composer-installed. + This is a read-only repository. +- **appstarter** is the released application starter repository. + It is derived from the framework's `app` and `public` folders, with + a composer requirement dependency to pull in the framework itself. + It is meant to be downloaded or composer-installed. + This is a read-only repository. +- **userguide** is released documentation publishing repository. + It contains built versions of the user guide, corresponding to the + framework releases. + It could be downloaded, forked or potentially composer-installed. + This is a read-only repository. +- **coding-standard** is the coding style standards repository. + It contains PHP-CS-Fixer rules to ensure consistent code style + within the framework itself. + It is meant to be composer-installed. +- **translations** is the repository holding official translations of + the locale-dependent system messages. + It is community-maintained, and accepts issues and pull requests. + It could be downloaded, forked or composer-installed. + +## Contributor Scripts + +- **setup.sh** installs a git pre-commit hook into a contributor's + local clone of their fork of the `CodeIgniter4` repository. +- **pre-commit** runs PHP Lint and PHP CodeSniffer on any files + to be added as part of a git commit, ensuring that they conform to the + framework coding style standards, and automatically fixing what can be. + +## Maintainer Scripts + +- **release-config** holds variables used for the maintainer & release building +- **docbot** re-builds the user guide from the RST source for it, + and optionally deploys it to the `gh-pages` branch of the main + repository (if the user running it has maintainer rights on that repo). + See the [writeup](./docbot.md). + +## Release Building Scripts + +*Do not use these scripts! They are left here for reference only.* + +The release workflow is detailed in its own writeup; these are the main +scripts used by the release manager: + +- **release** builds a new release branch in the main repo, for vetting. + This includes updating version dependencies or constants, + generating version(s) of the user guide; and possibly + moving or ignoring stuff, distinguishing release from development. + If successful, it will update the `config` file, with the version number + in it, and it will run the related scripts following, to revise + the release distributions. + Usage: `admin/release version qualifier` +- **release-userguide** builds the distributable userguide repo. + It could be used on its own, but is normally part of `release`. +- **release-deploy** pushes the release changes to the appropriate github + repositories. Tag & create releases on GitHub. This is not easily reversible! + Usage: `admin/release-deploy version qualifier` +- **release-revert** can be used to restore your repositories to the state they + were in before you started a release. **IF** you haven't deployed. + This is in case you decide not to proceed with the release, for any reason. + Remember to be polite when running it. + + +## Other Stuff + +- **release-notes.bb** is a boilerplate for forum announcements of a new release. + It is marked up using [BBcode](https://en.wikipedia.org/wiki/BBCode). +- The **framework** and **starter** subfolders contain files that will over-ride + those from the development repository, when the distribution repositories + are built. +- The subfolders inside `admin` contain "next release" files in the case of + `codeigniter4` and over-written distribution files in the other cases. +- The CHANGELOG.md file is auto-generated using the [GitHub Changelog Generator](https://github.com/github-changelog-generator/github-changelog-generator) diff --git a/admin/RELEASE.md b/admin/RELEASE.md new file mode 100644 index 000000000000..697af85ff712 --- /dev/null +++ b/admin/RELEASE.md @@ -0,0 +1,255 @@ +# Release Process + +> Documentation guide based on the releases of `4.0.5` and `4.1.0` on January 31, 2021. +> +> Updated for `4.5.0` on April 7, 2024. +> Updated for `4.6.0` on January 19, 2025. +> +> -MGatner, kenjis + +## Notation + +- `4.x.x`: The new release version. (e.g., `4.5.3`) +- `4.y`: The next minor version. (e.g., `4.6`) +- `4.z`: The next next minor version. (e.g., `4.7`) + +> [!NOTE] +> Copy this file, and replace the versions above with the actual versions. + +## Merge `develop` branch into next minor version branch `4.y` + +Before starting release process, if there are commits in `develop` branch that +are not merged into `4.y` branch, merge them. This is because if conflicts occur, +merging will take time. + +```console +git fetch upstream +git switch 4.y +git merge upstream/4.y +git merge upstream/develop +git push upstream HEAD +``` + +## [Minor version only] Merge minor version branch into `develop` + +If you release a new minor version. + +* [ ] Create PR to merge `4.y` into `develop`: + * Title: `4.y.0 Merge code` + * Description: blank +* [ ] Rename the current minor version (e.g., `4.5`) in Setting > Branches > + "Branch protection rules" to the next minor version (e.g. `4.5` → `4.6`). +* [ ] Delete the merged `4.y` branch (this closes all PRs to the branch). + +## Preparation + +Work off direct clones of the repos so the release branches persist for a time. + +* [ ] Clone both **codeigniter4/CodeIgniter4** and **codeigniter4/userguide** and + resolve any necessary PRs + ```console + rm -rf CodeIgniter4.bk userguide.bk + mv CodeIgniter4 CodeIgniter4.bk + mv userguide userguide.bk + git clone git@github.com:codeigniter4/CodeIgniter4.git + git clone git@github.com:codeigniter4/userguide.git + ``` +* [ ] Vet the **admin/** folders for any removed hidden files (Action deploy scripts + *do not remove these*) + ```console + cd CodeIgniter4 + git diff --name-status origin/master admin/ + ``` + +## Changelog + +When generating the changelog, each pull request to be included must have one of +the following [labels](https://github.com/codeigniter4/CodeIgniter4/labels): +- **bug** ... PRs that fix bugs +- **enhancement** ... PRs to improve existing functionalities +- **new feature** ... PRs for new features +- **refactor** ... PRs to refactor + +PRs with breaking changes must have the following additional label: +- **breaking change** ... PRs that may break existing functionalities + +### Generate Changelog + +To auto-generate the changelog, navigate to the +[Releases](https://github.com/codeigniter4/CodeIgniter4/releases) page, +click the "Draft a new release" button. + +* Choose a tag: `v4.x.x` (Create new tag: v4.x.x on publish) +* Target: `develop` + +Click the "Generate release notes" button. + +Check the resulting content. If there are items in the *Others* section which +should be included in the changelog, add a label to the PR and regenerate +the changelog. + +Copy the resulting contents into **CHANGELOG.md** and adjust the format to match +the existing content. + +## Process + +> [!NOTE] +> Most changes that need noting in the User Guide and docs should have +> been included with their PR, so this process assumes you will not be +> generating much new content. + +* [ ] Merge any security advisory PRs in private forks. +* [ ] Add the current version to **CHANGELOG.md** with the contents generated above. +* [ ] Update **user_guide_src/source/changelogs/v4.x.x.rst** + * Remove the section titles that have no items +* [ ] Update **user_guide_src/source/installation/upgrade_4xx.rst** + * [ ] fill in the "All Changes" section using the following command, and add it to **upgrade_4xx.rst**: + ``` + git diff --name-status origin/master -- . ':!.github/' ':!admin/' ':!system/' ':!tests/' \ + ':!user_guide_src/' ':!utils/' ':!*.json' ':!*.xml' ':!*.dist' ':!rector.php' \ + ':!phpstan*' ':!psalm*' ':!.php-cs-fixer.*' ':!LICENSE' ':!CHANGELOG.md' + ``` + * Note: `tests/` is not used for distribution repos. See `admin/starter/tests/`. + * [ ] Remove the section titles that have no items + * [ ] [Minor version only] Update the "from" version in the title, (e.g., `from 4.3.x` → `from 4.3.8`). +* [ ] Run `php admin/prepare-release.php 4.x.x` and push to origin. + * The above command does the following: + * Create a new branch `release-4.x.x` + * Update **system/CodeIgniter.php** with the new version number: + `const CI_VERSION = '4.x.x';` + * Update **user_guide_src/source/conf.py** with the new `version = '4.x'` (if releasing + the minor version) and `release = '4.x.x'`. + * Update **user_guide_src/source/changelogs/{version}.rst** + * Set the date to format `Release Date: January 31, 2021` + * Update **phpdoc.dist.xml** with the new `CodeIgniter v4.x API` + and `` + * Commit the changes with `Prep for 4.x.x release` +* [ ] Create a new PR from `release-4.x.x` to `develop`: + * Title: `Prep for 4.x.x release` + * Description: + ``` + Updates changelog and version references for 4.x.x. + + Previous version: #xxxx + Release Code: TODO + New Changelog: TODO + + (plus checklist) + ``` + +* [ ] Let all tests run, then review and merge the PR. +* [ ] Create a new PR from `develop` to `master`: + * Title: `4.x.x Ready code` + * Description: blank +* [ ] Merge the PR and wait for all tests. +* [ ] Create a new Release: + * Choose a tag: `v4.x.x` (Create new tag: v4.x.x on publish) + * Target: `master` + * Title: `CodeIgniter 4.x.x` + * Description: + ``` + CodeIgniter 4.x.x release. + + See the changelog: https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md + + ## New Contributors + * + + **Full Changelog**: https://github.com/codeigniter4/CodeIgniter4/compare/v4.x.w...v4.x.x + ``` + Click the "Generate release notes" button, and get the "New Contributors". +* [ ] Watch for the "Deploy Distributable Repos" action to make sure **framework**, + **appstarter**, and **userguide** get updated +* [ ] Run the following commands to install and test `appstarter` and verify the new + version: + ```console + rm -rf release-test + composer create-project codeigniter4/appstarter release-test + cd release-test + composer test && composer info codeigniter4/framework + ``` +* [ ] Verify that the user guide actions succeeded: + * [ ] "[Deploy Distributable Repos](https://github.com/codeigniter4/CodeIgniter4/actions/workflows/deploy-distributables.yml)", the main repo + * [ ] "[Deploy Production](https://github.com/codeigniter4/userguide/actions/workflows/deploy.yml)", UG repo + * [ ] "[pages-build-deployment](https://github.com/codeigniter4/userguide/actions/workflows/pages/pages-build-deployment)", UG repo + * [ ] Check if "CodeIgniter4.x.x.epub" is added to UG repo. "CodeIgniter.epub" was + created when v4.3.8 was released. +* [ ] Fast-forward `develop` branch to catch the merge commit from `master` + ```console + git fetch upstream + git checkout develop + git merge upstream/develop + git merge upstream/master + git push upstream HEAD + ``` +* [ ] Update the next minor version branch `4.y`: + ```console + git fetch upstream + git switch 4.y + git merge upstream/4.y + git merge upstream/develop + git push upstream HEAD + ``` +* [ ] [Minor version only] Create the new next minor version branch `4.z`: + ```console + git fetch upstream + git switch develop + git switch -c 4.z + git push upstream HEAD + ``` +* [ ] Request CVEs and publish any security advisories that were resolved from private forks + (note: publishing is restricted to administrators). +* [ ] Announce the release on the forums and Slack channel + (note: this forum is restricted to administrators). + * Make a new topic in the "News & Discussion" forums: + https://forum.codeigniter.com/forum-2.html + * The content is somewhat organic, but should include any major features and + changes as well as a link to the User Guide's changelog +* [ ] Run `php admin/create-new-changelog.php ` + * The above command does the following: + * Create **user_guide_src/source/changelogs/{next_version}.rst** and add it to + **index.rst** (See **next-changelog-*.rst**) + * Create **user_guide_src/source/installation/upgrade_{next_version}.rst** and add it to + **upgrading.rst** (See **next-upgrading-guide.rst**) +* [ ] Create a PR for new changelog and upgrade for the next version + +## Appendix + +### Sphinx Installation + +You may need to install Sphinx and its dependencies prior to building the User +Guide. + +This worked seamlessly on Ubuntu 20.04: +```console +sudo apt install python3-sphinx +sudo pip3 install sphinxcontrib-phpdomain +sudo pip3 install sphinx_rtd_theme +``` + +### Manual User Guide Process + +* Still in the **CodeIgniter4** repo enter the **user_guide_src** directory +* Clear out any old build files: `rm -rf build/` +* Build the HTML version of the User Guide: `make html` +* Build the ePub version of the User Guide: `make epub` +* Switch to the **userguide** repo and create a new branch `release-4.x.x` +* Replace **docs/** with **CodeIgniter4/user_guide_src/build/html** +* Ensure the file **docs/.nojekyll** exists or GitHub Pages will ignore folders + with an underscore prefix +* Copy **CodeIgniter4/user_guide_src/build/epub/CodeIgniter.epub** to + **./CodeIgniter4.x.x.epub** +* Commit the changes with "Update for 4.x.x" and push to origin +* Create a new PR from `release-4.x.x` to `develop`: + * Title: "Update for 4.x.x" + * Description: blank +* Merge the PR +* Create a new Release: + * Version: "v4.x.x" + * Title: "CodeIgniter 4.x.x User Guide" + * Description: "CodeIgniter 4.x.x User Guide" +* Watch for the "github pages" Environment to make sure the deployment succeeds + +The User Guide website should update itself via the deploy GitHub Action. Should +this fail the server must be updated manually. See repo and hosting details in +the deploy script at the User Guide repo. diff --git a/admin/alldocs b/admin/alldocs new file mode 100755 index 000000000000..12d0b410ff84 --- /dev/null +++ b/admin/alldocs @@ -0,0 +1,7 @@ +#!/bin/bash + +# Rebuild and deploy all CodeIgniter4 docs +# + +. admin/docbot $1 +. admin/apibot $1 \ No newline at end of file diff --git a/admin/apibot b/admin/apibot new file mode 100755 index 000000000000..08b451a04bbb --- /dev/null +++ b/admin/apibot @@ -0,0 +1,42 @@ +#!/bin/bash + +# Rebuild and deploy CodeIgniter4 under-development user guide +# +# This is a quick way to test user guide changes, and if they +# look good, to push them to the gh-pages branch of the +# development repository. +# +# This is not meant for updating the "stable" user guide. + +UPSTREAM=https://github.com/codeigniter4/api.git + +# Prepare the nested repo clone folder +rm -rf build/api* +mkdir -p build/api/docs + +# Get ready for git +cd build/api +git init +git remote add origin $UPSTREAM +git fetch +git checkout master +git reset --hard origin/master +rm -r docs/* + +# Make the new user guide +cd ../.. +phpdoc +cp -R api/build/* build/api/docs + +# All done? +if [ $# -lt 1 ]; then + exit 0 +fi + +# Optionally update the remote repo +if [ $1 = "deploy" ]; then + cd build/api + git add . + git commit -S -m "APIbot synching" + git push -f origin master +fi diff --git a/admin/apibot.md b/admin/apibot.md new file mode 100644 index 000000000000..ef22277069ec --- /dev/null +++ b/admin/apibot.md @@ -0,0 +1,36 @@ +# apibot + +Builds & deploys API docs. + +The in-progress CI4 API docs, warts & all, are rebuilt and +then copied to a nested +repository clone (`build/api`), with the result +optionally pushed to the `master` branch of the `api` repo. +That would then be publically visible as the in-progress +version of the [API](https://codeigniter4.github.io/api/). + +## Requirements + +You must have phpDocumentor installed, with a `phpdoc` alias installed globally. + +## Audience + +This script is intended for use by framework maintainers, +i.e. someone with commit rights on the CI4 repository. + +You will be prompted for your github credentials and +GPG-signing key as appropriate. + +## Usage + +Inside a shell prompt, in the project root: + + `admin/apibot [deploy]` + +If "deploy" is not added, the script execution is considered +a trial run, and nothing is pushed to the repo. + +Whether or not deployed, the results are left inside +`build/api` (which is git ignored). + +Generate these and the userguide together with the 'alldocs' script. diff --git a/admin/create-new-changelog.php b/admin/create-new-changelog.php new file mode 100644 index 000000000000..cc7f8359a570 --- /dev/null +++ b/admin/create-new-changelog.php @@ -0,0 +1,89 @@ + " . PHP_EOL; + echo "E.g.,: php {$argv[0]} 4.4.3 4.4.4" . PHP_EOL; + + exit(1); +} + +// Gets version number from argument. +$versionCurrent = $argv[1]; // e.g., '4.4.3' +$versionCurrentParts = explode('.', $versionCurrent); +$minorCurrent = $versionCurrentParts[0] . '.' . $versionCurrentParts[1]; +$version = $argv[2]; // e.g., '4.4.4' +$versionParts = explode('.', $version); +$minor = $versionParts[0] . '.' . $versionParts[1]; +$isMinorUpdate = ($minorCurrent !== $minor); + +// Creates a branch for release. +if (! $isMinorUpdate) { + system('git switch develop'); +} +system('git switch -c docs-changelog-' . $version); +system('git switch docs-changelog-' . $version); + +// Copy changelog +$changelog = "./user_guide_src/source/changelogs/v{$version}.rst"; +$changelogIndex = './user_guide_src/source/changelogs/index.rst'; +if ($isMinorUpdate) { + copy('./admin/next-changelog-minor.rst', $changelog); +} else { + copy('./admin/next-changelog-patch.rst', $changelog); +} +// Add changelog to index.rst. +replace_file_content( + $changelogIndex, + '/\.\. toctree::\n :titlesonly:\n/u', + ".. toctree::\n :titlesonly:\n\n v{$version}", +); +// Replace {version} +$length = mb_strlen("Version {$version}"); +$underline = str_repeat('#', $length); +replace_file_content( + $changelog, + '/#################\nVersion {version}\n#################/u', + "{$underline}\nVersion {$version}\n{$underline}", +); +replace_file_content( + $changelog, + '/{version}/u', + "{$version}", +); + +// Copy upgrading +$versionWithoutDots = str_replace('.', '', $version); +$upgrading = "./user_guide_src/source/installation/upgrade_{$versionWithoutDots}.rst"; +$upgradingIndex = './user_guide_src/source/installation/upgrading.rst'; +copy('./admin/next-upgrading-guide.rst', $upgrading); +// Add upgrading to upgrading.rst. +replace_file_content( + $upgradingIndex, + '/ backward_compatibility_notes\n/u', + " backward_compatibility_notes\n\n upgrade_{$versionWithoutDots}", +); +// Replace {version} +$length = mb_strlen("Upgrading from {$versionCurrent} to {$version}"); +$underline = str_repeat('#', $length); +replace_file_content( + $upgrading, + '/##############################\nUpgrading from {version} to {version}\n##############################/u', + "{$underline}\nUpgrading from {$versionCurrent} to {$version}\n{$underline}", +); + +// Commits +system("git add {$changelog} {$changelogIndex}"); +system("git add {$upgrading} {$upgradingIndex}"); +system('git commit -m "docs: add changelog and upgrade for v' . $version . '"'); diff --git a/admin/css/debug-toolbar/README.md b/admin/css/debug-toolbar/README.md new file mode 100644 index 000000000000..2c70e8147eae --- /dev/null +++ b/admin/css/debug-toolbar/README.md @@ -0,0 +1 @@ +See [contributing/css.md](../../../contributing/css.md). diff --git a/admin/css/debug-toolbar/_graphic-charter.scss b/admin/css/debug-toolbar/_graphic-charter.scss new file mode 100644 index 000000000000..522f07f6e255 --- /dev/null +++ b/admin/css/debug-toolbar/_graphic-charter.scss @@ -0,0 +1,20 @@ +// COLORS +// ========================================================================== */ + +// Themes +$t-dark: #252525; +$t-light: #FFFFFF; + +// Glossy colors +$g-blue: #5BC0DE; +$g-gray: #434343; +$g-green: #9ACE25; +$g-orange: #DD8615; +$g-red: #DD4814; + +// Matt colors +$m-blue: #D8EAF0; +$m-gray: #DFDFDF; +$m-green: #DFF0D8; +$m-orange: #FDC894; +$m-red: #EF9090; diff --git a/admin/css/debug-toolbar/_mixins.scss b/admin/css/debug-toolbar/_mixins.scss new file mode 100644 index 000000000000..69af2b67c475 --- /dev/null +++ b/admin/css/debug-toolbar/_mixins.scss @@ -0,0 +1,14 @@ +// MIXINS +// ========================================================================== */ + +@mixin border-radius($radius) { + border-radius: $radius; + -moz-border-radius: $radius; + -webkit-border-radius: $radius; +} + +@mixin box-shadow($left, $top, $radius, $color) { + box-shadow: $left $top $radius $color; + -moz-box-shadow: $left $top $radius $color; + -webkit-box-shadow: $left $top $radius $color; +} diff --git a/admin/css/debug-toolbar/_settings.scss b/admin/css/debug-toolbar/_settings.scss new file mode 100644 index 000000000000..1bb1386a46a0 --- /dev/null +++ b/admin/css/debug-toolbar/_settings.scss @@ -0,0 +1,8 @@ +// FONT +// ========================================================================== */ + +// Standard "sans-serif" font stack used by GitHub +$base-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; + +// Default size, all other styles are based on this size +$base-size: 16px; diff --git a/admin/css/debug-toolbar/_theme-dark.scss b/admin/css/debug-toolbar/_theme-dark.scss new file mode 100644 index 000000000000..ead7d02a58e3 --- /dev/null +++ b/admin/css/debug-toolbar/_theme-dark.scss @@ -0,0 +1,167 @@ +// IMPORTS +// ========================================================================== */ + +// The "box-shadow" mixin uses colors +@import '_mixins'; + +// Graphic charter +@import '_graphic-charter'; + + +// DEBUG ICON +// ========================================================================== */ + +#debug-icon { + background-color: $t-dark; + @include box-shadow(0, 0, 4px, $m-gray); + + a:active, + a:link, + a:visited { + color: $g-orange; + } +} + + +// DEBUG BAR +// ========================================================================== */ + +#debug-bar { + background-color: $t-dark; + color: $m-gray; + + // Reset to prevent conflict with other CSS files + h1, + h2, + h3, + p, + a, + button, + table, + thead, + tr, + td, + button, + .toolbar { + background-color: transparent; + color: $m-gray; + } + + // Buttons + button { + background-color: $t-dark; + } + + // Tables + table { + strong { + color: $g-orange; + } + + tbody tr { + &:hover { + background-color: $g-gray; + } + + &.current { + background-color: $m-orange; + + td { + color: $t-dark; + } + + &:hover td { + background-color: $g-red; + color: $t-light; + } + } + } + } + + // The toolbar + .toolbar { + background-color: $g-gray; + @include box-shadow(0, 0, 4px, $g-gray); + + img { + filter: brightness(0) invert(1); + } + } + + // Fixed top + &.fixed-top { + .toolbar { + @include box-shadow(0, 0, 4px, $g-gray); + } + + .tab { + @include box-shadow(0, 1px, 4px, $g-gray); + } + } + + // "Muted" elements + .muted { + color: $m-gray; + + td { + color: $g-gray; + } + + &:hover td { + color: $m-gray; + } + } + + // The toolbar preferences + #toolbar-position, + #toolbar-theme { + filter: brightness(0) invert(0.6); + } + + // The toolbar menus + .ci-label { + &.active { + background-color: $t-dark; + } + + &:hover { + background-color: $t-dark; + } + + .badge { + background-color: $g-red; + color: $t-light; + } + } + + // The tabs container + .tab { + background-color: $t-dark; + @include box-shadow(0, -1px, 4px, $g-gray); + } + + // The "Timeline" tab + .timeline { + th, + td { + border-color: $g-gray; + } + + .timer { + background-color: $g-orange; + } + } +} + + +// DEBUG VIEW +// ========================================================================== */ + +.debug-view.show-view { + border-color: $g-orange; +} + +.debug-view-path { + background-color: $m-orange; + color: $g-gray; +} diff --git a/admin/css/debug-toolbar/_theme-light.scss b/admin/css/debug-toolbar/_theme-light.scss new file mode 100644 index 000000000000..4e4295ccd131 --- /dev/null +++ b/admin/css/debug-toolbar/_theme-light.scss @@ -0,0 +1,163 @@ +// IMPORTS +// ========================================================================== */ + +// The "box-shadow" mixin uses colors +@import '_mixins'; + +// Graphic charter +@import '_graphic-charter'; + + +// DEBUG ICON +// ========================================================================== */ + +#debug-icon { + background-color: $t-light; + @include box-shadow(0, 0, 4px, $m-gray); + + a:active, + a:link, + a:visited { + color: $g-orange; + } +} + + +// DEBUG BAR +// ========================================================================== */ + +#debug-bar { + background-color: $t-light; + color: $g-gray; + + // Reset to prevent conflict with other CSS files + h1, + h2, + h3, + p, + a, + button, + table, + thead, + tr, + td, + button, + .toolbar { + background-color: transparent; + color: $g-gray; + } + + // Buttons + button { + background-color: $t-light; + } + + // Tables + table { + strong { + color: $g-orange; + } + + tbody tr { + &:hover { + background-color: $m-gray; + } + + &.current { + background-color: $m-orange; + + &:hover td { + background-color: $g-red; + color: $t-light; + } + } + } + } + + // The toolbar + .toolbar { + background-color: $t-light; + @include box-shadow(0, 0, 4px, $m-gray); + + img { + filter: brightness(0) invert(0.4); + } + } + + // Fixed top + &.fixed-top { + .toolbar { + @include box-shadow(0, 0, 4px, $m-gray); + } + + .tab { + @include box-shadow(0, 1px, 4px, $m-gray); + } + } + + // "Muted" elements + .muted { + color: $g-gray; + + td { + color: $m-gray; + } + + &:hover td { + color: $g-gray; + } + } + + // The toolbar preferences + #toolbar-position, + #toolbar-theme { + filter: brightness(0) invert(0.6); + } + + // The toolbar menus + .ci-label { + &.active { + background-color: $m-gray; + } + + &:hover { + background-color: $m-gray; + } + + .badge { + background-color: $g-red; + color: $t-light; + } + } + + // The tabs container + .tab { + background-color: $t-light; + @include box-shadow(0, -1px, 4px, $m-gray); + } + + // The "Timeline" tab + .timeline { + th, + td { + border-color: $m-gray; + } + + .timer { + background-color: $g-orange; + } + } +} + + +// DEBUG VIEW +// ========================================================================== */ + +.debug-view.show-view { + border-color: $g-orange; +} + +.debug-view-path { + background-color: $m-orange; + color: $g-gray; +} diff --git a/admin/css/debug-toolbar/toolbar.scss b/admin/css/debug-toolbar/toolbar.scss new file mode 100644 index 000000000000..65f4b802e22c --- /dev/null +++ b/admin/css/debug-toolbar/toolbar.scss @@ -0,0 +1,597 @@ +/** + * This file is part of the CodeIgniter 4 framework. + * + * (c) CodeIgniter Foundation + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +// IMPORTS +// ========================================================================== */ + +@import '_mixins'; +@import '_settings'; + +// DEBUG ICON +// ========================================================================== */ + +#debug-icon { + // Position + bottom: 0; + position: fixed; + right: 0; + z-index: 10000; + + // Size + height: 36px; + width: 36px; + + // Spacing + margin: 0; + padding: 0; + + // Content + clear: both; + text-align: center; + + cursor: pointer; + + a svg { + margin: 8px; + max-width: 20px; + max-height: 20px; + } + + &.fixed-top { + bottom: auto; + top: 0; + } + + .debug-bar-ndisplay { + display: none; + } +} + + +// DEBUG BAR +// ========================================================================== */ + +.debug-bar-vars { + cursor: pointer; +} + +#debug-bar { + // Position + bottom: 0; + left: 0; + position: fixed; + right: 0; + z-index: 10000; + + // Size + height: 36px; + + // Spacing + line-height: 36px; + + // Typography + font-family: $base-font; + font-size: $base-size; + font-weight: 400; + + // General elements + h1 { + display: flex; + font-weight: normal; + margin: 0 0 0 auto; + padding: 0; + font-family: $base-font; + + svg { + width: 16px; + margin-right: 5px; + } + } + + h2 { + font-weight: bold; + font-size: $base-size; + margin: 0; + padding: 5px 0 10px 0; + + span { + font-size: 13px; + } + } + + h3 { + font-size: $base-size - 4; + font-weight: 200; + margin: 0 0 0 10px; + padding: 0; + text-transform: uppercase; + } + + p { + font-size: $base-size - 4; + margin: 0 0 0 15px; + padding: 0; + } + + a { + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + + button { + border: 1px solid; + @include border-radius(4px); + cursor: pointer; + line-height: 15px; + + &:hover { + text-decoration: underline; + } + } + + table { + border-collapse: collapse; + font-size: $base-size - 2; + line-height: normal; + + // Tables indentation + margin: 5px 10px 15px 10px; + + // Make sure it still fits the container, even with the margins + width: calc(100% - 10px); + + strong { + font-weight: 500; + } + + th { + display: table-cell; + font-weight: 600; + padding-bottom: 0.7em; + text-align: left; + } + + tr { + border: none; + } + + td { + border: none; + display: table-cell; + margin: 0; + text-align: left; + + &:first-child { + max-width: 20%; + + &.narrow { + width: 7em; + } + } + } + } + + td[data-debugbar-route] { + form { + display: none; + } + + &:hover { + form { + display: block; + } + + &>div { + display: none; + } + } + + input[type=text] { + padding: 2px; + } + } + + // The toolbar + .toolbar { + display: flex; + overflow: hidden; + overflow-y: auto; + padding: 0 12px 0 12px; + + // Give room for OS X scrollbar + white-space: nowrap; + z-index: 10000; + // Endless rotate + .rotate { + animation: toolbar-rotate 9s linear infinite; + } + @keyframes toolbar-rotate { + to { + transform: rotate(360deg); + } + } + } + + // Fixed top + &.fixed-top { + bottom: auto; + top: 0; + + .tab { + bottom: auto; + top: 36px; + } + } + + // The toolbar preferences + #toolbar-position, + #toolbar-theme { + padding: 0 6px; + display: inline-flex; + vertical-align: top; + cursor: pointer; + + &:hover { + text-decoration: none; + } + } + + // The "Open/Close" toggle + #debug-bar-link { + display: flex; + padding: 6px; + cursor: pointer; + } + + // The toolbar menus + .ci-label { + display: inline-flex; + font-size: $base-size - 2; + + &:hover { + cursor: pointer; + } + + a { + color: inherit; + display: flex; + letter-spacing: normal; + padding: 0 10px; + text-decoration: none; + align-items: center; + } + + // The toolbar icons + img { + margin: 6px 3px 6px 0; + width: 16px !important; + } + + // The toolbar notification badges + .badge { + @include border-radius(12px); + display: inline-block; + font-size: 75%; + font-weight: bold; + line-height: 12px; + margin-left: 5px; + padding: 2px 5px; + text-align: center; + vertical-align: baseline; + white-space: nowrap; + } + } + + // The tabs container + .tab { + height: fit-content; + text-align: left; + bottom: 35px; + display: none; + left: 0; + max-height: 62%; + overflow: hidden; + overflow-y: auto; + padding: 1em 2em; + position: fixed; + right: 0; + z-index: 9999; + } + + // The "Timeline" tab + .timeline { + position: static; + display: table; + margin-left: 0; + width: 100%; + + th { + border-left: 1px solid; + font-size: $base-size - 4; + font-weight: 200; + padding: 5px 5px 10px 5px; + position: relative; + text-align: left; + + &:first-child { + border-left: 0; + } + } + + td { + border-left: 1px solid; + padding: 5px; + position: relative; + + &:first-child { + border-left: 0; + max-width: none; + } + + &.child-container { + padding: 0px; + + .timeline { + margin: 0px; + + td { + &:first-child { + &:not(.child-container) { + padding-left: calc(5px + 10px * var(--level)); + } + } + } + } + } + } + + .timer { + @include border-radius(4px); + display: inline-block; + padding: 5px; + position: absolute; + top: 30%; + } + + .timeline-parent { + cursor: pointer; + + td { + &:first-child { + nav { + background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; + background-position: 0 25%; + display: inline-block; + height: 15px; + width: 15px; + margin-right: 3px; + vertical-align: middle; + } + } + } + } + + .timeline-parent-open { + background-color: #DFDFDF; + + td { + &:first-child { + nav { + background-position: 0 75%; + } + } + } + } + + .child-row { + &:hover { + background: transparent; + } + } + } + + // The "Routes" tab + .route-params, + .route-params-item { + vertical-align: top; + + td:first-child { + font-style: italic; + padding-left: 1em; + text-align: right; + } + } + + // show tab + &>.debug-bar-dblock { + display: block; + } +} + + +// DEBUG VIEW +// ========================================================================== */ + +.debug-view.show-view { + border: 1px solid; + margin: 4px; +} + +.debug-view-path { + font-family: monospace; + font-size: $base-size - 4; + letter-spacing: normal; + min-height: 16px; + padding: 2px; + text-align: left; +} + +.show-view .debug-view-path { + display: block !important; +} + + +// RESPONSIVE DESIGN +// ========================================================================== */ + +@media screen and (max-width: 1024px) { + #debug-bar { + .ci-label { + img { + margin: unset + } + } + } + + .hide-sm { + display: none !important; + } +} + +@media screen and (max-width: 768px) { + #debug-bar { + table { + display: block; + overflow-x: auto; + font-size: 12px; + margin: 5px 5px 10px 5px; + + td, + th { + padding: 4px 6px; + } + } + + .timeline { + display: block; + white-space: nowrap; + font-size: 12px; + } + + .toolbar { + overflow-x: auto; + } + } + } + +// THEMES +// ========================================================================== */ + +// Default theme is "Light" +@import '_theme-light'; + +// If the browser supports "prefers-color-scheme" and the scheme is "Dark" +@media (prefers-color-scheme: dark) { + @import '_theme-dark'; +} + +// If we force the "Dark" theme +#toolbarContainer.dark { + @import '_theme-dark'; + + td[data-debugbar-route] input[type=text] { + background: #000; + color: #fff; + } +} + +// If we force the "Light" theme +#toolbarContainer.light { + @import '_theme-light'; +} + +// LAYOUT HELPERS +// ========================================================================== */ + +.debug-bar-width30 { + width: 30%; +} + +.debug-bar-width10 { + width: 10%; +} + +.debug-bar-width70p { + width: 70px; +} + +.debug-bar-width190p { + width: 190px; +} + +.debug-bar-width20e { + width: 20em; +} + +.debug-bar-width6r { + width: 6rem; +} + +.debug-bar-ndisplay { + display: none; +} + +.debug-bar-alignRight { + text-align: right; +} + +.debug-bar-alignLeft { + text-align: left; +} + +.debug-bar-noverflow { + overflow: hidden; +} + +.debug-bar-dtableRow { + display: table-row; +} + +.debug-bar-dinlineBlock { + display: inline-block; +} + +.debug-bar-pointer { + cursor: pointer; +} + +.debug-bar-mleft4 { + margin-left: 4px; +} + +.debug-bar-level-0 { + --level: 0; +} + +.debug-bar-level-1 { + --level: 1; +} + +.debug-bar-level-2 { + --level: 2; +} + +.debug-bar-level-3 { + --level: 3; +} + +.debug-bar-level-4 { + --level: 4; +} + +.debug-bar-level-5 { + --level: 5; +} + +.debug-bar-level-6 { + --level: 6; +} diff --git a/admin/docbot b/admin/docbot new file mode 100755 index 000000000000..c4dd8229c9ac --- /dev/null +++ b/admin/docbot @@ -0,0 +1,42 @@ +#!/bin/bash + +# Rebuild and deploy CodeIgniter4 under-development user guide +# +# This is a quick way to test user guide changes, and if they +# look good, to push them to the gh-pages branch of the +# development repository. +# +# This is not meant for updating the "stable" user guide. + +UPSTREAM=https://github.com/codeigniter4/CodeIgniter4.git + +# Prepare the nested repo clone folder +cd user_guide_src +rm -rf build/* +mkdir build/html + +# Get ready for git +cd build/html +git init +git remote add origin $UPSTREAM +git fetch +git checkout gh-pages +git reset --hard origin/gh-pages +rm -r * + +# Make the new user guide +cd ../.. +make html + +# All done? +if [ $# -lt 1 ]; then + exit 0 +fi + +# Optionally update the remote repo +if [ $1 = "deploy" ]; then + cd build/html + git add . + git commit -S -m "Docbot synching" + git push -f origin gh-pages +fi \ No newline at end of file diff --git a/admin/docbot.md b/admin/docbot.md new file mode 100644 index 000000000000..f40b81a35d77 --- /dev/null +++ b/admin/docbot.md @@ -0,0 +1,39 @@ +# docbot + +Builds & deploys user guide. + +The in-progress CI4 user guide, warts & all, is rebuilt in a nested +repository clone (`user_guide_src/build/html`), with the result +optionally pushed to the `gh-pages` branch of the repo. +That would then be publically visible as the in-progress +version of the [User Guide](https://codeigniter4.github.io/CodeIgniter4/). + +## Requirements + +You must have python & sphinx installed. + +## Audience + +This script is intended for use by framework maintainers, +i.e. someone with commit rights on the CI4 repository. + +This script wraps the conventional user guide building, +i.e. `user_guide_src/make html`, with additional +steps. + +You will be prompted for your github credentials and +GPG-signing key as appropriate. + +## Usage + +Inside a shell prompt, in the project root: + + `admin/docbot [deploy]` + +If "deploy" is not added, the script execution is considered +a trial run, and nothing is pushed to the repo. + +Whether or not deployed, the results are left inside +user_guide_src/build (which is git ignored). + +Generate these and the API docs together with the 'alldocs' script. diff --git a/admin/framework/.gitattributes b/admin/framework/.gitattributes new file mode 100644 index 000000000000..99484cbc3c97 --- /dev/null +++ b/admin/framework/.gitattributes @@ -0,0 +1,3 @@ +/.github export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/admin/framework/.github/workflows/close-pull-request.yml b/admin/framework/.github/workflows/close-pull-request.yml new file mode 100644 index 000000000000..96675f69e878 --- /dev/null +++ b/admin/framework/.github/workflows/close-pull-request.yml @@ -0,0 +1,24 @@ +name: Close Pull Request + +on: + pull_request_target: + types: [opened, reopened] + +permissions: + pull-requests: write + +jobs: + main: + runs-on: ubuntu-latest + steps: + - name: Close PR with nice message + run: gh pr close ${{ env.ISSUE }} -c "${{ env.COMMENT }}" + working-directory: ${{ github.workspace }} + env: + COMMENT: > + Thank you for your pull request. However, you have submitted your PR on a read-only + split of codeigniter4/CodeIgniter4. This repository, unfortunately, does + not accept PRs. Please submit your PR at https://github.com/codeigniter4/CodeIgniter4 + repository.

Thank you. + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE: ${{ github.event.pull_request.html_url }} diff --git a/admin/framework/.gitignore b/admin/framework/.gitignore new file mode 100644 index 000000000000..87e86b93bd42 --- /dev/null +++ b/admin/framework/.gitignore @@ -0,0 +1,126 @@ +#------------------------- +# Operating Specific Junk Files +#------------------------- + +# OS X +.DS_Store +.AppleDouble +.LSOverride + +# OS X Thumbnails +._* + +# Windows image file caches +Thumbs.db +ehthumbs.db +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Linux +*~ + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +#------------------------- +# Environment Files +#------------------------- +# These should never be under version control, +# as it poses a security risk. +.env +.vagrant +Vagrantfile + +#------------------------- +# Temporary Files +#------------------------- +writable/cache/* +!writable/cache/index.html + +writable/logs/* +!writable/logs/index.html + +writable/session/* +!writable/session/index.html + +writable/uploads/* +!writable/uploads/index.html + +writable/debugbar/* +!writable/debugbar/index.html + +php_errors.log + +#------------------------- +# User Guide Temp Files +#------------------------- +user_guide_src/build/* +user_guide_src/cilexer/build/* +user_guide_src/cilexer/dist/* +user_guide_src/cilexer/pycilexer.egg-info/* + +#------------------------- +# Test Files +#------------------------- +tests/coverage* + +# Don't save phpunit under version control. +phpunit + +#------------------------- +# Composer +#------------------------- +vendor/ + +#------------------------- +# IDE / Development Files +#------------------------- + +# Modules Testing +_modules/* + +# phpenv local config +.php-version + +# Jetbrains editors (PHPStorm, etc) +.idea/ +*.iml + +# NetBeans +/nbproject/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/nbactions.xml +/nb-configuration.xml +/.nb-gradle/ + +# Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache +*.sublime-workspace +*.sublime-project +.phpintel +/api/ + +# Visual Studio Code +.vscode/ + +/results/ +/phpunit*.xml diff --git a/admin/framework/README.md b/admin/framework/README.md new file mode 100644 index 000000000000..a23783ac316a --- /dev/null +++ b/admin/framework/README.md @@ -0,0 +1,60 @@ +# CodeIgniter 4 Framework + +## What is CodeIgniter? + +CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure. +More information can be found at the [official site](https://codeigniter.com). + +This repository holds the distributable version of the framework. +It has been built from the +[development repository](https://github.com/codeigniter4/CodeIgniter4). + +More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums. + +You can read the [user guide](https://codeigniter.com/user_guide/) +corresponding to the latest version of the framework. + +## Important Change with index.php + +`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. A better practice would be to configure a virtual host to point there. A poor practice would be to point your web server to the project root and expect to enter *public/...*, as the rest of your logic and the +framework are exposed. + +**Please** read the user guide for a better explanation of how CI4 works! + +## Repository Management + +We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages. +We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss +FEATURE REQUESTS. + +This repository is a "distribution" one, built by our release preparation script. +Problems with it can be raised on our forum, or as issues in the main repository. + +## Contributing + +We welcome contributions from the community. + +Please read the [*Contributing to CodeIgniter*](https://github.com/codeigniter4/CodeIgniter4/blob/develop/CONTRIBUTING.md) section in the development repository. + +## Server Requirements + +PHP version 8.1 or higher is required, with the following extensions installed: + +- [intl](http://php.net/manual/en/intl.requirements.php) +- [mbstring](http://php.net/manual/en/mbstring.installation.php) + +> [!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. +> - If you are still using PHP 7.4 or 8.0, you should upgrade immediately. +> - The end of life date for PHP 8.1 will be December 31, 2025. + +Additionally, make sure that the following extensions are enabled in your PHP: + +- json (enabled by default - don't turn it off) +- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL +- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library diff --git a/admin/framework/composer.json b/admin/framework/composer.json new file mode 100644 index 000000000000..7a6e1c58a1e1 --- /dev/null +++ b/admin/framework/composer.json @@ -0,0 +1,66 @@ +{ + "name": "codeigniter4/framework", + "description": "The CodeIgniter framework v4", + "license": "MIT", + "type": "project", + "homepage": "https://codeigniter.com", + "support": { + "forum": "https://forum.codeigniter.com/", + "source": "https://github.com/codeigniter4/CodeIgniter4", + "slack": "https://codeigniterchat.slack.com" + }, + "require": { + "php": "^8.1", + "ext-intl": "*", + "ext-mbstring": "*", + "laminas/laminas-escaper": "^2.17", + "psr/log": "^3.0" + }, + "require-dev": { + "codeigniter/coding-standard": "^1.7", + "fakerphp/faker": "^1.24", + "friendsofphp/php-cs-fixer": "^3.47.1", + "kint-php/kint": "^6.1", + "mikey179/vfsstream": "^1.6.12", + "nexusphp/cs-config": "^3.6", + "phpunit/phpunit": "^10.5.16 || ^11.2", + "predis/predis": "^3.0" + }, + "suggest": { + "ext-curl": "If you use CURLRequest class", + "ext-dom": "If you use TestResponse", + "ext-exif": "If you run Image class tests", + "ext-fileinfo": "Improves mime type detection for files", + "ext-gd": "If you use Image class GDHandler", + "ext-imagick": "If you use Image class ImageMagickHandler", + "ext-libxml": "If you use TestResponse", + "ext-memcache": "If you use Cache class MemcachedHandler with Memcache", + "ext-memcached": "If you use Cache class MemcachedHandler with Memcached", + "ext-mysqli": "If you use MySQL", + "ext-oci8": "If you use Oracle Database", + "ext-pgsql": "If you use PostgreSQL", + "ext-readline": "Improves CLI::input() usability", + "ext-redis": "If you use Cache class RedisHandler", + "ext-simplexml": "If you format XML", + "ext-sodium": "If you use Encryption SodiumHandler", + "ext-sqlite3": "If you use SQLite3", + "ext-sqlsrv": "If you use SQL Server", + "ext-xdebug": "If you use CIUnitTestCase::assertHeaderEmitted()" + }, + "autoload": { + "psr-4": { + "CodeIgniter\\": "system/" + }, + "exclude-from-classmap": [ + "**/Database/Migrations/**" + ] + }, + "config": { + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true + }, + "scripts": { + "test": "phpunit" + } +} diff --git a/admin/framework/phpunit.xml.dist b/admin/framework/phpunit.xml.dist new file mode 100644 index 000000000000..dea940878617 --- /dev/null +++ b/admin/framework/phpunit.xml.dist @@ -0,0 +1,63 @@ + + + + + + + + + + + + + ./tests + + + + + + + + + + ./app + + + ./app/Views + ./app/Config/Routes.php + + + + + + + + + + + + + + + diff --git a/admin/next-changelog-minor.rst b/admin/next-changelog-minor.rst new file mode 100644 index 000000000000..c22f0be7d9f3 --- /dev/null +++ b/admin/next-changelog-minor.rst @@ -0,0 +1,84 @@ +################# +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 new file mode 100644 index 000000000000..ed2ba70570b3 --- /dev/null +++ b/admin/next-changelog-patch.rst @@ -0,0 +1,35 @@ +################# +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 new file mode 100644 index 000000000000..e38bebe3c4a7 --- /dev/null +++ b/admin/next-upgrading-guide.rst @@ -0,0 +1,55 @@ +############################## +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 new file mode 100644 index 000000000000..19bec4f4726b --- /dev/null +++ b/admin/pre-commit @@ -0,0 +1,40 @@ +#!/bin/sh + +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..." + +if [ "$STAGED_PHP_FILES" != "" ]; then + echo "Linting PHP code..." + for FILE in $STAGED_PHP_FILES; do + php -l -d display_errors=0 "$PROJECT/$FILE" + + if [ $? != 0 ]; then + echo "Fix the error(s) before commit." + exit 1 + fi + + FILES="$FILES $FILE" + done +fi + +if [ "$FILES" != "" ]; then + echo "Running PHP CS Fixer..." + + # Run on whole codebase to skip on unnecessary filtering + composer cs + + if [ $? != 0 ]; then + echo "There are PHP files which are not following the coding standards. Please fix them before commit." + exit 1 + 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/prepare-release.php b/admin/prepare-release.php new file mode 100644 index 000000000000..5d66a43b8c86 --- /dev/null +++ b/admin/prepare-release.php @@ -0,0 +1,73 @@ +" . PHP_EOL; + echo "E.g.,: php {$argv[0]} 4.4.3" . PHP_EOL; + + exit(1); +} + +// Gets version number from argument. +$version = $argv[1]; // e.g., '4.4.3' +$versionParts = explode('.', $version); +$minor = $versionParts[0] . '.' . $versionParts[1]; + +// Creates a branch for release. +system('git switch develop'); +system('git branch -D release-' . $version); +system('git switch -c release-' . $version); + +// Updates version number in "CodeIgniter.php". +replace_file_content( + './system/CodeIgniter.php', + '/public const CI_VERSION = \'.*?\';/u', + "public const CI_VERSION = '{$version}';", +); + +// Updates version number in "conf.py". +replace_file_content( + './user_guide_src/source/conf.py', + '/^version = \'.*?\'/mu', + "version = '{$minor}'", +); +replace_file_content( + './user_guide_src/source/conf.py', + '/^release = \'.*?\'/mu', + "release = '{$version}'", +); + +// Updates version number in "phpdoc.dist.xml". +replace_file_content( + './phpdoc.dist.xml', + '!CodeIgniter v.*? API!mu', + "CodeIgniter v{$minor} API", +); +replace_file_content( + './phpdoc.dist.xml', + '//mu', + "", +); + +// Updates release date in changelogs. +$date = date('F j, Y'); +replace_file_content( + "./user_guide_src/source/changelogs/v{$version}.rst", + '/^Release Date: .*/mu', + "Release Date: {$date}", +); + +// Commits +system('git add -u'); +system('git commit -m "Prep for ' . $version . ' release"'); diff --git a/admin/release b/admin/release new file mode 100755 index 000000000000..d14167f0502e --- /dev/null +++ b/admin/release @@ -0,0 +1,145 @@ +#!/bin/bash + +## Build framework release branch & distributables + +# Setup variables +. admin/release-config + +echo -e "${BOLD}${COLOR}CodeIgniter4 release builder${NORMAL}" +echo '----------------------------' + +#--------------------------------------------------- +# Check arguments +echo -e "${BOLD}Checking arguments...${NORMAL}" + +if [ $# -lt 1 ]; then + echo -e "${BOLD}Usage: admin/release version# pre-release-qualifier${NORMAL}" + exit 1 +fi + +#--------------------------------------------------- +# Create the release branch +echo -e "${BOLD}Creating $which $branch to $action ${NORMAL}" + +git checkout develop +git branch -d $branch &>/dev/null # remove the branch if there +git checkout -b $branch +composer update + +#--------------------------------------------------- +# Update version dependencies +echo -e "${BOLD}Updating version dependencies${NORMAL}" + +function check_unique { + count=`grep -c '$1' < $2 | wc -l` + if [ $count -ne 1 ]; then + echo -e "${BOLD}${COLOR}$2 has ${count} occurrences of '$1'${NORMAL}" + exit 1 + fi +} + +# Make sure there is only one line to affect in each file +check_unique "const CI_VERSION" 'system/CodeIgniter.php' +check_unique "release =" 'user_guide_src/source/conf.py' +check_unique "|release|" 'user_guide_src/source/changelogs/index.rst' +check_unique "Release Date.*Not Released" 'user_guide_src/source/changelogs/index.rst' + +# CI_VERSION definition in system/CodeIgniter.php +sed -i "/const CI_VERSION/s/'.*'/'${RELEASE}'/" system/CodeIgniter.php + +# release substitution variable in user_guide_src/source/conf.py +sed -i "/release =/s/'.*'/'${RELEASE}'/" user_guide_src/source/conf.py + +# version & date in user_guide_src/source/index.rst +sed -i "/|release|/s/|.*|/${RELEASE}/" user_guide_src/source/changelogs/index.rst +sed -i "/Release Date/s/Not Released/$(date +'%B %d, %Y')/" user_guide_src/source/changelogs/index.rst +sed -i "/|version|/s/|version|/${RELEASE}/" user_guide_src/source/changelogs/index.rst + +# version & date in user_guide_src/source/next.rst +sed -i "/Release Date/s/Not Released/$(date +'%B %d, %Y')/" user_guide_src/source/changelogs/next.rst +sed -i "/|version|/s/|version|/${RELEASE}/" user_guide_src/source/changelogs/next.rst + +# establish version-specific changelog +sed -i "|changelogs/next|s|changeslog/next|changelogs/v{$RELEASE}|" user_guide_src/source/changelogs/index.rst +mv user_guide_src/source/changelogs/next.rst user_guide_src/source/changelogs/v${RELEASE}.rst +touch user_guide_src/source/changelogs/next.rst +cp admin/next.rst user_guide_src/source/changelogs/next.rst + +#--------------------------------------------------- +# Setup the distribution folders +echo -e "${BOLD}Building distribution folders${NORMAL}" + +function setup_repo { + echo -e "${BOLD}... $1${NORMAL}" + if [ -d dist/$1 ]; then + rm -rf dist/$1 + fi + mkdir dist/$1 + cd dist/$1 + git init + git remote add origin ${CI_ORG}/$1.git + git fetch + git checkout master + git checkout -b $branch + cd $CI_DIR +} + +if [ -d dist ]; then + rm -rf dist/ +fi +mkdir dist + +setup_repo userguide + +#--------------------------------------------------- +# Housekeeping - make sure writable is flushed of test files +# at least, test files that crop up on my system :-/ +rm -f writable/cache/H* +rm -f writable/cache/d* +rm -f writable/cache/s* +rm -f writable/debugbar/debug* +rm -f writable/logs/log* + +#--------------------------------------------------- +# Generate the user guide +echo -e "${BOLD}Generate the user guide${NORMAL}" + +cd user_guide_src + +# make the UG +rm -rf build/* +echo -e "${BOLD}... HTML version${NORMAL}" +make html +touch build/html/.nojekyll +echo -e "${BOLD}... epub version${NORMAL}" +make epub + +cd ${CI_DIR} + +# add changelog preamble +file=user_guide_src/source/changelogs/index.rst +sed -i "4 a Version |version|" $file +sed -i "5 a ====================================================" $file +sed -i "6 G" $file +sed -i "7 a Release Date: Not Released" $file +sed -i "8 G" $file +sed -i "9 a **Next release of CodeIgniter4**" $file +sed -i "10 G" $file +sed -i "11 G" $file +sed -i "12 a :doc:\`See all the changes. \`" $file +sed -i "13 G" $file + +#--------------------------------------------------- +echo -e "${BOLD}Commit the release branch${NORMAL}" +git add . +git commit -S -m "Release ${RELEASE}" + +#--------------------------------------------------- +# Build the distributables + +. admin/release-userguide + +#--------------------------------------------------- +# Done for now +echo -e "${BOLD}Your $branch branch is ready to inspect.${NORMAL}" +echo -e "${BOLD}Follow the directions in workflow.md to continue.${NORMAL}" diff --git a/admin/release-config b/admin/release-config new file mode 100644 index 000000000000..8a969af81c68 --- /dev/null +++ b/admin/release-config @@ -0,0 +1,26 @@ +# Variables used for release building + +if [ -z "$CI_ORG" ]; then + + # Initialize variables + CI_ORG=https://github.com/codeigniter4 + CI_DIR=`pwd` + + BOLD='\033[1m' + NORMAL='\033[0m' + COLOR='\033[1;31m' + ERROR='\033[0;31m' + + qualifier= + which=release + + version=$1 + if [ $# -gt 1 ]; then + qualifier="-${2}" + which='pre-release' + fi + + RELEASE=$version$qualifier + branch="release-$RELEASE" + +fi diff --git a/admin/release-deploy b/admin/release-deploy new file mode 100755 index 000000000000..fe70284024fc --- /dev/null +++ b/admin/release-deploy @@ -0,0 +1,31 @@ +#!/bin/bash + +## Push local changes to github + +echo -e "${BOLD}${COLOR}CodeIgniter4 release deployment${NORMAL}" +echo '-------------------------------' + +. admin/release-config + +echo -e "${BOLD}Merge release into develop${NORMAL}" +git checkout develop +git merge $branch +git push origin develop +git push ${CI_ORG}/CodeIgniter4 develop + +echo -e "${BOLD}Merge develop into master${NORMAL}" +git checkout master +git merge develop +git push origin master +git push ${CI_ORG}/CodeIgniter4 master + +echo -e "${BOLD}Pushing to the user guide repository${NORMAL}" +cd ${CI_DIR}/dist/userguide +git push origin master + +cd ${CI_DIR} + +#--------------------------------------------------- +# Phew! +echo -e "${BOLD}Congratulations - we have liftoff${NORMAL}" +echo "Don't forget to announce this release on the forum and on twitter!" diff --git a/admin/release-notes.bb b/admin/release-notes.bb new file mode 100755 index 000000000000..6147a011cde1 --- /dev/null +++ b/admin/release-notes.bb @@ -0,0 +1,43 @@ +CAUTION: THIS FILE IS A MIX OF BBCODE & MARKDOWN... NEEDS PROOFING + +CodeIgniter-4.0.0-alpha.1 launches today, after a lengthy build-up :) + +Huge shoutout to Lonnie Ezell for all of his hard work getting the vision +and the core implementation in place! + +This is an early pre-release of 4.0.0. It is not suitable for production! + +There are several possible downloads, that you can see on the +[url=https://github.com/codeigniter4/CodeIgniter4/releases/tag/v4.0.0-alpha.1]release page[/url]) + +- the runnable versions as a +[zip](https://github.com/codeigniter4/CodeIgniter4/releases/download/v4.0.0-alpha.1/CodeIgniter-4.0.0-alpha.1.zip) or a +[tarball](https://github.com/codeigniter4/CodeIgniter4/releases/download/v4.0.0-alpha.1/CodeIgniter-4.0.0-alpha.1.tar.gz)/ +- the developer versions of the framework (with contributor components) as +a [zip](https://github.com/codeigniter4/CodeIgniter4/archive/v4.0.0-alpha.1.zip) or a +[tarball](https://github.com/codeigniter4/CodeIgniter4/archive/v4.0.0-alpha.1.tar.gz)/ +- and finally the [epub](https://github.com/codeigniter4/CodeIgniter4/releases/download/v4.0.0-alpha.1/CodeIgniter-4.0.0-alpha.1.epub) version of the user guide for this release. + +The release has all the major features in place, but there are still gaps +and issues. See ... + +- [Bugs in the 4.0.0-alpha.1](https://github.com/codeigniter4/CodeIgniter4/issues?q=is%3Aopen+is%3Aissue+milestone%3A4.0.0-alpha) +- [Things that we definitely want to see fixed before first proper release](https://github.com/codeigniter4/CodeIgniter4/issues?q=is%3Aopen+is%3Aissue+milestone%3A4.0.0) +- [Features we would like to see in the initial proper release](), if possible, else the next update to it +- [Features that we are consciously deferring to later](https://github.com/codeigniter4/CodeIgniter4/issues?q=is%3Aopen+is%3Aissue+milestone%3A4.1.0) + +What we need now is feedback from the community ... + +- What doesn't work well (raise a post in [url=https://forum.codeigniter.com/forum-27.html]CodeIgniter 4 Development[/url]). +If you have found a bug, then by all means create a new issue on the repo. +- What you think is missing (raise a post in [url=https://forum.codeigniter.com/forum-29.html]CodeIgniter 4 Feature Requests[/url]) +We will soon start the [url=https://forum.codeigniter.com/forum-33.html]candidate new feature[/url] posts, +for those items in the feature requests forum that appear to have traction +- Problems that you are having using the release (raise a post in [url=https://forum.codeigniter.com/forum-30.html]CodeIgniter 4 Support[/url]) +Do NOT create repo issues with support questions - we are using github for bug and work package tracking + +Do NOT post support questions or feature requests in response to this thread - those +will be deleted. We are trying to make the best of the +limited resources that we have! + +Thank you, and ENJOY! \ No newline at end of file diff --git a/admin/release-revert b/admin/release-revert new file mode 100755 index 000000000000..1c8a4eacd504 --- /dev/null +++ b/admin/release-revert @@ -0,0 +1,26 @@ +#!/bin/bash + +## Revert local repos to pre-release state +echo -e "${BOLD}${COLOR}CodeIgniter4 release revert${NORMAL}" +echo '---------------------------' + +if [ $# -lt 2 ]; then + echo "You forgot the magic word" + exit 1 +fi +if [ $1 != 'please' ]; then + echo "What do you say?" + exit 1 +fi + +. admin/release-config + +echo -e "${BOLD}Reverting the main repository${NORMAL}" +git checkout master +git pull -f ${CI_ORG}/CodeIgniter4 master +git checkout develop +git pull -f${CI_ORG}/CodeIgniter4 develop + +#--------------------------------------------------- +# Phew! +echo -e "${BOLD}Congratulations - we have aborted liftoff${NORMAL}" diff --git a/admin/release-userguide b/admin/release-userguide new file mode 100755 index 000000000000..6a8beb7bcbaf --- /dev/null +++ b/admin/release-userguide @@ -0,0 +1,29 @@ +#!/bin/bash + +## Build user guide distributable + +# Setup variables +. admin/release-config +TARGET=dist/userguide +cd $TARGET +git checkout $branch + +#--------------------------------------------------- +echo -e "${BOLD}Build the user guide distributable${NORMAL}" + +cp -rf ${CI_DIR}/user_guide_src/build/html/* docs +cp -rf ${CI_DIR}/user_guide_src/build/epub/CodeIgniter4.epub ./CodeIgniter${RELEASE}.epub + +#--------------------------------------------------- +# And finally, get ready for merging +echo -e "${BOLD}Assemble the pieces...${NORMAL}" +git add . +git commit -S -m "Release ${RELEASE}" +git checkout master +git merge $branch + +cd $CI_DIR + +#--------------------------------------------------- +# Done for now +echo -e "${BOLD}Distributable user guide ready..${NORMAL}" diff --git a/admin/setup.sh b/admin/setup.sh new file mode 100644 index 000000000000..55adf547e4bd --- /dev/null +++ b/admin/setup.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +# Install a pre-commit hook that +# automatically runs php-cs-fixer to lint code +mkdir -p .git/hooks +cp admin/pre-commit .git/hooks/pre-commit +chmod +x .git/hooks/pre-commit diff --git a/admin/starter/.gitattributes b/admin/starter/.gitattributes new file mode 100644 index 000000000000..aacb20e85228 --- /dev/null +++ b/admin/starter/.gitattributes @@ -0,0 +1,2 @@ +/.gitattributes export-ignore +/.github export-ignore diff --git a/admin/starter/.github/workflows/close-pull-request.yml b/admin/starter/.github/workflows/close-pull-request.yml new file mode 100644 index 000000000000..96675f69e878 --- /dev/null +++ b/admin/starter/.github/workflows/close-pull-request.yml @@ -0,0 +1,24 @@ +name: Close Pull Request + +on: + pull_request_target: + types: [opened, reopened] + +permissions: + pull-requests: write + +jobs: + main: + runs-on: ubuntu-latest + steps: + - name: Close PR with nice message + run: gh pr close ${{ env.ISSUE }} -c "${{ env.COMMENT }}" + working-directory: ${{ github.workspace }} + env: + COMMENT: > + Thank you for your pull request. However, you have submitted your PR on a read-only + split of codeigniter4/CodeIgniter4. This repository, unfortunately, does + not accept PRs. Please submit your PR at https://github.com/codeigniter4/CodeIgniter4 + repository.

Thank you. + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE: ${{ github.event.pull_request.html_url }} diff --git a/admin/starter/.github/workflows/phpunit.yml b/admin/starter/.github/workflows/phpunit.yml new file mode 100644 index 000000000000..2be22ec16095 --- /dev/null +++ b/admin/starter/.github/workflows/phpunit.yml @@ -0,0 +1,51 @@ +name: PHPUnit + +on: + pull_request: + branches: + - develop + +jobs: + main: + name: Build and test + + strategy: + matrix: + php-versions: ['8.1', '8.3'] + + runs-on: ubuntu-latest + + if: (! contains(github.event.head_commit.message, '[ci skip]')) + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + tools: composer, pecl, phpunit + extensions: intl, json, mbstring, mysqlnd, xdebug, xml, sqlite3 + coverage: xdebug + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer install --no-progress --no-interaction --prefer-dist --optimize-autoloader + # To prevent rate limiting you may need to supply an OAuth token in Settings > Secrets + # env: + # https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens + # COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} + + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-text diff --git a/admin/starter/.gitignore b/admin/starter/.gitignore new file mode 100644 index 000000000000..87e86b93bd42 --- /dev/null +++ b/admin/starter/.gitignore @@ -0,0 +1,126 @@ +#------------------------- +# Operating Specific Junk Files +#------------------------- + +# OS X +.DS_Store +.AppleDouble +.LSOverride + +# OS X Thumbnails +._* + +# Windows image file caches +Thumbs.db +ehthumbs.db +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# Linux +*~ + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +#------------------------- +# Environment Files +#------------------------- +# These should never be under version control, +# as it poses a security risk. +.env +.vagrant +Vagrantfile + +#------------------------- +# Temporary Files +#------------------------- +writable/cache/* +!writable/cache/index.html + +writable/logs/* +!writable/logs/index.html + +writable/session/* +!writable/session/index.html + +writable/uploads/* +!writable/uploads/index.html + +writable/debugbar/* +!writable/debugbar/index.html + +php_errors.log + +#------------------------- +# User Guide Temp Files +#------------------------- +user_guide_src/build/* +user_guide_src/cilexer/build/* +user_guide_src/cilexer/dist/* +user_guide_src/cilexer/pycilexer.egg-info/* + +#------------------------- +# Test Files +#------------------------- +tests/coverage* + +# Don't save phpunit under version control. +phpunit + +#------------------------- +# Composer +#------------------------- +vendor/ + +#------------------------- +# IDE / Development Files +#------------------------- + +# Modules Testing +_modules/* + +# phpenv local config +.php-version + +# Jetbrains editors (PHPStorm, etc) +.idea/ +*.iml + +# NetBeans +/nbproject/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/nbactions.xml +/nb-configuration.xml +/.nb-gradle/ + +# Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache +*.sublime-workspace +*.sublime-project +.phpintel +/api/ + +# Visual Studio Code +.vscode/ + +/results/ +/phpunit*.xml diff --git a/admin/starter/README.md b/admin/starter/README.md new file mode 100644 index 000000000000..d14b4c9c804c --- /dev/null +++ b/admin/starter/README.md @@ -0,0 +1,68 @@ +# CodeIgniter 4 Application Starter + +## What is CodeIgniter? + +CodeIgniter is a PHP full-stack web framework that is light, fast, flexible and secure. +More information can be found at the [official site](https://codeigniter.com). + +This repository holds a composer-installable app starter. +It has been built from the +[development repository](https://github.com/codeigniter4/CodeIgniter4). + +More information about the plans for version 4 can be found in [CodeIgniter 4](https://forum.codeigniter.com/forumdisplay.php?fid=28) on the forums. + +You can read the [user guide](https://codeigniter.com/user_guide/) +corresponding to the latest version of the framework. + +## Installation & updates + +`composer create-project codeigniter4/appstarter` then `composer update` whenever +there is a new release of the framework. + +When updating, check the release notes to see if there are any changes you might need to apply +to your `app` folder. The affected files can be copied or merged from +`vendor/codeigniter4/framework/app`. + +## Setup + +Copy `env` to `.env` and tailor for your app, specifically the baseURL +and any database settings. + +## Important Change with index.php + +`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. A better practice would be to configure a virtual host to point there. A poor practice would be to point your web server to the project root and expect to enter *public/...*, as the rest of your logic and the +framework are exposed. + +**Please** read the user guide for a better explanation of how CI4 works! + +## Repository Management + +We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages. +We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss +FEATURE REQUESTS. + +This repository is a "distribution" one, built by our release preparation script. +Problems with it can be raised on our forum, or as issues in the main repository. + +## Server Requirements + +PHP version 8.1 or higher is required, with the following extensions installed: + +- [intl](http://php.net/manual/en/intl.requirements.php) +- [mbstring](http://php.net/manual/en/mbstring.installation.php) + +> [!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. +> - If you are still using PHP 7.4 or 8.0, you should upgrade immediately. +> - The end of life date for PHP 8.1 will be December 31, 2025. + +Additionally, make sure that the following extensions are enabled in your PHP: + +- json (enabled by default - don't turn it off) +- [mysqlnd](http://php.net/manual/en/mysqlnd.install.php) if you plan to use MySQL +- [libcurl](http://php.net/manual/en/curl.requirements.php) if you plan to use the HTTP\CURLRequest library diff --git a/admin/starter/app/Config/Paths.php b/admin/starter/app/Config/Paths.php new file mode 100644 index 000000000000..39a902029882 --- /dev/null +++ b/admin/starter/app/Config/Paths.php @@ -0,0 +1,78 @@ + 'vcs', + 'url' => GITHUB_URL, + ]; + } + + $array['require']['codeigniter4/codeigniter4'] = 'dev-develop'; + unset($array['require']['codeigniter4/framework']); + } else { + unset($array['minimum-stability']); + + if (isset($array['repositories'])) { + foreach ($array['repositories'] as $i => $repository) { + if ($repository['url'] === GITHUB_URL) { + unset($array['repositories'][$i]); + break; + } + } + + if (empty($array['repositories'])) { + unset($array['repositories']); + } + } + + $array['require']['codeigniter4/framework'] = LATEST_RELEASE; + unset($array['require']['codeigniter4/codeigniter4']); + } + + file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL); + + $modified[] = $file; + } else { + echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL; + } + } else { + echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL; + } +} + +$files = [ + __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php', + __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml.dist', + __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml', +]; + +foreach ($files as $file) { + if (is_file($file)) { + $contents = file_get_contents($file); + + if ($dev) { + $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents); + } else { + $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents); + } + + file_put_contents($file, $contents); + + $modified[] = $file; + } +} + +if ($modified === []) { + echo 'No files modified.' . PHP_EOL; +} else { + echo 'The following files were modified:' . PHP_EOL; + + foreach ($modified as $file) { + echo " * {$file}" . PHP_EOL; + } + + echo 'Run `composer update` to sync changes with your vendor folder.' . PHP_EOL; +} diff --git a/admin/starter/composer.json b/admin/starter/composer.json new file mode 100644 index 000000000000..38a51e29fb64 --- /dev/null +++ b/admin/starter/composer.json @@ -0,0 +1,43 @@ +{ + "name": "codeigniter4/appstarter", + "description": "CodeIgniter4 starter app", + "license": "MIT", + "type": "project", + "homepage": "https://codeigniter.com", + "support": { + "forum": "https://forum.codeigniter.com/", + "source": "https://github.com/codeigniter4/CodeIgniter4", + "slack": "https://codeigniterchat.slack.com" + }, + "require": { + "php": "^8.1", + "codeigniter4/framework": "^4.0" + }, + "require-dev": { + "fakerphp/faker": "^1.9", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": "^10.5.16" + }, + "autoload": { + "psr-4": { + "App\\": "app/", + "Config\\": "app/Config/" + }, + "exclude-from-classmap": [ + "**/Database/Migrations/**" + ] + }, + "autoload-dev": { + "psr-4": { + "Tests\\Support\\": "tests/_support" + } + }, + "config": { + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true + }, + "scripts": { + "test": "phpunit" + } +} diff --git a/admin/starter/phpunit.xml.dist b/admin/starter/phpunit.xml.dist new file mode 100644 index 000000000000..b408a99d988c --- /dev/null +++ b/admin/starter/phpunit.xml.dist @@ -0,0 +1,63 @@ + + + + + + + + + + + + + ./tests + + + + + + + + + + ./app + + + ./app/Views + ./app/Config/Routes.php + + + + + + + + + + + + + + + diff --git a/admin/starter/tests/.htaccess b/admin/starter/tests/.htaccess new file mode 100644 index 000000000000..3462048add78 --- /dev/null +++ b/admin/starter/tests/.htaccess @@ -0,0 +1,6 @@ + + Require all denied + + + Deny from all + diff --git a/admin/starter/tests/README.md b/admin/starter/tests/README.md new file mode 100644 index 000000000000..fc40e447301e --- /dev/null +++ b/admin/starter/tests/README.md @@ -0,0 +1,118 @@ +# Running Application Tests + +This is the quick-start to CodeIgniter testing. Its intent is to describe what +it takes to set up your application and get it ready to run unit tests. +It is not intended to be a full description of the test features that you can +use to test your application. Those details can be found in the documentation. + +## Resources + +* [CodeIgniter 4 User Guide on Testing](https://codeigniter.com/user_guide/testing/index.html) +* [PHPUnit docs](https://phpunit.de/documentation.html) +* [Any tutorials on Unit testing in CI4?](https://forum.codeigniter.com/showthread.php?tid=81830) + +## Requirements + +It is recommended to use the latest version of PHPUnit. At the time of this +writing, we are running version 9.x. Support for this has been built into the +**composer.json** file that ships with CodeIgniter and can easily be installed +via [Composer](https://getcomposer.org/) if you don't already have it installed globally. + +```console +> composer install +``` + +If running under macOS or Linux, you can create a symbolic link to make running tests a touch nicer. + +```console +> ln -s ./vendor/bin/phpunit ./phpunit +``` + +You also need to install [XDebug](https://xdebug.org/docs/install) in order +for code coverage to be calculated successfully. After installing `XDebug`, you must add `xdebug.mode=coverage` in the **php.ini** file to enable code coverage. + +## Setting Up + +A number of the tests use a running database. +In order to set up the database edit the details for the `tests` group in +**app/Config/Database.php** or **.env**. +Make sure that you provide a database engine that is currently running on your machine. +More details on a test database setup are in the +[Testing Your Database](https://codeigniter.com/user_guide/testing/database.html) section of the documentation. + +## Running the tests + +The entire test suite can be run by simply typing one command-line command from the main directory. + +```console +> ./phpunit +``` + +If you are using Windows, use the following command. + +```console +> vendor\bin\phpunit +``` + +You can limit tests to those within a single test directory by specifying the +directory name after phpunit. + +```console +> ./phpunit app/Models +``` + +## Generating Code Coverage + +To generate coverage information, including HTML reports you can view in your browser, +you can use the following command: + +```console +> ./phpunit --colors --coverage-text=tests/coverage.txt --coverage-html=tests/coverage/ -d memory_limit=1024m +``` + +This runs all of the tests again collecting information about how many lines, +functions, and files are tested. It also reports the percentage of the code that is covered by tests. +It is collected in two formats: a simple text file that provides an overview as well +as a comprehensive collection of HTML files that show the status of every line of code in the project. + +The text file can be found at **tests/coverage.txt**. +The HTML files can be viewed by opening **tests/coverage/index.html** in your favorite browser. + +## PHPUnit XML Configuration + +The repository has a ``phpunit.xml.dist`` file in the project root that's used for +PHPUnit configuration. This is used to provide a default configuration if you +do not have your own configuration file in the project root. + +The normal practice would be to copy ``phpunit.xml.dist`` to ``phpunit.xml`` +(which is git ignored), and to tailor it as you see fit. +For instance, you might wish to exclude database tests, or automatically generate +HTML code coverage reports. + +## Test Cases + +Every test needs a *test case*, or class that your tests extend. CodeIgniter 4 +provides one class that you may use directly: +* `CodeIgniter\Test\CIUnitTestCase` + +Most of the time you will want to write your own test cases that extend `CIUnitTestCase` +to hold functions and services common to your test suites. + +## Creating Tests + +All tests go in the **tests/** directory. Each test file is a class that extends a +**Test Case** (see above) and contains methods for the individual tests. These method +names must start with the word "test" and should have descriptive names for precisely what +they are testing: +`testUserCanModifyFile()` `testOutputColorMatchesInput()` `testIsLoggedInFailsWithInvalidUser()` + +Writing tests is an art, and there are many resources available to help learn how. +Review the links above and always pay attention to your code coverage. + +### Database Tests + +Tests can include migrating, seeding, and testing against a mock or live database. +Be sure to modify the test case (or create your own) to point to your seed and migrations +and include any additional steps to be run before tests in the `setUp()` method. +See [Testing Your Database](https://codeigniter.com/user_guide/testing/database.html) +for details. diff --git a/admin/starter/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php b/admin/starter/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php new file mode 100644 index 000000000000..a73356d3479a --- /dev/null +++ b/admin/starter/tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php @@ -0,0 +1,37 @@ +forge->addField('id'); + $this->forge->addField([ + 'name' => ['type' => 'varchar', 'constraint' => 31], + 'uid' => ['type' => 'varchar', 'constraint' => 31], + 'class' => ['type' => 'varchar', 'constraint' => 63], + 'icon' => ['type' => 'varchar', 'constraint' => 31], + 'summary' => ['type' => 'varchar', 'constraint' => 255], + 'created_at' => ['type' => 'datetime', 'null' => true], + 'updated_at' => ['type' => 'datetime', 'null' => true], + 'deleted_at' => ['type' => 'datetime', 'null' => true], + ]); + + $this->forge->addKey('name'); + $this->forge->addKey('uid'); + $this->forge->addKey(['deleted_at', 'id']); + $this->forge->addKey('created_at'); + + $this->forge->createTable('factories'); + } + + public function down(): void + { + $this->forge->dropTable('factories'); + } +} diff --git a/admin/starter/tests/_support/Database/Seeds/ExampleSeeder.php b/admin/starter/tests/_support/Database/Seeds/ExampleSeeder.php new file mode 100644 index 000000000000..619fc27a7292 --- /dev/null +++ b/admin/starter/tests/_support/Database/Seeds/ExampleSeeder.php @@ -0,0 +1,41 @@ + 'Test Factory', + 'uid' => 'test001', + 'class' => 'Factories\Tests\NewFactory', + 'icon' => 'fas fa-puzzle-piece', + 'summary' => 'Longer sample text for testing', + ], + [ + 'name' => 'Widget Factory', + 'uid' => 'widget', + 'class' => 'Factories\Tests\WidgetPlant', + 'icon' => 'fas fa-puzzle-piece', + 'summary' => 'Create widgets in your factory', + ], + [ + 'name' => 'Evil Factory', + 'uid' => 'evil-maker', + 'class' => 'Factories\Evil\MyFactory', + 'icon' => 'fas fa-book-dead', + 'summary' => 'Abandon all hope, ye who enter here', + ], + ]; + + $builder = $this->db->table('factories'); + + foreach ($factories as $factory) { + $builder->insert($factory); + } + } +} diff --git a/admin/starter/tests/_support/Libraries/ConfigReader.php b/admin/starter/tests/_support/Libraries/ConfigReader.php new file mode 100644 index 000000000000..0bb4a8fcf598 --- /dev/null +++ b/admin/starter/tests/_support/Libraries/ConfigReader.php @@ -0,0 +1,19 @@ +findAll(); + + // Make sure the count is as expected + $this->assertCount(3, $objects); + } + + public function testSoftDeleteLeavesRow(): void + { + $model = new ExampleModel(); + $this->setPrivateProperty($model, 'useSoftDeletes', true); + $this->setPrivateProperty($model, 'tempUseSoftDeletes', true); + + /** @var stdClass $object */ + $object = $model->first(); + $model->delete($object->id); + + // The model should no longer find it + $this->assertNull($model->find($object->id)); + + // ... but it should still be in the database + $result = $model->builder()->where('id', $object->id)->get()->getResult(); + + $this->assertCount(1, $result); + } +} diff --git a/application/index.html b/admin/starter/tests/index.html similarity index 100% rename from application/index.html rename to admin/starter/tests/index.html diff --git a/admin/starter/tests/session/ExampleSessionTest.php b/admin/starter/tests/session/ExampleSessionTest.php new file mode 100644 index 000000000000..33242a477112 --- /dev/null +++ b/admin/starter/tests/session/ExampleSessionTest.php @@ -0,0 +1,17 @@ +set('logged_in', 123); + $this->assertSame(123, $session->get('logged_in')); + } +} diff --git a/admin/starter/tests/unit/HealthTest.php b/admin/starter/tests/unit/HealthTest.php new file mode 100644 index 000000000000..b3e480f4b0bf --- /dev/null +++ b/admin/starter/tests/unit/HealthTest.php @@ -0,0 +1,49 @@ +assertTrue(defined('APPPATH')); + } + + public function testBaseUrlHasBeenSet(): void + { + $validation = service('validation'); + + $env = false; + + // Check the baseURL in .env + if (is_file(HOMEPATH . '.env')) { + $env = preg_grep('/^app\.baseURL = ./', file(HOMEPATH . '.env')) !== false; + } + + if ($env) { + // BaseURL in .env is a valid URL? + // phpunit.xml.dist sets app.baseURL in $_SERVER + // So if you set app.baseURL in .env, it takes precedence + $config = new App(); + $this->assertTrue( + $validation->check($config->baseURL, 'valid_url'), + 'baseURL "' . $config->baseURL . '" in .env is not valid URL', + ); + } + + // Get the baseURL in app/Config/App.php + // You can't use Config\App, because phpunit.xml.dist sets app.baseURL + $reader = new ConfigReader(); + + // BaseURL in app/Config/App.php is a valid URL? + $this->assertTrue( + $validation->check($reader->baseURL, 'valid_url'), + 'baseURL "' . $reader->baseURL . '" in app/Config/App.php is not valid URL', + ); + } +} diff --git a/admin/userguide/.github/scripts/deploy.sh b/admin/userguide/.github/scripts/deploy.sh new file mode 100755 index 000000000000..43e0675db0e6 --- /dev/null +++ b/admin/userguide/.github/scripts/deploy.sh @@ -0,0 +1,23 @@ +#!/bin/sh -e + +# Deploys the User Guide to the production +# website. Triggered by updates to the GitHub +# codeigniter4/userguide repo's master branch. +# See https://github.com/codeigniter4/userguide/blob/master/.github/workflows/deploy.yml + +REPO="/opt/userguide" +SITE="/home/public_html/userguides/userguide4" + +if [ "$(id -u)" = "0" ]; then + echo "Cannot be run as root. Please run as the user for deployment." + exit 1 +fi + +cd "$REPO" +git switch master +git pull + +cp -R "$REPO/docs" "$SITE.new" +mv "$SITE" "$SITE.old" +mv "$SITE.new" "$SITE" +rm -rf "$SITE.old" diff --git a/admin/userguide/.github/workflows/close-pull-request.yml b/admin/userguide/.github/workflows/close-pull-request.yml new file mode 100644 index 000000000000..96675f69e878 --- /dev/null +++ b/admin/userguide/.github/workflows/close-pull-request.yml @@ -0,0 +1,24 @@ +name: Close Pull Request + +on: + pull_request_target: + types: [opened, reopened] + +permissions: + pull-requests: write + +jobs: + main: + runs-on: ubuntu-latest + steps: + - name: Close PR with nice message + run: gh pr close ${{ env.ISSUE }} -c "${{ env.COMMENT }}" + working-directory: ${{ github.workspace }} + env: + COMMENT: > + Thank you for your pull request. However, you have submitted your PR on a read-only + split of codeigniter4/CodeIgniter4. This repository, unfortunately, does + not accept PRs. Please submit your PR at https://github.com/codeigniter4/CodeIgniter4 + repository.

Thank you. + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ISSUE: ${{ github.event.pull_request.html_url }} diff --git a/admin/userguide/.github/workflows/deploy.yml b/admin/userguide/.github/workflows/deploy.yml new file mode 100644 index 000000000000..d244eb415978 --- /dev/null +++ b/admin/userguide/.github/workflows/deploy.yml @@ -0,0 +1,22 @@ +# Deploys the User Guide to the production +# website whenever master branch is updated +name: Deploy Production + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: executing remote ssh commands using ssh key + uses: appleboy/ssh-action@master + with: + host: ${{ secrets.HOST }} + username: ${{ secrets.USERNAME }} + key: ${{ secrets.KEY }} + port: ${{ secrets.PORT }} + script: /opt/userguide/.github/scripts/deploy.sh diff --git a/admin/userguide/.gitignore b/admin/userguide/.gitignore new file mode 100644 index 000000000000..d0eba7f4bdaa --- /dev/null +++ b/admin/userguide/.gitignore @@ -0,0 +1,13 @@ +*/config/development +*/logs/log-*.php +!*/logs/index.html +*/cache/* +!*/cache/index.html +!*/cache/.htaccess + +user_guide_src/build/* +user_guide_src/cilexer/build/* +user_guide_src/cilexer/dist/* +user_guide_src/cilexer/pycilexer.egg-info/* + +/vendor/ diff --git a/admin/userguide/README.md b/admin/userguide/README.md new file mode 100644 index 000000000000..0ea07075db61 --- /dev/null +++ b/admin/userguide/README.md @@ -0,0 +1,15 @@ +# CodeIgniter 4 User Guide + +CodeIgniter 4 is a PHP web framework that is light, fast, flexible, and secure. +More information can be found at the [official site](http://codeigniter.com). + +**This is a read-only repository used to publish the user guide for the current release.** +It is built automatically as part of the framework release workflow, and pull +requests are not accepted here. + +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. + +If you feel that features are missing or unclear, please comment on our +[forum](https://forum.codeigniter.com/index.php), +in the appropriate CodeIgniter4 subforum. diff --git a/admin/workflow.md b/admin/workflow.md new file mode 100644 index 000000000000..85e38e018ec2 --- /dev/null +++ b/admin/workflow.md @@ -0,0 +1,92 @@ +# Workflow + +The main repo has two branches of interest: "master" (stable) and "develop" (in progress). +There might be other feature branches, but they are not relevant to this process. + +Once "develop" is ready for a new release, the general workflow is to + +release prep (`admin/release `)... +- create a "release" branch from develop +- update version dependencies or constants +- generate version(s) of the user guide +- move or ignore stuff, distinguishing release from development +- test that all is as it should be +- merge the release branch into "master" & "develop" + +After these have been vetted ... +- push the release(s) to github (`admin/release-deploy `) +- **manually** create the release & tag it on GitHub, based on master + Include any supplementary binaries as part of releases. +- Confirm the GitHub release action successfully deploys `appstarter` and `framework` +- **manually** post a sticky announcement thread on the forum +- **manually** tweet the release announcement + +## Assumptions + +You (a maintainer) have forked the main CodeIgniter4 repo, +and the git alias `origin`, in your local clone, refers to your fork. +The `config` script defines an additional alias, `CI_ORG`, which refers to the +CodeIgniter 4 organization on github. +This separation keeps the release branch isolated for any testing you want to do. + +The `develop` branch of the main repo should be "clean", and ready for +a release. This means that the changelog and upgrading instructions +have been suitably edited. + +This script is not intended to deal with hotfixes, i.e. PRs against +`master` that need to also be merged into `develop`, probably +as part of a bug fix minor release. + +## GitHub Action + +There is an action defined to run on any release publish event: +**.github/workflows/deploy.yml**. This will cascade any release made from +the main repo to the distribution repos, `appstarter` and `framework`. In order +for the action to authenticate you must create a Personal Access Token and add it +as a repo secret `ACCESS_TOKEN`. It is recommended that the PAT be to a secure bot +account with organization access that is dedicated for this purpose. + +If for some reason a release needs to be made that should not cascade the easiest +solution is to disable repo actions temporarily. + +## Usage + +Inside a shell prompt, in the project root: + + `admin/release version [qualifier]` + +Nothing is pushed to the repo at this point. You have a chance to vet +the repository changes. + +The "version" should follow semantic versioning, e.g. `4.0.6`, and the +version number should be higher than the current released one. + +The "qualifier" argument is a suffix to add to the version +for a pre-release, e.g. `beta.2` or `rc.41`. + +Examples: +- `admin/release 4.0.0 alpha.1` would prepare the "4.0.0-alpha.1" pre-release PR +- `admin/release 4.0.0` would prepare the "4.0.0" release PR +- `admin/release peanut butter banana` would complain and tell you to read these directions + +Once you have vetted the `dist` folder inside your local repo, you +can merge & push everything with + + `admin/release-deploy please` + +On github.com, create an appropriate release (or pre-release), +with any optional files from the root of `dist`. + +## Release notes + +On launch of a new release, a release notes post should be made in the +announcements subforum. The planned text for it (so it can be previewed +by admins) is in `admin/release_notes.bb`. + +## Audience + +These scripts are intended for use by framework maintainers, +i.e. someone with commit rights on the CI4 repositories. + +You will be prompted for your github credentials and +GPG-signing key as appropriate. diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 000000000000..3462048add78 --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,6 @@ + + Require all denied + + + Deny from all + diff --git a/app/Common.php b/app/Common.php new file mode 100644 index 000000000000..95f554425236 --- /dev/null +++ b/app/Common.php @@ -0,0 +1,15 @@ + + */ + public array $allowedHostnames = []; + + /** + * -------------------------------------------------------------------------- + * Index File + * -------------------------------------------------------------------------- + * + * Typically, this will be your `index.php` file, unless you've renamed it to + * something else. If you have configured your web server to remove this file + * from your site URIs, set this variable to an empty string. + */ + public string $indexPage = 'index.php'; + + /** + * -------------------------------------------------------------------------- + * URI PROTOCOL + * -------------------------------------------------------------------------- + * + * This item determines which server global should be used to retrieve the + * URI string. The default setting of 'REQUEST_URI' works for most servers. + * If your links do not seem to work, try one of the other delicious flavors: + * + * 'REQUEST_URI': Uses $_SERVER['REQUEST_URI'] + * 'QUERY_STRING': Uses $_SERVER['QUERY_STRING'] + * 'PATH_INFO': Uses $_SERVER['PATH_INFO'] + * + * WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded! + */ + public string $uriProtocol = 'REQUEST_URI'; + + /* + |-------------------------------------------------------------------------- + | Allowed URL Characters + |-------------------------------------------------------------------------- + | + | This lets you specify which characters are permitted within your URLs. + | When someone tries to submit a URL with disallowed characters they will + | get a warning message. + | + | As a security measure you are STRONGLY encouraged to restrict URLs to + | as few characters as possible. + | + | By default, only these are allowed: `a-z 0-9~%.:_-` + | + | Set an empty string to allow all characters -- but only if you are insane. + | + | The configured value is actually a regular expression character group + | and it will be used as: '/\A[]+\z/iu' + | + | DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!! + | + */ + public string $permittedURIChars = 'a-z 0-9~%.:_\-'; + + /** + * -------------------------------------------------------------------------- + * Default Locale + * -------------------------------------------------------------------------- + * + * The Locale roughly represents the language and location that your visitor + * is viewing the site from. It affects the language strings and other + * strings (like currency markers, numbers, etc), that your program + * should run under for this request. + */ + public string $defaultLocale = 'en'; + + /** + * -------------------------------------------------------------------------- + * Negotiate Locale + * -------------------------------------------------------------------------- + * + * If true, the current Request object will automatically determine the + * language to use based on the value of the Accept-Language header. + * + * If false, no automatic detection will be performed. + */ + public bool $negotiateLocale = false; + + /** + * -------------------------------------------------------------------------- + * Supported Locales + * -------------------------------------------------------------------------- + * + * If $negotiateLocale is true, this array lists the locales supported + * by the application in descending order of priority. If no match is + * found, the first locale will be used. + * + * IncomingRequest::setLocale() also uses this list. + * + * @var list + */ + public array $supportedLocales = ['en']; + + /** + * -------------------------------------------------------------------------- + * Application Timezone + * -------------------------------------------------------------------------- + * + * The default timezone that will be used in your application to display + * dates with the date helper, and can be retrieved through app_timezone() + * + * @see https://www.php.net/manual/en/timezones.php for list of timezones + * supported by PHP. + */ + public string $appTimezone = 'UTC'; + + /** + * -------------------------------------------------------------------------- + * Default Character Set + * -------------------------------------------------------------------------- + * + * This determines which character set is used by default in various methods + * that require a character set to be provided. + * + * @see http://php.net/htmlspecialchars for a list of supported charsets. + */ + public string $charset = 'UTF-8'; + + /** + * -------------------------------------------------------------------------- + * Force Global Secure Requests + * -------------------------------------------------------------------------- + * + * If true, this will force every request made to this application to be + * made via a secure connection (HTTPS). If the incoming request is not + * secure, the user will be redirected to a secure version of the page + * and the HTTP Strict Transport Security (HSTS) header will be set. + */ + public bool $forceGlobalSecureRequests = false; + + /** + * -------------------------------------------------------------------------- + * Reverse Proxy IPs + * -------------------------------------------------------------------------- + * + * If your server is behind a reverse proxy, you must whitelist the proxy + * IP addresses from which CodeIgniter should trust headers such as + * X-Forwarded-For or Client-IP in order to properly identify + * the visitor's IP address. + * + * You need to set a proxy IP address or IP address with subnets and + * the HTTP header for the client IP address. + * + * Here are some examples: + * [ + * '10.0.1.200' => 'X-Forwarded-For', + * '192.168.5.0/24' => 'X-Real-IP', + * ] + * + * @var array + */ + public array $proxyIPs = []; + + /** + * -------------------------------------------------------------------------- + * Content Security Policy + * -------------------------------------------------------------------------- + * + * Enables the Response's Content Secure Policy to restrict the sources that + * can be used for images, scripts, CSS files, audio, video, etc. If enabled, + * the Response object will populate default values for the policy from the + * `ContentSecurityPolicy.php` file. Controllers can always add to those + * restrictions at run time. + * + * For a better understanding of CSP, see these documents: + * + * @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/ + * @see http://www.w3.org/TR/CSP/ + */ + public bool $CSPEnabled = false; +} diff --git a/app/Config/Autoload.php b/app/Config/Autoload.php new file mode 100644 index 000000000000..9a928241a0eb --- /dev/null +++ b/app/Config/Autoload.php @@ -0,0 +1,92 @@ +|string> + */ + public $psr4 = [ + APP_NAMESPACE => APPPATH, + ]; + + /** + * ------------------------------------------------------------------- + * Class Map + * ------------------------------------------------------------------- + * The class map provides a map of class names and their exact + * location on the drive. Classes loaded in this manner will have + * slightly faster performance because they will not have to be + * searched for within one or more directories as they would if they + * were being autoloaded through a namespace. + * + * Prototype: + * $classmap = [ + * 'MyClass' => '/path/to/class/file.php' + * ]; + * + * @var array + */ + public $classmap = []; + + /** + * ------------------------------------------------------------------- + * Files + * ------------------------------------------------------------------- + * The files array provides a list of paths to __non-class__ files + * that will be autoloaded. This can be useful for bootstrap operations + * or for loading functions. + * + * Prototype: + * $files = [ + * '/path/to/my/file.php', + * ]; + * + * @var list + */ + public $files = []; + + /** + * ------------------------------------------------------------------- + * Helpers + * ------------------------------------------------------------------- + * Prototype: + * $helpers = [ + * 'form', + * ]; + * + * @var list + */ + public $helpers = []; +} diff --git a/app/Config/Boot/development.php b/app/Config/Boot/development.php new file mode 100644 index 000000000000..a868447a8e37 --- /dev/null +++ b/app/Config/Boot/development.php @@ -0,0 +1,34 @@ + WRITEPATH . 'cache/', + 'mode' => 0640, + ]; + + /** + * ------------------------------------------------------------------------- + * Memcached settings + * ------------------------------------------------------------------------- + * + * Your Memcached servers can be specified below, if you are using + * the Memcached drivers. + * + * @see https://codeigniter.com/user_guide/libraries/caching.html#memcached + * + * @var array{host?: string, port?: int, weight?: int, raw?: bool} + */ + public array $memcached = [ + 'host' => '127.0.0.1', + 'port' => 11211, + 'weight' => 1, + 'raw' => false, + ]; + + /** + * ------------------------------------------------------------------------- + * Redis settings + * ------------------------------------------------------------------------- + * + * Your Redis server can be specified below, if you are using + * the Redis or Predis drivers. + * + * @var array{host?: string, password?: string|null, port?: int, timeout?: int, database?: int} + */ + public array $redis = [ + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'timeout' => 0, + 'database' => 0, + ]; + + /** + * -------------------------------------------------------------------------- + * Available Cache Handlers + * -------------------------------------------------------------------------- + * + * This is an array of cache engine alias' and class names. Only engines + * that are listed here are allowed to be used. + * + * @var array> + */ + public array $validHandlers = [ + 'dummy' => DummyHandler::class, + 'file' => FileHandler::class, + 'memcached' => MemcachedHandler::class, + 'predis' => PredisHandler::class, + 'redis' => RedisHandler::class, + 'wincache' => WincacheHandler::class, + ]; + + /** + * -------------------------------------------------------------------------- + * Web Page Caching: Cache Include Query String + * -------------------------------------------------------------------------- + * + * Whether to take the URL query string into consideration when generating + * output cache files. Valid options are: + * + * false = Disabled + * true = Enabled, take all query parameters into account. + * Please be aware that this may result in numerous cache + * files generated for the same page over and over again. + * ['q'] = Enabled, but only take into account the specified list + * of query parameters. + * + * @var bool|list + */ + public $cacheQueryString = false; +} diff --git a/app/Config/Constants.php b/app/Config/Constants.php new file mode 100644 index 000000000000..fb56bb1c5b03 --- /dev/null +++ b/app/Config/Constants.php @@ -0,0 +1,79 @@ +|string|null + */ + public $defaultSrc; + + /** + * Lists allowed scripts' URLs. + * + * @var list|string + */ + public $scriptSrc = 'self'; + + /** + * Lists allowed stylesheets' URLs. + * + * @var list|string + */ + public $styleSrc = 'self'; + + /** + * Defines the origins from which images can be loaded. + * + * @var list|string + */ + public $imageSrc = 'self'; + + /** + * Restricts the URLs that can appear in a page's `` element. + * + * Will default to self if not overridden + * + * @var list|string|null + */ + public $baseURI; + + /** + * Lists the URLs for workers and embedded frame contents + * + * @var list|string + */ + public $childSrc = 'self'; + + /** + * Limits the origins that you can connect to (via XHR, + * WebSockets, and EventSource). + * + * @var list|string + */ + public $connectSrc = 'self'; + + /** + * Specifies the origins that can serve web fonts. + * + * @var list|string + */ + public $fontSrc; + + /** + * Lists valid endpoints for submission from `
` tags. + * + * @var list|string + */ + public $formAction = 'self'; + + /** + * Specifies the sources that can embed the current page. + * This directive applies to ``, `