diff --git a/.docker/Dockerfile b/.docker/Dockerfile new file mode 100644 index 0000000..631a66f --- /dev/null +++ b/.docker/Dockerfile @@ -0,0 +1,36 @@ +FROM php:8.4-cli-alpine + +# Install system dependencies +RUN apk add --no-cache \ + postgresql-dev \ + libpq \ + git \ + unzip \ + libzip-dev \ + icu-dev + +# Install PHP extensions +RUN docker-php-ext-install \ + pdo_pgsql \ + pgsql \ + zip \ + intl + +# Install pcov for code coverage +RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \ + && pecl install pcov \ + && docker-php-ext-enable pcov \ + && apk del .build-deps + +# Install Composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +WORKDIR /app + +COPY . /app + +RUN composer install --no-interaction --no-progress + +# Run the full test gate (PHPCS + PHPUnit) by default. +# pcov is available in the image for `composer test-cover`. +CMD ["composer", "test"] diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 7ad82eb..8320592 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -3,15 +3,39 @@ name: PHP Laravel Package on: [ push, pull_request ] jobs: - # phpcs: - # name: PHPCS - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v2 - # - name: PHPCS check - # uses: chekalsky/phpcs-action@v1 - # with: - # enable_warnings: true + lint: + name: Coding Standards (PHPCS) + runs-on: ubuntu-latest + timeout-minutes: 5 + + steps: + - uses: actions/checkout@v6 + + - name: Use PHP 8.4 + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: mbstring + coverage: none + + - name: Get Composer Cache Directory + id: composer-cache + run: | + echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: | + ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer update --prefer-dist --no-interaction + + - name: Run PHPCS + run: composer phpcs testing: name: Test on PHP ${{ matrix.php }} with ${{ matrix.setup }} dependencies @@ -23,15 +47,15 @@ jobs: fail-fast: false matrix: setup: [ 'basic', 'lowest', 'stable' ] - php: [ '8.2','8.3' ] + php: [ '8.4', '8.5' ] services: postgres: - image: postgres:15 + image: postgres:18 env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: postgres + POSTGRES_USER: forge + POSTGRES_PASSWORD: forge + POSTGRES_DB: forge ports: - 5432:5432 options: >- @@ -41,14 +65,14 @@ jobs: --health-retries 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Use PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 # Action page: with: php-version: ${{ matrix.php }} - extensions: mbstring - coverage: xdebug + extensions: mbstring, pdo_pgsql, pgsql + coverage: none - name: Get Composer Cache Directory # Docs: id: composer-cache @@ -68,15 +92,15 @@ jobs: - name: Install [LOWEST] Composer dependencies if: matrix.setup == 'lowest' - run: composer update --prefer-dist --no-interaction --no-suggest --prefer-lowest + run: composer update --prefer-dist --no-interaction --prefer-lowest - name: Install [BASIC] Composer dependencies if: matrix.setup == 'basic' - run: composer update --prefer-dist --no-interaction --no-suggest + run: composer update --prefer-dist --no-interaction - name: Install [STABLE] Composer dependencies if: matrix.setup == 'stable' - run: composer update --prefer-dist --no-interaction --no-suggest --prefer-stable + run: composer update --prefer-dist --no-interaction --prefer-stable - name: Show most important packages' versions run: composer info | grep -e efureev -e laravel/framework -e phpunit/phpunit @@ -89,6 +113,9 @@ jobs: env: DB_HOST: localhost DB_PORT: ${{ job.services.postgres.ports[5432] }} + DB_DATABASE: forge + DB_USERNAME: forge + DB_PASSWORD: forge release: name: Create Release @@ -97,15 +124,14 @@ jobs: if: ${{ startsWith(github.ref, 'refs/tags/v') && endsWith(github.ref, '.0') }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Create Release - id: create_release - uses: actions/create-release@v1 + uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} + tag_name: ${{ github.ref_name }} + name: Release ${{ github.ref_name }} draft: false prerelease: false diff --git a/.gitignore b/.gitignore index cb2ad02..9f447a0 100755 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,6 @@ composer.lock clover.xml /.git-hooks -phpunit.xml.dist +phpunit.xml /coverage /.phpunit.cache diff --git a/CHANGELOG.md b/CHANGELOG.md index 2910f69..e4cc9b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file. +## [4.0.0](https://github.com/efureev/laravel-support/compare/v3.0.0...v4.0.0) (2026-06-04) + +### ⚠ BREAKING CHANGES + +* Require PHP >= 8.4 and Laravel >= 13 +* Remove duplicate/obsolete functionality covered by Laravel 13: Caster (Geo/PgPoint/PgArray), LaraRequest, UUID trait and `user()` helper + +### Features + +* Upgrade to PHP 8.4 and Laravel 13 (promoted/readonly properties, strict types) +* Add Docker + docker-compose (PostgreSQL 18, pcov) test environment +* Migrate test suite to PHPUnit 13 (attributes, schema/env config) +* Modernize CI: dedicated PHPCS lint job, Composer cache, PostgreSQL 18 service, `softprops/action-gh-release` + +### Bug Fixes + +* `Delimited` rule: make it implicit so `min` rejects empty values; fix Postgres array casting in tests + +### Documentation + +* Split README/CHANGELOG into single sources, sync docs with current API, add upgrade guide + +--- + ## [3.0.0](https://github.com/efureev/laravel-support/compare/v2.1.0...v3.0.0) (2025-02-24) ### Features @@ -31,3 +55,504 @@ All notable changes to this project will be documented in this file. --- +## [1.19.0](https://github.com/efureev/laravel-support/compare/v1.18.1...v1.19.0) (2023-08-04) + +### Features + +* Divide EntityCacheTrait ([81c8cb](https://github.com/efureev/laravel-support/commit/81c8cbb539ea1e3be846ddaec0cdbc0c632e2294)) + + +--- + +## [1.18.1](https://github.com/efureev/laravel-support/compare/v1.18.0...v1.18.1) (2023-02-24) + + +--- + +## [1.18.0](https://github.com/efureev/laravel-support/compare/v1.17.1...v1.18.0) (2023-02-24) + +### Features + +* Add support Laravel 10 ([847a0a](https://github.com/efureev/laravel-support/commit/847a0a05aa5e673ef4cd1a7dff0da4119526777d)) + + +--- + +## [1.17.1](https://github.com/efureev/laravel-support/compare/v1.17.0...v1.17.1) (2022-08-17) + +### Features + +* Add support >= Laravel 9.25 ([332a90](https://github.com/efureev/laravel-support/commit/332a901a2c52799ea84098637c8bd7e5e8e3f5e7)) + + +--- + +## [1.17.0](https://github.com/efureev/laravel-support/compare/v1.16.5...v1.17.0) (2022-08-17) + +### Features + +* Add support `PHP 8.1` ([2d53f9](https://github.com/efureev/laravel-support/commit/2d53f9aad4ddb28a3f30af0bf3a9613e4a0ffa44)) + + +--- + +## [1.16.5](https://github.com/efureev/laravel-support/compare/v1.16.4...v1.16.5) (2022-06-29) +### Bug Fixes + +* CacheForgetByKey ([0e136b](https://github.com/efureev/laravel-support/commit/0e136ba5ee42555e4984ea09df828bc62d24d755)) + + +--- + +## [1.16.3](https://github.com/efureev/laravel-support/compare/v1.16.2...v1.16.3) (2022-04-28) +### Features + +* Add method getVersionFromFile to get version ([0c6cf9](https://github.com/efureev/laravel-support/commit/0c6cf917bc15e99b6769fe3c4c3e91d55c33156c), [11c66b](https://github.com/efureev/laravel-support/commit/11c66b124f0ca8592871c09952cde8fba2ec24e0)) + + +--- + +## [1.16.2](https://github.com/efureev/laravel-support/compare/v1.16.1...v1.16.2) (2022-04-22) +### Bug Fixes + +* CreateHttpRequests ([a4c5f1](https://github.com/efureev/laravel-support/commit/a4c5f1488ee50d1d159e73dac68624422e9aa858)) + + +--- + +## [1.16.1](https://github.com/efureev/laravel-support/compare/v1.16.0...v1.16.1) (2022-04-22) +### Features + +* Add some new funcs to CreateHttpRequests ([58a878](https://github.com/efureev/laravel-support/commit/58a878ac247529cfda98597a339278f0da37198b)) + + +--- + +## [1.16.0](https://github.com/efureev/laravel-support/compare/v1.15.2...v1.16.0) (2022-04-22) +### Features + +* Add trait `CreateHttpRequests` to `Test` ns ([a8d076](https://github.com/efureev/laravel-support/commit/a8d07600a421edc028171848ec3c379fe0ffe0d3)) + + +--- + +## [1.15.2](https://github.com/efureev/laravel-support/compare/v1.15.1...v1.15.2) (2022-04-15) + +--- + +## [1.15.1](https://github.com/efureev/laravel-support/compare/v1.15.0...v1.15.1) (2022-04-15) +### Bug Fixes + +* Set sorting position as integer ([57043c](https://github.com/efureev/laravel-support/commit/57043ccddfb739cd0877c98fa297b44c8d70ecb9)) + + +--- + +## [1.15.0](https://github.com/efureev/laravel-support/compare/v1.14.1...v1.15.0) (2022-03-23) +### Features + +* Add the global function `objectToArray` ([1e1b15](https://github.com/efureev/laravel-support/commit/1e1b15bd40155041866e875d390b0563aed6713c)) + + +--- + +## [1.14.1](https://github.com/efureev/laravel-support/compare/v1.14.0...v1.14.1) (2022-03-09) +### Features + +* Policies: divide a logic ([423bff](https://github.com/efureev/laravel-support/commit/423bffec139cf9828ef6beeefcff2391573b030d)) + + +--- + +## [1.14.0](https://github.com/efureev/laravel-support/compare/v1.13.3...v1.14.0) (2022-03-07) +### Features + +* Add registerInstance ([e10615](https://github.com/efureev/laravel-support/commit/e106157eddcd24fef93462e2f0b961ff934c659c)) + + +--- + +## [1.13.3](https://github.com/efureev/laravel-support/compare/v1.13.2...v1.13.3) (2022-03-04) + +--- + +## [1.13.2](https://github.com/efureev/laravel-support/compare/v1.13.1...v1.13.2) (2022-03-04) +### Bug Fixes + +* Cache ([500e3d](https://github.com/efureev/laravel-support/commit/500e3d1ff7e0dcbf67f7dd170f3e9836f9b828ce)) + + +--- + +## [1.13.1](https://github.com/efureev/laravel-support/compare/v1.13.0...v1.13.1) (2022-02-21) +### Features + +* Add afterInit method to LaraRequestServiceProvider ([7f5b24](https://github.com/efureev/laravel-support/commit/7f5b24cfe4bb26a41ca1e5ae3253c60ab165be9b)) + + +--- + +## [1.13.0](https://github.com/efureev/laravel-support/compare/v1.12.2...v1.13.0) (2022-02-08) +### Features + +* Add caster PgPoint ([328f30](https://github.com/efureev/laravel-support/commit/328f302068cf7e97131c5fa54768b703d1d195c1)) + + +--- + +## [1.12.2](https://github.com/efureev/laravel-support/compare/v1.12.1...v1.12.2) (2022-02-03) + +--- + +## [1.12.1](https://github.com/efureev/laravel-support/compare/v1.12.0...v1.12.1) (2022-02-03) + +--- + +## [1.12.0](https://github.com/efureev/laravel-support/compare/v1.11.1...v1.12.0) (2022-02-03) +### Features + +* Fix ServiceProviders ([b1af69](https://github.com/efureev/laravel-support/commit/b1af692b91365238ea9fc3573825bcd9c5be3844)) + + +--- + +## [1.11.1](https://github.com/efureev/laravel-support/compare/v1.11.0...v1.11.1) (2022-01-21) +### Bug Fixes + +* Caching ([2b5075](https://github.com/efureev/laravel-support/commit/2b5075224031f48b7880b55c49672f72e20fbf3e)) + + +--- + +## [1.11.0](https://github.com/efureev/laravel-support/compare/v1.10.3...v1.11.0) (2022-01-18) +### Features + +* Add HasModelEntityCache ([754117](https://github.com/efureev/laravel-support/commit/754117eb338e2034e228b498b2941686c594ca59)) + + +--- + +## [1.10.3](https://github.com/efureev/laravel-support/compare/v1.10.2...v1.10.3) (2021-12-15) +### Bug Fixes + +* LaraRequestServiceProvider ([2822de](https://github.com/efureev/laravel-support/commit/2822deb235c1272c68c8504ff057ce89c8b62cc2), [6d0b05](https://github.com/efureev/laravel-support/commit/6d0b05e6d5988fd9a68ef97d180ebe5b91e8fbd2)) + + +--- + +## [1.10.2](https://github.com/efureev/laravel-support/compare/v1.10.1...v1.10.2) (2021-11-22) + +--- + +## [1.10.1](https://github.com/efureev/laravel-support/compare/v1.10.0...v1.10.1) (2021-11-14) + +--- + +## [1.10.0](https://github.com/efureev/laravel-support/compare/v1.9.0...v1.10.0) (2021-11-14) +### Features + +* Add trait AllowToExecute ([0fda4d](https://github.com/efureev/laravel-support/commit/0fda4d0e83fcb38e1c699bf58c5a790379825644)) + + +--- + +## [1.9.0](https://github.com/efureev/laravel-support/compare/v1.8.0...v1.9.0) (2021-10-16) + +--- + +## [1.8.0](https://github.com/efureev/laravel-support/compare/v1.7.2...v1.8.0) (2021-10-07) + +--- + +## [1.7.2](https://github.com/efureev/laravel-support/compare/v1.7.1...v1.7.2) (2021-09-29) + +--- + +## [1.7.1](https://github.com/efureev/laravel-support/compare/v1.7.0...v1.7.1) (2021-09-29) +### Features + +* Add hasDeferredRelation to DeferredRelations ([a2a237](https://github.com/efureev/laravel-support/commit/a2a2377f624d109809388bb3514783f10d0f2daa)) + + +--- + +## [1.7.0](https://github.com/efureev/laravel-support/compare/v1.6.1...v1.7.0) (2021-09-29) +### Features + +* Add model`s trait DeferredRelations ([3af639](https://github.com/efureev/laravel-support/commit/3af639f43f5d346916f777eb5dea0cdffa9c0ccf)) + + +--- + +## [1.6.1](https://github.com/efureev/laravel-support/compare/v1.6.0...v1.6.1) (2021-09-21) + +--- + +## [1.6.0](https://github.com/efureev/laravel-support/compare/v1.5.0...v1.6.0) (2021-08-27) +### Features + +* Add some functions to HasValidate ([a95677](https://github.com/efureev/laravel-support/commit/a956778a62fa0829da182ba5120cb11a573956d6)) + + +--- + +## [1.5.0](https://github.com/efureev/laravel-support/compare/v1.4.0...v1.5.0) (2021-08-11) +### Features + +* Add HasMergeAdditional ([9992b6](https://github.com/efureev/laravel-support/commit/9992b67ddf072fd6029e35903e95de528246812b)) + + +--- + +## [1.4.0](https://github.com/efureev/laravel-support/compare/v1.3.1...v1.4.0) (2021-07-30) +### Features + +* Add GeoPoint caster ([c8f1e9](https://github.com/efureev/laravel-support/commit/c8f1e9dafac3820923a92b58fc331b2720da9c6b)) + + +--- + +## [1.3.1](https://github.com/efureev/laravel-support/compare/v1.3.0...v1.3.1) (2021-07-29) + +--- + +## [1.3.0](https://github.com/efureev/laravel-support/compare/v1.2.1...v1.3.0) (2021-07-29) +### Features + +* Add ServiceProvider helpers ([84ae6f](https://github.com/efureev/laravel-support/commit/84ae6fc087bbe252cb3282e6bbd3b805d7f3c446)) + + +--- + +## [1.2.1](https://github.com/efureev/laravel-support/compare/v1.2.0...v1.2.1) (2021-07-20) + +--- + +## [1.2.0](https://github.com/efureev/laravel-support/compare/v1.1.0...v1.2.0) (2021-07-20) +### Features + +* Add `validateValue` method ([29b085](https://github.com/efureev/laravel-support/commit/29b0857c37372fb555ffb12d6c2ee3186a014c08)) + + +--- + +## [1.1.0](https://github.com/efureev/laravel-support/compare/v1.0.1...v1.1.0) (2021-05-25) + +--- + +## [1.0.1](https://github.com/efureev/laravel-support/compare/v1.0.0...v1.0.1) (2021-05-24) + +--- + +## [1.0.0](https://github.com/efureev/laravel-support/compare/v0.11.5...v1.0.0) (2021-04-28) + +--- + +## [0.11.5](https://github.com/efureev/laravel-support/compare/v0.11.3...v0.11.5) (2021-02-16) + +--- + +## [0.11.3](https://github.com/efureev/laravel-support/compare/v0.11.4...v0.11.3) (2021-02-04) + +--- + +## [0.11.4](https://github.com/efureev/laravel-support/compare/v0.11.2...v0.11.4) (2021-02-04) + +--- + +## [0.11.2](https://github.com/efureev/laravel-support/compare/v0.11.1...v0.11.2) (2021-01-29) + +--- + +## [0.11.1](https://github.com/efureev/laravel-support/compare/v0.11.0...v0.11.1) (2021-01-28) + +--- + +## [0.11.0](https://github.com/efureev/laravel-support/compare/v0.10.3...v0.11.0) (2021-01-27) + +--- + +## [0.10.3](https://github.com/efureev/laravel-support/compare/v0.10.2...v0.10.3) (2021-01-26) + +--- + +## [0.10.2](https://github.com/efureev/laravel-support/compare/v0.10.1...v0.10.2) (2021-01-25) + +--- + +## [0.10.1](https://github.com/efureev/laravel-support/compare/v0.10.0...v0.10.1) (2021-01-25) + +--- + +## [0.10.0](https://github.com/efureev/laravel-support/compare/v0.9.6...v0.10.0) (2021-01-25) + +--- + +## [0.9.6](https://github.com/efureev/laravel-support/compare/v0.9.5...v0.9.6) (2020-12-28) + +--- + +## [0.9.5](https://github.com/efureev/laravel-support/compare/v0.9.4.2...v0.9.5) (2020-11-06) + +--- + +## [0.9.4.2](https://github.com/efureev/laravel-support/compare/v0.9.4.1...v0.9.4.2) (2020-09-16) + +--- + +## [0.9.4.1](https://github.com/efureev/laravel-support/compare/v0.9.4...v0.9.4.1) (2020-09-16) + +--- + +## [0.9.4](https://github.com/efureev/laravel-support/compare/v0.9.3.2...v0.9.4) (2020-09-16) + +--- + +## [0.9.3.2](https://github.com/efureev/laravel-support/compare/v0.9.3.1...v0.9.3.2) (2020-09-10) + +--- + +## [0.9.3.1](https://github.com/efureev/laravel-support/compare/v0.9.3...v0.9.3.1) (2020-09-07) + +--- + +## [0.9.3](https://github.com/efureev/laravel-support/compare/v0.9.2...v0.9.3) (2020-09-07) + +--- + +## [0.9.2](https://github.com/efureev/laravel-support/compare/v0.9.1...v0.9.2) (2020-08-14) + +--- + +## [0.9.1](https://github.com/efureev/laravel-support/compare/v0.9.0...v0.9.1) (2020-08-12) + +--- + +## [0.9.0](https://github.com/efureev/laravel-support/compare/v0.8.0...v0.9.0) (2020-08-12) + +--- + +## [0.8.0](https://github.com/efureev/laravel-support/compare/v0.7.9...v0.8.0) (2020-07-08) + +--- + +## [0.7.9](https://github.com/efureev/laravel-support/compare/v0.7.8...v0.7.9) (2020-07-06) + +--- + +## [0.7.8](https://github.com/efureev/laravel-support/compare/v0.7.7...v0.7.8) (2020-07-06) + +--- + +## [0.7.7](https://github.com/efureev/laravel-support/compare/v0.7.6...v0.7.7) (2020-07-06) + +--- + +## [0.7.6](https://github.com/efureev/laravel-support/compare/v0.7.5...v0.7.6) (2020-07-03) + +--- + +## [0.7.5](https://github.com/efureev/laravel-support/compare/v0.7.4...v0.7.5) (2020-07-02) + +--- + +## [0.7.4](https://github.com/efureev/laravel-support/compare/v0.7.3...v0.7.4) (2020-06-24) + +--- + +## [0.7.3](https://github.com/efureev/laravel-support/compare/v0.7.2...v0.7.3) (2020-06-23) + +--- + +## [0.7.2](https://github.com/efureev/laravel-support/compare/v0.7.1...v0.7.2) (2020-06-23) + +--- + +## [0.7.1](https://github.com/efureev/laravel-support/compare/v0.7.0...v0.7.1) (2020-06-23) + +--- + +## [0.7.0](https://github.com/efureev/laravel-support/compare/v0.6.0...v0.7.0) (2020-06-22) + +--- + +## [0.6.0](https://github.com/efureev/laravel-support/compare/v0.5.3...v0.6.0) (2020-06-15) + +--- + +## [0.5.3](https://github.com/efureev/laravel-support/compare/v0.5.2...v0.5.3) (2020-05-24) + +--- + +## [0.5.2](https://github.com/efureev/laravel-support/compare/v0.5.1...v0.5.2) (2020-05-24) + +--- + +## [0.5.1](https://github.com/efureev/laravel-support/compare/v0.5.0...v0.5.1) (2020-05-24) + +--- + +## [0.5.0](https://github.com/efureev/laravel-support/compare/v0.4.3...v0.5.0) (2020-05-23) + +--- + +## [0.4.3](https://github.com/efureev/laravel-support/compare/v0.4.2...v0.4.3) (2020-05-23) + +--- + +## [0.4.2](https://github.com/efureev/laravel-support/compare/v0.4.1...v0.4.2) (2020-04-10) + +--- + +## [0.4.1](https://github.com/efureev/laravel-support/compare/v0.4.0...v0.4.1) (2020-04-06) + +--- + +## [0.4.0](https://github.com/efureev/laravel-support/compare/v0.3.4...v0.4.0) (2020-04-04) + +--- + +## [0.3.4](https://github.com/efureev/laravel-support/compare/v0.3.3...v0.3.4) (2020-03-05) + +--- + +## [0.3.3](https://github.com/efureev/laravel-support/compare/v0.3.2...v0.3.3) (2020-02-25) + +--- + +## [0.3.2](https://github.com/efureev/laravel-support/compare/v0.3.1...v0.3.2) (2020-02-19) + +--- + +## [0.3.1](https://github.com/efureev/laravel-support/compare/v0.3.0...v0.3.1) (2020-02-19) + +--- + +## [0.3.0](https://github.com/efureev/laravel-support/compare/v0.2.1...v0.3.0) (2020-02-18) + +--- + +## [0.2.1](https://github.com/efureev/laravel-support/compare/v0.2.0...v0.2.1) (2020-02-11) + +--- + +## [0.2.0](https://github.com/efureev/laravel-support/compare/v0.1.0...v0.2.0) (2020-02-06) + +--- + +## [0.1.0](https://github.com/efureev/laravel-support/compare/v0.0.3...v0.1.0) (2020-01-29) + +--- + +## [0.0.3](https://github.com/efureev/laravel-support/compare/v0.0.2...v0.0.3) (2020-01-28) + +--- + +## [0.0.2](https://github.com/efureev/laravel-support/compare/v0.0.1...v0.0.2) (2020-01-28) + +--- + +## [0.0.1](https://github.com/efureev/laravel-support/compare/19bad4a26e54f968db9f7c4efd7be1dc97712a0d...v0.0.1) (2020-01-28) + +--- + diff --git a/LICENSE b/LICENSE index d1e20b1..f557125 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 feugene +Copyright (c) 2026 feugene Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 567b129..75e795e 100644 --- a/README.md +++ b/README.md @@ -1,514 +1,102 @@ - -# Changelog +# PHP Laravel Support -All notable changes to this project will be documented in this file. - +![](https://img.shields.io/badge/php->=8.4-blue.svg) +![](https://img.shields.io/badge/Laravel->=13.0-red.svg) +[![PHP Laravel Package](https://github.com/efureev/laravel-support/actions/workflows/php.yml/badge.svg)](https://github.com/efureev/laravel-support/actions/workflows/php.yml) +[![Latest Stable Version](https://poser.pugx.org/efureev/laravel-support/v/stable?format=flat)](https://packagist.org/packages/efureev/laravel-support) +[![Total Downloads](https://poser.pugx.org/efureev/laravel-support/downloads)](https://packagist.org/packages/efureev/laravel-support) +[![License](https://poser.pugx.org/efureev/laravel-support/license)](https://packagist.org/packages/efureev/laravel-support) -## [3.0.0](https://github.com/efureev/laravel-support/compare/v2.1.0...v3.0.0) (2025-02-24) +A collection of helpers, traits, validation rules and service-provider utilities for modern Laravel applications. -### Features +## Requirements -* Add Laravel 12 support +* PHP `>= 8.4` +* Laravel `>= 13.0` +## Install -## [1.19.0](https://github.com/efureev/laravel-support/compare/v1.18.1...v1.19.0) (2023-08-04) +```bash +composer require efureev/laravel-support +``` -### Features +The package is auto-discovered, no manual provider registration is required. -* Divide EntityCacheTrait ([81c8cb](https://github.com/efureev/laravel-support/commit/81c8cbb539ea1e3be846ddaec0cdbc0c632e2294)) +## Features +The full documentation lives in [`/docs`](docs/index.md). Below is a short overview. ---- +### Validation rules — `Php\Support\Laravel\Rules` -## [1.18.1](https://github.com/efureev/laravel-support/compare/v1.18.0...v1.18.1) (2023-02-24) +* `Delimited` — validates a delimited string (e.g. comma-separated emails), with `min`/`max`, custom separator, + duplicate control and trimming options. +* `Authorized` — validates that the current user is authorized (`can`) to use a given model by its key. +* `HasValidate` — helper trait that adds reusable `validate`/`validateValue` helpers. +### Eloquent traits — `Php\Support\Laravel\Traits` ---- +* `Traits\Models\PostgresArray` — query scopes for searching inside native PostgreSQL arrays + (`wherePgArrayContains`, `wherePgArrayContainsAny`, `wherePgArrayContainsOnly`, `wherePgArrayOverlapWith`). + See `\Php\Support\Laravel\Tests\TestClasses\Models\PgArrayModel::scopeByTag`. +* `Traits\Models\HasModelEntityCache` — cache layer for model entities (with pluggable cachers). +* `Traits\Models\AllowToExecute` — guard helpers for model actions. +* `Traits\Models\WrapQuery` — query-wrapping helpers. +* `Traits\Modelable` / `Traits\ModelQueryable` — bind an Eloquent model into a request/class. +* `Traits\Requests\RequestModelable` — model resolution from requests. +* `Traits\Resources\HasMergeAdditional` — merge additional data into API resources. -## [1.18.0](https://github.com/efureev/laravel-support/compare/v1.17.1...v1.18.0) (2023-02-24) +### Sorting — `Php\Support\Laravel\Sorting` -### Features +* `Sorting\Model\Sortable` — model trait to make records sortable (works with drag'n'drop). +* `Sorting\Database\Sortable` — migration helpers (`columnSortingPosition`). -* Add support Laravel 10 ([847a0a](https://github.com/efureev/laravel-support/commit/847a0a05aa5e673ef4cd1a7dff0da4119526777d)) +See [docs/sortable.md](docs/sortable.md). +### Service providers — `Php\Support\Laravel\ServiceProviders` ---- +`AbstractServiceProvider` aggregates a set of helper traits: `HasCommands`, `HasPolicies`, +`HasPathHelpers`, `HasRegisters`, `HasBooting`. See [docs/sp.md](docs/sp.md). -## [1.17.1](https://github.com/efureev/laravel-support/compare/v1.17.0...v1.17.1) (2022-08-17) +### Pagination & Repositories -### Features +* `Pagination\PaginatedResourceArray` — nested paginated resource collections. See [docs/pagination.md](docs/pagination.md). +* `Repositories\AbstractRepository` — base Eloquent repository. See [docs/repository.md](docs/repository.md). -* Add support >= Laravel 9.25 ([332a90](https://github.com/efureev/laravel-support/commit/332a901a2c52799ea84098637c8bd7e5e8e3f5e7)) +### Global helpers — `src/Global/base.php` +Autoloaded functions: `toCollect()`, `objectToArray()`. See [docs/global.md](docs/global.md). ---- +## Test -## [1.17.0](https://github.com/efureev/laravel-support/compare/v1.16.5...v1.17.0) (2022-08-17) +### Local -### Features +```bash +composer test # PHPCS + PHPUnit +composer test-cover # with coverage +``` -* Add support `PHP 8.1` ([2d53f9](https://github.com/efureev/laravel-support/commit/2d53f9aad4ddb28a3f30af0bf3a9613e4a0ffa44)) +### Docker +Runs the full test gate (PHPCS + PHPUnit) against PostgreSQL 18 inside containers. +No local PostgreSQL installation is required. ---- +```bash +composer test:docker +# or +docker compose up --build --abort-on-container-exit --exit-code-from app +``` -## [1.16.5](https://github.com/efureev/laravel-support/compare/v1.16.4...v1.16.5) (2022-06-29) -### Bug Fixes +## Development -* CacheForgetByKey ([0e136b](https://github.com/efureev/laravel-support/commit/0e136ba5ee42555e4984ea09df828bc62d24d755)) +This is a library, so `composer.lock` is intentionally **not** committed and `"lock": false` is set in +`composer.json`. Every CI run (and local `composer update`) resolves the latest matching dependency versions, +which surfaces incompatibilities with new Laravel/PHP releases early. Pin versions in the consuming application, +not here. +## Changelog ---- +See [CHANGELOG.md](CHANGELOG.md). -## [1.16.3](https://github.com/efureev/laravel-support/compare/v1.16.2...v1.16.3) (2022-04-28) -### Features - -* Add method getVersionFromFile to get version ([0c6cf9](https://github.com/efureev/laravel-support/commit/0c6cf917bc15e99b6769fe3c4c3e91d55c33156c), [11c66b](https://github.com/efureev/laravel-support/commit/11c66b124f0ca8592871c09952cde8fba2ec24e0)) - - ---- - -## [1.16.2](https://github.com/efureev/laravel-support/compare/v1.16.1...v1.16.2) (2022-04-22) -### Bug Fixes - -* CreateHttpRequests ([a4c5f1](https://github.com/efureev/laravel-support/commit/a4c5f1488ee50d1d159e73dac68624422e9aa858)) - - ---- - -## [1.16.1](https://github.com/efureev/laravel-support/compare/v1.16.0...v1.16.1) (2022-04-22) -### Features - -* Add some new funcs to CreateHttpRequests ([58a878](https://github.com/efureev/laravel-support/commit/58a878ac247529cfda98597a339278f0da37198b)) - - ---- - -## [1.16.0](https://github.com/efureev/laravel-support/compare/v1.15.2...v1.16.0) (2022-04-22) -### Features - -* Add trait `CreateHttpRequests` to `Test` ns ([a8d076](https://github.com/efureev/laravel-support/commit/a8d07600a421edc028171848ec3c379fe0ffe0d3)) - - ---- - -## [1.15.2](https://github.com/efureev/laravel-support/compare/v1.15.1...v1.15.2) (2022-04-15) - ---- - -## [1.15.1](https://github.com/efureev/laravel-support/compare/v1.15.0...v1.15.1) (2022-04-15) -### Bug Fixes - -* Set sorting position as integer ([57043c](https://github.com/efureev/laravel-support/commit/57043ccddfb739cd0877c98fa297b44c8d70ecb9)) - - ---- - -## [1.15.0](https://github.com/efureev/laravel-support/compare/v1.14.1...v1.15.0) (2022-03-23) -### Features - -* Add the global function `objectToArray` ([1e1b15](https://github.com/efureev/laravel-support/commit/1e1b15bd40155041866e875d390b0563aed6713c)) - - ---- - -## [1.14.1](https://github.com/efureev/laravel-support/compare/v1.14.0...v1.14.1) (2022-03-09) -### Features - -* Policies: divide a logic ([423bff](https://github.com/efureev/laravel-support/commit/423bffec139cf9828ef6beeefcff2391573b030d)) - - ---- - -## [1.14.0](https://github.com/efureev/laravel-support/compare/v1.13.3...v1.14.0) (2022-03-07) -### Features - -* Add registerInstance ([e10615](https://github.com/efureev/laravel-support/commit/e106157eddcd24fef93462e2f0b961ff934c659c)) - - ---- - -## [1.13.3](https://github.com/efureev/laravel-support/compare/v1.13.2...v1.13.3) (2022-03-04) - ---- - -## [1.13.2](https://github.com/efureev/laravel-support/compare/v1.13.1...v1.13.2) (2022-03-04) -### Bug Fixes - -* Cache ([500e3d](https://github.com/efureev/laravel-support/commit/500e3d1ff7e0dcbf67f7dd170f3e9836f9b828ce)) - - ---- - -## [1.13.1](https://github.com/efureev/laravel-support/compare/v1.13.0...v1.13.1) (2022-02-21) -### Features - -* Add afterInit method to LaraRequestServiceProvider ([7f5b24](https://github.com/efureev/laravel-support/commit/7f5b24cfe4bb26a41ca1e5ae3253c60ab165be9b)) - - ---- - -## [1.13.0](https://github.com/efureev/laravel-support/compare/v1.12.2...v1.13.0) (2022-02-08) -### Features - -* Add caster PgPoint ([328f30](https://github.com/efureev/laravel-support/commit/328f302068cf7e97131c5fa54768b703d1d195c1)) - - ---- - -## [1.12.2](https://github.com/efureev/laravel-support/compare/v1.12.1...v1.12.2) (2022-02-03) - ---- - -## [1.12.1](https://github.com/efureev/laravel-support/compare/v1.12.0...v1.12.1) (2022-02-03) - ---- - -## [1.12.0](https://github.com/efureev/laravel-support/compare/v1.11.1...v1.12.0) (2022-02-03) -### Features - -* Fix ServiceProviders ([b1af69](https://github.com/efureev/laravel-support/commit/b1af692b91365238ea9fc3573825bcd9c5be3844)) - - ---- - -## [1.11.1](https://github.com/efureev/laravel-support/compare/v1.11.0...v1.11.1) (2022-01-21) -### Bug Fixes - -* Caching ([2b5075](https://github.com/efureev/laravel-support/commit/2b5075224031f48b7880b55c49672f72e20fbf3e)) - - ---- - -## [1.11.0](https://github.com/efureev/laravel-support/compare/v1.10.3...v1.11.0) (2022-01-18) -### Features - -* Add HasModelEntityCache ([754117](https://github.com/efureev/laravel-support/commit/754117eb338e2034e228b498b2941686c594ca59)) - - ---- - -## [1.10.3](https://github.com/efureev/laravel-support/compare/v1.10.2...v1.10.3) (2021-12-15) -### Bug Fixes - -* LaraRequestServiceProvider ([2822de](https://github.com/efureev/laravel-support/commit/2822deb235c1272c68c8504ff057ce89c8b62cc2), [6d0b05](https://github.com/efureev/laravel-support/commit/6d0b05e6d5988fd9a68ef97d180ebe5b91e8fbd2)) - - ---- - -## [1.10.2](https://github.com/efureev/laravel-support/compare/v1.10.1...v1.10.2) (2021-11-22) - ---- - -## [1.10.1](https://github.com/efureev/laravel-support/compare/v1.10.0...v1.10.1) (2021-11-14) - ---- - -## [1.10.0](https://github.com/efureev/laravel-support/compare/v1.9.0...v1.10.0) (2021-11-14) -### Features - -* Add trait AllowToExecute ([0fda4d](https://github.com/efureev/laravel-support/commit/0fda4d0e83fcb38e1c699bf58c5a790379825644)) - - ---- - -## [1.9.0](https://github.com/efureev/laravel-support/compare/v1.8.0...v1.9.0) (2021-10-16) - ---- - -## [1.8.0](https://github.com/efureev/laravel-support/compare/v1.7.2...v1.8.0) (2021-10-07) - ---- - -## [1.7.2](https://github.com/efureev/laravel-support/compare/v1.7.1...v1.7.2) (2021-09-29) - ---- - -## [1.7.1](https://github.com/efureev/laravel-support/compare/v1.7.0...v1.7.1) (2021-09-29) -### Features - -* Add hasDeferredRelation to DeferredRelations ([a2a237](https://github.com/efureev/laravel-support/commit/a2a2377f624d109809388bb3514783f10d0f2daa)) - - ---- - -## [1.7.0](https://github.com/efureev/laravel-support/compare/v1.6.1...v1.7.0) (2021-09-29) -### Features - -* Add model`s trait DeferredRelations ([3af639](https://github.com/efureev/laravel-support/commit/3af639f43f5d346916f777eb5dea0cdffa9c0ccf)) - - ---- - -## [1.6.1](https://github.com/efureev/laravel-support/compare/v1.6.0...v1.6.1) (2021-09-21) - ---- - -## [1.6.0](https://github.com/efureev/laravel-support/compare/v1.5.0...v1.6.0) (2021-08-27) -### Features - -* Add some functions to HasValidate ([a95677](https://github.com/efureev/laravel-support/commit/a956778a62fa0829da182ba5120cb11a573956d6)) - - ---- - -## [1.5.0](https://github.com/efureev/laravel-support/compare/v1.4.0...v1.5.0) (2021-08-11) -### Features - -* Add HasMergeAdditional ([9992b6](https://github.com/efureev/laravel-support/commit/9992b67ddf072fd6029e35903e95de528246812b)) - - ---- - -## [1.4.0](https://github.com/efureev/laravel-support/compare/v1.3.1...v1.4.0) (2021-07-30) -### Features - -* Add GeoPoint caster ([c8f1e9](https://github.com/efureev/laravel-support/commit/c8f1e9dafac3820923a92b58fc331b2720da9c6b)) - - ---- - -## [1.3.1](https://github.com/efureev/laravel-support/compare/v1.3.0...v1.3.1) (2021-07-29) - ---- - -## [1.3.0](https://github.com/efureev/laravel-support/compare/v1.2.1...v1.3.0) (2021-07-29) -### Features - -* Add ServiceProvider helpers ([84ae6f](https://github.com/efureev/laravel-support/commit/84ae6fc087bbe252cb3282e6bbd3b805d7f3c446)) - - ---- - -## [1.2.1](https://github.com/efureev/laravel-support/compare/v1.2.0...v1.2.1) (2021-07-20) - ---- - -## [1.2.0](https://github.com/efureev/laravel-support/compare/v1.1.0...v1.2.0) (2021-07-20) -### Features - -* Add `validateValue` method ([29b085](https://github.com/efureev/laravel-support/commit/29b0857c37372fb555ffb12d6c2ee3186a014c08)) - - ---- - -## [1.1.0](https://github.com/efureev/laravel-support/compare/v1.0.1...v1.1.0) (2021-05-25) - ---- - -## [1.0.1](https://github.com/efureev/laravel-support/compare/v1.0.0...v1.0.1) (2021-05-24) - ---- - -## [1.0.0](https://github.com/efureev/laravel-support/compare/v0.11.5...v1.0.0) (2021-04-28) - ---- - -## [0.11.5](https://github.com/efureev/laravel-support/compare/v0.11.3...v0.11.5) (2021-02-16) - ---- - -## [0.11.3](https://github.com/efureev/laravel-support/compare/v0.11.4...v0.11.3) (2021-02-04) - ---- - -## [0.11.4](https://github.com/efureev/laravel-support/compare/v0.11.2...v0.11.4) (2021-02-04) - ---- - -## [0.11.2](https://github.com/efureev/laravel-support/compare/v0.11.1...v0.11.2) (2021-01-29) - ---- - -## [0.11.1](https://github.com/efureev/laravel-support/compare/v0.11.0...v0.11.1) (2021-01-28) - ---- - -## [0.11.0](https://github.com/efureev/laravel-support/compare/v0.10.3...v0.11.0) (2021-01-27) - ---- - -## [0.10.3](https://github.com/efureev/laravel-support/compare/v0.10.2...v0.10.3) (2021-01-26) - ---- - -## [0.10.2](https://github.com/efureev/laravel-support/compare/v0.10.1...v0.10.2) (2021-01-25) - ---- - -## [0.10.1](https://github.com/efureev/laravel-support/compare/v0.10.0...v0.10.1) (2021-01-25) - ---- - -## [0.10.0](https://github.com/efureev/laravel-support/compare/v0.9.6...v0.10.0) (2021-01-25) - ---- - -## [0.9.6](https://github.com/efureev/laravel-support/compare/v0.9.5...v0.9.6) (2020-12-28) - ---- - -## [0.9.5](https://github.com/efureev/laravel-support/compare/v0.9.4.2...v0.9.5) (2020-11-06) - ---- - -## [0.9.4.2](https://github.com/efureev/laravel-support/compare/v0.9.4.1...v0.9.4.2) (2020-09-16) - ---- - -## [0.9.4.1](https://github.com/efureev/laravel-support/compare/v0.9.4...v0.9.4.1) (2020-09-16) - ---- - -## [0.9.4](https://github.com/efureev/laravel-support/compare/v0.9.3.2...v0.9.4) (2020-09-16) - ---- - -## [0.9.3.2](https://github.com/efureev/laravel-support/compare/v0.9.3.1...v0.9.3.2) (2020-09-10) - ---- - -## [0.9.3.1](https://github.com/efureev/laravel-support/compare/v0.9.3...v0.9.3.1) (2020-09-07) - ---- - -## [0.9.3](https://github.com/efureev/laravel-support/compare/v0.9.2...v0.9.3) (2020-09-07) - ---- - -## [0.9.2](https://github.com/efureev/laravel-support/compare/v0.9.1...v0.9.2) (2020-08-14) - ---- - -## [0.9.1](https://github.com/efureev/laravel-support/compare/v0.9.0...v0.9.1) (2020-08-12) - ---- - -## [0.9.0](https://github.com/efureev/laravel-support/compare/v0.8.0...v0.9.0) (2020-08-12) - ---- - -## [0.8.0](https://github.com/efureev/laravel-support/compare/v0.7.9...v0.8.0) (2020-07-08) - ---- - -## [0.7.9](https://github.com/efureev/laravel-support/compare/v0.7.8...v0.7.9) (2020-07-06) - ---- - -## [0.7.8](https://github.com/efureev/laravel-support/compare/v0.7.7...v0.7.8) (2020-07-06) - ---- - -## [0.7.7](https://github.com/efureev/laravel-support/compare/v0.7.6...v0.7.7) (2020-07-06) - ---- - -## [0.7.6](https://github.com/efureev/laravel-support/compare/v0.7.5...v0.7.6) (2020-07-03) - ---- - -## [0.7.5](https://github.com/efureev/laravel-support/compare/v0.7.4...v0.7.5) (2020-07-02) - ---- - -## [0.7.4](https://github.com/efureev/laravel-support/compare/v0.7.3...v0.7.4) (2020-06-24) - ---- - -## [0.7.3](https://github.com/efureev/laravel-support/compare/v0.7.2...v0.7.3) (2020-06-23) - ---- - -## [0.7.2](https://github.com/efureev/laravel-support/compare/v0.7.1...v0.7.2) (2020-06-23) - ---- - -## [0.7.1](https://github.com/efureev/laravel-support/compare/v0.7.0...v0.7.1) (2020-06-23) - ---- - -## [0.7.0](https://github.com/efureev/laravel-support/compare/v0.6.0...v0.7.0) (2020-06-22) - ---- - -## [0.6.0](https://github.com/efureev/laravel-support/compare/v0.5.3...v0.6.0) (2020-06-15) - ---- - -## [0.5.3](https://github.com/efureev/laravel-support/compare/v0.5.2...v0.5.3) (2020-05-24) - ---- - -## [0.5.2](https://github.com/efureev/laravel-support/compare/v0.5.1...v0.5.2) (2020-05-24) - ---- - -## [0.5.1](https://github.com/efureev/laravel-support/compare/v0.5.0...v0.5.1) (2020-05-24) - ---- - -## [0.5.0](https://github.com/efureev/laravel-support/compare/v0.4.3...v0.5.0) (2020-05-23) - ---- - -## [0.4.3](https://github.com/efureev/laravel-support/compare/v0.4.2...v0.4.3) (2020-05-23) - ---- - -## [0.4.2](https://github.com/efureev/laravel-support/compare/v0.4.1...v0.4.2) (2020-04-10) - ---- - -## [0.4.1](https://github.com/efureev/laravel-support/compare/v0.4.0...v0.4.1) (2020-04-06) - ---- - -## [0.4.0](https://github.com/efureev/laravel-support/compare/v0.3.4...v0.4.0) (2020-04-04) - ---- - -## [0.3.4](https://github.com/efureev/laravel-support/compare/v0.3.3...v0.3.4) (2020-03-05) - ---- - -## [0.3.3](https://github.com/efureev/laravel-support/compare/v0.3.2...v0.3.3) (2020-02-25) - ---- - -## [0.3.2](https://github.com/efureev/laravel-support/compare/v0.3.1...v0.3.2) (2020-02-19) - ---- - -## [0.3.1](https://github.com/efureev/laravel-support/compare/v0.3.0...v0.3.1) (2020-02-19) - ---- - -## [0.3.0](https://github.com/efureev/laravel-support/compare/v0.2.1...v0.3.0) (2020-02-18) - ---- - -## [0.2.1](https://github.com/efureev/laravel-support/compare/v0.2.0...v0.2.1) (2020-02-11) - ---- - -## [0.2.0](https://github.com/efureev/laravel-support/compare/v0.1.0...v0.2.0) (2020-02-06) - ---- - -## [0.1.0](https://github.com/efureev/laravel-support/compare/v0.0.3...v0.1.0) (2020-01-29) - ---- - -## [0.0.3](https://github.com/efureev/laravel-support/compare/v0.0.2...v0.0.3) (2020-01-28) - ---- - -## [0.0.2](https://github.com/efureev/laravel-support/compare/v0.0.1...v0.0.2) (2020-01-28) - ---- - -## [0.0.1](https://github.com/efureev/laravel-support/compare/19bad4a26e54f968db9f7c4efd7be1dc97712a0d...v0.0.1) (2020-01-28) - ---- +## License +The MIT License (MIT). See [LICENSE](LICENSE). diff --git a/SUMMARY.md b/SUMMARY.md index 4167031..6186919 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -1,14 +1,13 @@ # Table of contents -* [Changelog](README.md) -* [PHP Laravel Support](readme.md) +* [PHP Laravel Support](README.md) +* [Changelog](CHANGELOG.md) * [docs](docs/README.md) - * [Caster](docs/caster.md) - * [Global](docs/global.md) - * [Http](docs/http.md) * [Content](docs/index.md) + * [Global](docs/global.md) * [Pagination](docs/pagination.md) * [Repository](docs/repository.md) * [Sortable](docs/sortable.md) * [Service Providers](docs/sp.md) * [Traits](docs/traits.md) + * [Upgrade to PHP 8.4 / Laravel 13](docs/upgrade-php84-laravel13.md) diff --git a/composer.json b/composer.json index ce0f3fc..b9940df 100755 --- a/composer.json +++ b/composer.json @@ -16,17 +16,17 @@ } ], "require": { - "php": "^8.2", - "efureev/support": "^4.27 || ^5.0", - "illuminate/database": "^12.0" + "php": ">=8.4", + "efureev/support": "^5.2", + "illuminate/database": "^13.0" }, "require-dev": { - "ergebnis/composer-normalize": "^2.42", + "ergebnis/composer-normalize": "^2.52.0", "fakerphp/faker": "^1.23", "marcocesarato/php-conventional-changelog": "^1.17", - "orchestra/testbench": "^10.0", - "phpstan/phpstan": "^2.0", - "phpunit/phpunit": "^11.5", + "orchestra/testbench": "^11.1", + "phpstan/phpstan": "^2.2", + "phpunit/phpunit": "^13.0", "squizlabs/php_codesniffer": "^3.9" }, "autoload": { @@ -87,6 +87,7 @@ "@phpcs", "@phpunit" ], + "test:docker": "docker compose up --build --abort-on-container-exit --exit-code-from app", "test-cover": [ "@phpcs", "@phpunit-cover" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..34c801b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +services: + app: + build: + context: . + dockerfile: .docker/Dockerfile + volumes: + - .:/app + depends_on: + db: + condition: service_healthy + environment: + DB_CONNECTION: pgsql + DB_HOST: db + DB_PORT: 5432 + DB_DATABASE: forge + DB_USERNAME: forge + DB_PASSWORD: forge + + db: + image: postgres:18-alpine + environment: + POSTGRES_DB: forge + POSTGRES_USER: forge + POSTGRES_PASSWORD: forge + ports: + - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U forge -d forge"] + interval: 5s + timeout: 5s + retries: 5 diff --git a/docs/README.md b/docs/README.md index 7dd802a..f038654 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,2 +1,14 @@ -# docs +# Documentation +Documentation for the `efureev/laravel-support` package. + +## Contents + +* [Content (index)](index.md) +* [Global helpers](global.md) +* [Pagination](pagination.md) +* [Repository](repository.md) +* [Sortable](sortable.md) +* [Service Providers](sp.md) +* [Traits](traits.md) +* [Upgrade to PHP 8.4 / Laravel 13](upgrade-php84-laravel13.md) diff --git a/docs/caster.md b/docs/caster.md deleted file mode 100644 index 2352ce1..0000000 --- a/docs/caster.md +++ /dev/null @@ -1,101 +0,0 @@ -# Caster - -* for one entity -* for collection - -## For Entity - -Cast property into Class for one Entity. - -## For Collection - -Cast property into Class for collection of items (class / simple). - -### Examples #1 - -Collection for no-wrap elements (example: array): - -```php -class ArrayCollection extends AbstractCastingCollection -{ -} -``` - -```javascript -[{"id": "key","title": "value"}] -``` - -Collection for wrap elements (example: other class): - -```php -class ComponentCollection extends AbstractCastingCollection -{ - protected function wrapEntity(): ?callable - { - return static function ($item) { - return new Component($item); - }; - } -} -``` - -```javascript -[{"id": "key","title": "value"}] -``` - -```javascript -{"key1":{"id": "key2","title": "value"},"key2":{"id": "key2","title": "value2"}} -``` - -Model: - -```php -/** - * @property ComponentCollection $components - * @property ArrayCollection $arrays - */ -class UserModel extends Model -{ - use HasCasts; - - protected $table = 'test_table_caster'; - - protected $casts = [ - 'components' => ComponentCollection::class, - 'arrays' => ArrayCollection::class, - ]; - - protected $fillable = [ - 'components', - 'arrays', - ]; -} -``` - -### Examples #2: Postgres array casting - -Model: - -```php -class PgArrayModel extends Model -{ - use HasCasts; // <- for casting - use PostgresArray; // <- for scope byTag($tag) - - protected $table = 'pg_table'; - - - protected $casts = [ - 'tags' => PgArray::class, - ]; - - public function scopeByTag(Builder $query, string $value) - { - $this->scopeWherePgArrayContains($query, 'tags', $value); - } -} -``` - -```javascript -['value', 'val2', 'value3'] -``` diff --git a/docs/global.md b/docs/global.md index 5040205..3f3f23c 100644 --- a/docs/global.md +++ b/docs/global.md @@ -1,9 +1,26 @@ # Global -## user - -Returns the current user authenticated, or `null` +Global helper functions are autoloaded via `src/Global/base.php`. ## toCollect -Returns a collection of a value +Returns a collection of a value. + +```php +toCollect($model); // Model -> Collection([$model]) +toCollect([$a, $b]); // array -> Collection([$a, $b]) +toCollect($coll); // Collection -> the same Collection +toCollect($value); // mixed -> Collection([$value]) +``` + +## objectToArray + +Recursively converts an object (or a structure of objects) into an array. + +Supports `Illuminate\Contracts\Support\Arrayable`, `JsonSerializable` and `Traversable`. + +```php +objectToArray($model); // uses Arrayable::toArray() +objectToArray($jsonSerializable); // uses jsonSerialize() +objectToArray($iterator); // uses iterator_to_array() +``` diff --git a/docs/http.md b/docs/http.md deleted file mode 100644 index 109c2d7..0000000 --- a/docs/http.md +++ /dev/null @@ -1,45 +0,0 @@ -# Http - -## LaraRequest - -Helps you build your own Requests. - -### Example - -You need to boot `LaraRequestServiceProvider`. - -Custom Request - -```php -query->get('id'); - } -} -``` - -Controller - -```php -id(); - } -} -``` - -Other services - -```php -$app['request'] instanceOf CustomRequest === true -request() instanceOf CustomRequest === true -app('request') instanceOf CustomRequest === true -``` diff --git a/docs/index.md b/docs/index.md index 2a3ff7b..b933a22 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,17 +1,16 @@ # Content - [Global][global] -- [Caster][caster] - [Pagination][pagination] - [Traits][traits] - [Repository][repository] -- [Http][http] - [Sortable][sortable] - [Service Providers][sp] +- [Upgrade to PHP 8.4 / Laravel 13][upgrade] [global]:./global.md -[caster]:./caster.md +[upgrade]:./upgrade-php84-laravel13.md [pagination]:./pagination.md @@ -19,8 +18,6 @@ [repository]:./repository.md -[http]:./http.md - [sortable]:./sortable.md [sp]:./sp.md diff --git a/phpunit.xml b/phpunit.xml.dist similarity index 64% rename from phpunit.xml rename to phpunit.xml.dist index 24dd19a..51b6b4a 100755 --- a/phpunit.xml +++ b/phpunit.xml.dist @@ -1,7 +1,7 @@ @@ -25,8 +25,16 @@ - + + + + + + + diff --git a/readme.md b/readme.md deleted file mode 100644 index 5704906..0000000 --- a/readme.md +++ /dev/null @@ -1,114 +0,0 @@ -# PHP Laravel Support - -![](https://img.shields.io/badge/php-8.1|8.2-blue.svg) -![](https://img.shields.io/badge/Laravel-^10.1-red.svg) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5c8b9e85897f4c65b5a017d16f6af6cb)](https://app.codacy.com/manual/efureev/laravel-support?utm_source=github.com&utm_medium=referral&utm_content=efureev/laravel-support&utm_campaign=Badge_Grade_Dashboard) -[![Build Status](https://travis-ci.com/efureev/laravel-support.svg?branch=master)](https://travis-ci.com/efureev/laravel-support) -![PHP Laravel Package](https://github.com/efureev/laravel-support/workflows/PHP%20Laravel%20Package/badge.svg?branch=master) -[![Latest Stable Version](https://poser.pugx.org/efureev/laravel-support/v/stable?format=flat)](https://packagist.org/packages/efureev/laravel-support) -[![Total Downloads](https://poser.pugx.org/efureev/laravel-support/downloads)](https://packagist.org/packages/efureev/laravel-support) -[![Maintainability](https://api.codeclimate.com/v1/badges/5c2f433a24871b1f12e3/maintainability)](https://codeclimate.com/github/efureev/laravel-support/maintainability) -[![Test Coverage](https://api.codeclimate.com/v1/badges/5c2f433a24871b1f12e3/test_coverage)](https://codeclimate.com/github/efureev/laravel-support/test_coverage) - -## Install - -```bash -composer require efureev/laravel-support "^1.17" -``` - -Read `/docs` for more documentations. - - - -## Usage - -### Traits\Database\UUID - -Use UUID type for primary key - -```php -Schema::create( - 'table_name', - static function (Blueprint $table) { - static::columnUUID($table)->primary(); - $table->string('title'); - $table->timestamps(); - } -); -``` - -Use UUID type for foreign keys - -```php -Schema::create( - 'table_name', - static function (Blueprint $table) { - //... - static::columnUUID($table, 'source_id', false)->nullable()->index(); - //... - } -); -``` - -Types of `$default`: - -- string: `NOW()` -- callable: needs return param of `Illuminate\Database\Query\Expression` class -- class `Illuminate\Database\Query\Expression` - -### Traits\Models\PostgresArray - -Scope for searching into PG arrays. @see: `\Php\Support\Laravel\Tests\Models\PgArrayModel::scopeByTag` - -### Custom Casting - -Use it for custom casting model's attributes. Even based on classes. -@see: `\Php\Support\Laravel\Tests\Models\PgArrayModel::36` -@see: `\Php\Support\Laravel\Tests\Models\TestModel::33` -@example: -Cast class: - -```php -use Php\Support\Laravel\Caster\AbstractCasting; - -class Params extends AbstractCasting -{ - protected $key; - - public function toArray(): array - { - return [ - 'key' => $this->key, - ]; - } -} -``` - -Model: - -```php -use Php\Support\Laravel\Caster\HasCasts; -class TestModel extends Model -{ - use HasCasts; - - protected $table = 'test_table'; - - protected $fillable = ['params']; - - protected $casts = [ - 'params' => Params::class, - ]; -} -``` - -It's enough for use attribute `params` as class `Params`: `$model->params->key`! - -Now, mutators are not needed. But they will work. - -## Test - -```bash -composer test -composer test-cover # with coverage -``` diff --git a/src/Caster/AbstractCasting.php b/src/Caster/AbstractCasting.php deleted file mode 100644 index 5a47c1b..0000000 --- a/src/Caster/AbstractCasting.php +++ /dev/null @@ -1,204 +0,0 @@ -fill($value); - } - - /** - * Fill the instance with data - * - * @param string|array|static $value - * - * @return AbstractCasting - * @throws Exception - */ - public function fill($value): self - { - $value = $this->preFormat($value); - - if (empty($value)) { - return $this->afterFill(); - } - - $value = $this->convert($value); - - $this->validate($value); - - return $this - ->configurable($value) - ->afterFill(); - } - - /** - * Prepend formatting - * - * @param string|array|static $value - * - * @return string|array|static - */ - protected function preFormat($value) - { - return $value; - } - - protected function afterFill(): self - { - return $this; - } - - /** - * Convert value data - * - * @param mixed $value - * - * @return array|string - */ - public function convert($value) - { - if (is_string($value)) { - $value = static::dataFromJson($value); - } - - if ($value instanceof static) { - $value = $value->toArray(); - } - - return $value; - } - - /** - * @param mixed $value - * - * @throws Exception - */ - public function validate($value) - { - if (!is_array($value)) { - throw new Exception('type of value must be Array'); - } - } - - /** - * JSON-string to Array - * - * @param string|null|array $json - * - * @return array - */ - protected static function dataFromJson($json): array - { - if (empty($json)) { - return []; - } - - if (is_array($json)) { - return $json; - } - - return Json::decode($json); - } - - /** - * @return array - */ - abstract public function toArray(): array; - - /** - * @param static|array|null $value - * - * @return string|null - */ - public static function castToDatabase($value): ?string - { - if ($value instanceof static) { - return $value->toJson(); - } - - return static::dataToJson($value ?? []); - } - - /** - * @param int $options - * - * @return string|null - */ - public function toJson($options = 320): ?string - { - return static::dataToJson($this->toArray(), $options); - } - - /** - * Array to JSON-string - * - * @param array $data - * @param int $options Default is `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE`. - * - * @return string|null - */ - protected static function dataToJson(array $data, $options = 320): ?string - { - if (empty($data)) { - return static::emptyJsonStruct(); - } - - return Json::encode($data, $options); - } - - /** - * @param string|null $value - * - * @return $this - * @throws Exception - */ - public function castFromDatabase(?string $value): self - { - return $this->fill($value); - } - - /** - * @param $value - * @param $original - * - * @return bool - */ - public static function isEquivalent($value, $original): bool - { - return $value->toJson() === $original?->toJson(); - } - - protected static function emptyJsonStruct(): ?string - { - return self::EMPTY_JSON_OBJECT; - } - - public function value(): mixed - { - return static::castToDatabase($this); - } -} diff --git a/src/Caster/AbstractCastingCollection.php b/src/Caster/AbstractCastingCollection.php deleted file mode 100644 index 2b1a5a9..0000000 --- a/src/Caster/AbstractCastingCollection.php +++ /dev/null @@ -1,316 +0,0 @@ -fill($value); - } - - public function fill($value): self - { - $value = $this->preFormat($value); - - if (empty($value)) { - return $this->afterFill(); - } - - $value = $this->convert($value); - - $this->validate($value); - - return $this - ->fillItems($value) - ->afterFill(); - } - - /** - * Prepend formatting - * - * @param string|array|static $value - * - * @return string|array|static - */ - protected function preFormat($value) - { - return $value; - } - - /** - * Convert value data into array - * - * @param mixed $value - * - * @return array|string - */ - public function convert($value) - { - if (is_string($value)) { - $value = static::dataFromJson($value); - } elseif ($value instanceof static) { - $value = $value->toArray(); - } else { - $value = $this->getArrayableItems($value); - } - - return $value; - } - - /** - * JSON-string to Array - * - * @param string|null $json - * - * @return array - */ - protected static function dataFromJson($json): array - { - if (empty($json)) { - return []; - } - - return Json::decode($json); - } - - /** - * Results array of items from Collection or Arrayable. - * - * @param mixed $items - * - * @return array|mixed|null - */ - protected function getArrayableItems($items) - { - if (is_array($items)) { - return $items; - } - if ($items instanceof Enumerable) { - return $items->all(); - } - if ($items instanceof \Illuminate\Contracts\Support\Arrayable) { - return $items->toArray(); - } - if ($items instanceof Jsonable) { - return Json::decode($items->toJson()); - } - if ($items instanceof \JsonSerializable) { - return (array)$items->jsonSerialize(); - } - if ($items instanceof \Traversable) { - return iterator_to_array($items); - } - - return (array)$items; - } - - protected function afterFill(): self - { - return $this; - } - - /** - * @param mixed $value - * - * @throws Exception - */ - public function validate($value) - { - if (!is_array($value)) { - throw new Exception('type of value must be Array'); - } - } - - - /** - * @param static|array $value - * - * @return string|null - */ - public static function castToDatabase($value): ?string - { - if ($value instanceof Jsonable) { - return $value->toJson(); - } - - return static::dataToJson($value); - } - - /** - * @param int $options - * - * @return string|null - */ - public function toJson($options = 320): ?string - { - return static::dataToJson($this->toArray(), $options); - } - - /** - * Array to JSON-string - * - * @param array $data - * @param int $options Default is `JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE`. - * - * @return string|null - */ - protected static function dataToJson(?array $data, $options = 320): ?string - { - if (empty($data)) { - return '[]'; - } - - return Json::encode($data, $options); - } - - /** - * @param string|null $value - * - * @return $this - * @throws Exception - */ - public function castFromDatabase(?string $value): self - { - return $this->fill($value); - } - - public static function isEquivalent($value, $original): bool - { - return $value->toJson() === $original->toJson(); - } - - /** - * Push one or more items onto the end of the collection. - * - * @param mixed $values [optional] - * - * @return $this - */ - public function fillItems($values): self - { - $cb = $this->wrapEntity(); - - foreach ($values as $key => $value) { - $this->set($key, $value, $cb); - } - - return $this; - } - - /** - * Add an item to the collection. - * - * @param mixed $item - * @param callable|null $cb - * - * @return $this - */ - public function add($item, ?callable $cb = null): self - { - $this->items[] = with($item, $cb); - - return $this; - } - - /** - * @param string|int $key - * @param mixed $item - * @param callable|null $cb - * - * @return $this - */ - public function set($key, $item, ?callable $cb = null): self - { - $this->items[$key] = $cb === null ? $item : $cb($item, $key); - - return $this; - } - - - /** - * @param string|int $key - * - * @return mixed|null - */ - public function get($key) - { - return $this->items[$key] ?? null; - } - - /** - * Wrapper for element - * @return callable|null - * protected function wrapEntity(): ?callable { - * return static function ($item) {return $item;}; - * } - * @example - */ - protected function wrapEntity(): ?callable - { - return null; - } - - public function toArray(): array - { - if (!$this->wrapEntity()) { - return $this->items; - } - - return Arr::dataToArray($this->items); - } - - public function all(): array - { - return $this->items; - } - - /** - * Get an iterator for the items. - * - * @return ArrayIterator - */ - public function getIterator(): ArrayIterator - { - return new ArrayIterator($this->items); - } - - /** - * Count the number of items in the collection. - * - * @return int - */ - public function count(): int - { - return count($this->items); - } - - public function value(): mixed - { - return static::castToDatabase($this); - } -} diff --git a/src/Caster/Caster.php b/src/Caster/Caster.php deleted file mode 100644 index 534c693..0000000 --- a/src/Caster/Caster.php +++ /dev/null @@ -1,16 +0,0 @@ -toPgDB(); - } - - throw new \RuntimeException('Invalid type of $value: ' . gettype($value)); - } - - public static function isEquivalent($value, $original): bool - { - return $value->toJson() === $original?->toJson(); - } - - public function value(): ?string - { - return static::castToDatabase($this); - } -} diff --git a/src/Caster/HasCasts.php b/src/Caster/HasCasts.php deleted file mode 100644 index 3715121..0000000 --- a/src/Caster/HasCasts.php +++ /dev/null @@ -1,150 +0,0 @@ -attributes[$key] = $value::castToDatabase($value); - - return $this; - } - - $type = $this->getCastType($key); - - if ($this->typeIsClass($type) && method_exists($type, 'castToDatabase')) { - $this->attributes[$key] = $type::castToDatabase($value); - - return $this; - } - - return parent::setAttribute($key, $value); - } - - protected function getCastType($key): ?string - { - if (!$type = $this->getCasts()[$key] ?? null) { - return null; - } - - if ($this->isCustomDateTimeCast($type)) { - return 'custom_datetime'; - } - - if ($this->isDecimalCast($type)) { - return 'decimal'; - } - - return $type; - } - - public function typeIsClass(?string $type): bool - { - return $type !== null && class_exists($type); - } - - protected function castAttribute($key, $value) - { - if ($value === null) { - return $value; - } - - $type = $this->getCastType($key); - if ($type === null) { - return $value; - } - - return $this->castValue($type, $value); - } - - public function castValue($type, $value) - { - switch ($simpleType = strtolower(trim($type))) { - case 'int': - case 'integer': - return (int)$value; - case 'real': - case 'float': - case 'double': - return $this->fromFloat($value); - case 'decimal': - return $this->asDecimal($value, explode(':', $simpleType, 2)[1]); - case 'string': - return (string)$value; - case 'bool': - case 'boolean': - return (bool)$value; - case 'object': - return $this->fromJson($value, true); - case 'array': - case 'json': - return $this->fromJson($value); - case 'collection': - return new BaseCollection($this->fromJson($value)); - case 'date': - return $this->asDate($value); - case 'datetime': - case 'custom_datetime': - return $this->asDateTime($value); - case 'timestamp': - return $this->asTimestamp($value); - } - - - if ($this->typeIsClass($type)) { - $type = new $type(); - if (!$type instanceof Caster) { - throw new Exception('Invalid class for casting'); - } - return $type->castFromDatabase($value); - } - - return $value; - } - - public function originalIsEquivalent($key): bool - { - if (!array_key_exists($key, $this->original)) { - return false; - } - - $type = $this->getCastType($key); - - if ($this->typeIsClass($type)) { - $castType = $this->$key; - if (is_array($castType) && method_exists($type, 'isEquivalent')) { - return $type::isEquivalent($castType, $this->getOriginal($key)); - } - - if ($castType instanceof Caster) { - return $castType::isEquivalent($castType, $this->getOriginal($key)); - } - } - - return parent::originalIsEquivalent($key); - } - - /** - * @inheritDoc - */ - public function fromJson($value, $asObject = false) - { - return Json::decode($value, !$asObject); - } - - /** - * @inheritDoc - */ - protected function asJson($value) - { - return Json::encode($value); - } -} diff --git a/src/Caster/PgArray.php b/src/Caster/PgArray.php deleted file mode 100644 index 0ca57f2..0000000 --- a/src/Caster/PgArray.php +++ /dev/null @@ -1,35 +0,0 @@ -guard($guard)->user(); - } -} - if (!function_exists('toCollect')) { /** * @param mixed $model diff --git a/src/Http/LaraRequest.php b/src/Http/LaraRequest.php deleted file mode 100644 index 0809764..0000000 --- a/src/Http/LaraRequest.php +++ /dev/null @@ -1,38 +0,0 @@ -container = $container; - - return $this->afterInit(); - } - - protected function afterInit(): static - { - return $this; - } -} diff --git a/src/LaraRequestServiceProvider.php b/src/LaraRequestServiceProvider.php deleted file mode 100644 index 7b164bb..0000000 --- a/src/LaraRequestServiceProvider.php +++ /dev/null @@ -1,24 +0,0 @@ -app->resolving( - LaraRequest::class, - static function ($request, $app) { - $app->instance('request', LaraRequest::createFrom($app->make('request'), $request)->setContainer($app)); - } - ); - } -} diff --git a/src/Rules/Authorized.php b/src/Rules/Authorized.php index 9fc3389..44cbe5c 100644 --- a/src/Rules/Authorized.php +++ b/src/Rules/Authorized.php @@ -4,57 +4,47 @@ namespace Php\Support\Laravel\Rules; -use Illuminate\Contracts\Validation\Rule; +use Closure; +use Illuminate\Contracts\Validation\ValidationRule; use Illuminate\Support\Facades\Auth; /** * Class Authorized * @package Php\Support\Laravel\Rules */ -class Authorized implements Rule +class Authorized implements ValidationRule { - /** @var string */ - protected $ability; - - /** @var array */ - protected $arguments; - - /** @var string */ - protected $className; - - /** @var string */ - protected $attribute; - - public function __construct(string $ability, string $className) - { - $this->ability = $ability; - - $this->className = $className; + public function __construct( + protected readonly string $ability, + protected readonly string $className, + ) { } - public function passes($attribute, $value): bool + public function validate(string $attribute, mixed $value, Closure $fail): void { - $this->attribute = $attribute; - if (!$user = Auth::user()) { - return false; + $fail($this->getErrorMessage($attribute)); + return; } if (!$model = $this->className::find($value)) { - return false; + $fail($this->getErrorMessage($attribute)); + return; } - return $user->can($this->ability, $model); + if (!$user->can($this->ability, $model)) { + $fail($this->getErrorMessage($attribute)); + } } - public function message(): string + protected function getErrorMessage(string $attribute): string { $classBasename = class_basename($this->className); return __( 'laravelSupport::messages.authorized', [ - 'attribute' => $this->attribute, + 'attribute' => $attribute, 'ability' => $this->ability, 'className' => $classBasename, ] diff --git a/src/Rules/Delimited.php b/src/Rules/Delimited.php index 2a8dd86..b97df1f 100644 --- a/src/Rules/Delimited.php +++ b/src/Rules/Delimited.php @@ -4,34 +4,37 @@ namespace Php\Support\Laravel\Rules; -use Illuminate\Contracts\Validation\Rule; +use Closure; +use Illuminate\Contracts\Validation\ValidationRule; use Illuminate\Support\Facades\Validator; use Illuminate\Support\Str; -class Delimited implements Rule +class Delimited implements ValidationRule { - /** @var string|array|Rule */ - protected $rule; - - protected $minimum; + /** + * Run the validation rule even when the attribute is empty/absent, + * so that the "min" constraint can reject empty values. + */ + public bool $implicit = true; - protected $maximum; + protected ?int $minimum = null; - protected $allowDuplicates = false; + protected ?int $maximum = null; - protected $message = ''; + protected bool $allowDuplicates = false; - protected $separatedBy = ','; + protected string $separatedBy = ','; - /** @var bool */ - protected $trimItems = true; + protected bool $trimItems = true; - /** @var string */ - protected $validationMessageWord = 'item'; + protected string $validationMessageWord = 'item'; - public function __construct($rule) - { - $this->rule = $rule; + /** + * @param string|array|ValidationRule $rule + */ + public function __construct( + protected string|array|ValidationRule $rule + ) { } /** @@ -86,13 +89,13 @@ public function validationMessageWord(string $word): self return $this; } - public function passes($attribute, $value) + public function validate(string $attribute, mixed $value, Closure $fail): void { if ($this->trimItems) { - $value = trim($value); + $value = trim((string)$value); } - $items = collect(explode($this->separatedBy, $value)) + $items = collect(explode($this->separatedBy, (string)$value)) ->filter( static function ($item) { return (string)$item !== ''; @@ -100,29 +103,33 @@ static function ($item) { ); if (($this->minimum !== null) && $items->count() < $this->minimum) { - $this->message = __( - 'laravelSupport::messages.delimited.min', - [ - 'minimum' => $this->minimum, - 'actual' => $items->count(), - 'item' => Str::plural($this->validationMessageWord, $items->count()), - ] + $fail( + __( + 'laravelSupport::messages.delimited.min', + [ + 'minimum' => $this->minimum, + 'actual' => $items->count(), + 'item' => Str::plural($this->validationMessageWord, $items->count()), + ] + ) ); - return false; + return; } if (($this->maximum !== null) && $items->count() > $this->maximum) { - $this->message = __( - 'laravelSupport::messages.delimited.max', - [ - 'maximum' => $this->maximum, - 'actual' => $items->count(), - 'item' => Str::plural($this->validationMessageWord, $items->count()), - ] + $fail( + __( + 'laravelSupport::messages.delimited.max', + [ + 'maximum' => $this->maximum, + 'actual' => $items->count(), + 'item' => Str::plural($this->validationMessageWord, $items->count()), + ] + ) ); - return false; + return; } if ($this->trimItems) { @@ -137,30 +144,21 @@ static function (string $item) { [ $isValid, $validationMessage, - ] = $this->validate($attribute, $item); + ] = $this->validateItem($attribute, $item); if (!$isValid) { - $this->message = $validationMessage; + $fail($validationMessage); - return false; + return; } } if (!$this->allowDuplicates && $items->unique()->count() !== $items->count()) { - $this->message = __('laravelSupport::messages.delimited.unique'); - - return false; + $fail(__('laravelSupport::messages.delimited.unique')); } - - return true; - } - - public function message() - { - return $this->message; } - protected function validate(string $attribute, string $item): array + protected function validateItem(string $attribute, string $item): array { $attribute = Str::after($attribute, '.'); diff --git a/src/Traits/Database/UUID.php b/src/Traits/Database/UUID.php deleted file mode 100644 index ddf37ae..0000000 --- a/src/Traits/Database/UUID.php +++ /dev/null @@ -1,59 +0,0 @@ -uuid($name); - - if (!$default) { - return $defCol; - } - - $driverName = DB::getDriverName(); - - switch ($driverName) { - case 'pgsql': - DB::statement('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";'); - $expression = 'uuid_generate_v4()'; - break; - case 'mysql': - $expression = 'UUID()'; - break; - default: - throw new Exception('Your DB driver [' . $driverName . '] does not supported'); - } - - if (is_callable($default)) { - $defaultExpression = new Expression($default($driverName)); - } elseif ($default instanceof Expression) { - $defaultExpression = $default; - } elseif ($default === true) { - $defaultExpression = new Expression($expression); - } else { - $defaultExpression = new Expression($default); - } - - return $defCol->default($defaultExpression); - } -} diff --git a/src/Traits/Models/HasModelEntityCache.php b/src/Traits/Models/HasModelEntityCache.php index 83b8110..e13f315 100644 --- a/src/Traits/Models/HasModelEntityCache.php +++ b/src/Traits/Models/HasModelEntityCache.php @@ -94,7 +94,7 @@ public static function cacheForgetByKey(string $key): bool return static::resolveStoreDriver()->forgetByKey($key); } - protected static function cacheForgetCollection(string $key = null): bool + protected static function cacheForgetCollection(?string $key = null): bool { return static::resolveStoreDriver()->cacheForgetCollection($key); } @@ -104,7 +104,7 @@ protected static function cacheKeyName(): string return 'id'; } - protected static function cachePrefixKey(string $key = null, string $prefix = null): string + protected static function cachePrefixKey(?string $key = null, ?string $prefix = null): string { return static::resolveStoreDriver()->prefixKey($key, $prefix); } diff --git a/tests/AbstractTestCase.php b/tests/AbstractTestCase.php index ac9dd96..a49330c 100755 --- a/tests/AbstractTestCase.php +++ b/tests/AbstractTestCase.php @@ -36,9 +36,9 @@ protected function getEnvironmentSetUp($app): void 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', 'localhost'), 'port' => env('DB_PORT', '5432'), - 'database' => env('POSTGRES_DB', 'postgres'), - 'username' => env('DB_USERNAME', 'postgres'), - 'password' => env('DB_PASSWORD', 'postgres'), + 'database' => env('DB_DATABASE', 'forge'), + 'username' => env('DB_USERNAME', 'forge'), + 'password' => env('DB_PASSWORD', 'forge'), 'charset' => 'utf8', 'prefix' => '', 'prefix_indexes' => true, diff --git a/tests/Functional/CasterCollectionTest.php b/tests/Functional/CasterCollectionTest.php deleted file mode 100755 index ff9a4a5..0000000 --- a/tests/Functional/CasterCollectionTest.php +++ /dev/null @@ -1,220 +0,0 @@ -components); - static::assertNull($model->arrays); - static::assertNull($model->getOriginal('components')); - static::assertNull($model->getOriginal('arrays')); - static::assertNull($model->getRawOriginal('components')); - static::assertNull($model->getRawOriginal('arrays')); - } - - public function testCreateWithEmptyCollection2(): void - { - $model = CasterCollection::create(['components' => null, 'arrays' => null]); - - static::assertInstanceOf(CasterCollection::class, $model); - static::assertInstanceOf(ComponentCollection::class, $model->components); - static::assertInstanceOf(ComponentCollection::class, $model->getOriginal('components')); - static::assertInstanceOf(ArrayCollection::class, $model->arrays); - static::assertInstanceOf(ArrayCollection::class, $model->getOriginal('arrays')); - - static::assertEquals('[]', $model->getRawOriginal('components')); - static::assertEquals('[]', $model->getRawOriginal('arrays')); - } - - private static function createComponent($isMain = false): array - { - return [ - 'module' => 'news', - 'isMain' => $isMain, - 'params' => [], - ]; - } - - - public function testCreateArrayCollection(): void - { - $data = [ - self::createComponent(), - self::createComponent(true), - self::createComponent(), - ]; - $model = CasterCollection::create(['arrays' => $data]); - - static::assertInstanceOf(ArrayCollection::class, $model->arrays); - static::assertInstanceOf(ArrayCollection::class, $model->getOriginal('arrays')); - - static::assertCount(3, $model->arrays); - static::assertEquals( - '[{"module":"news","isMain":false,"params":[]},{"module":"news","isMain":true,"params":[]},{"module":"news","isMain":false,"params":[]}]', - $model->getRawOriginal('arrays') - ); - - static::assertJsonStringEqualsJsonString(Json::encode($data), $model->getRawOriginal('arrays')); - } - - public function testCreateCollection(): void - { - $data = [ - self::createComponent(), - self::createComponent(true), - self::createComponent(), - self::createComponent(), - ]; - $model = CasterCollection::create(['components' => $data]); - - static::assertInstanceOf(ComponentCollection::class, $model->components); - static::assertInstanceOf(ComponentCollection::class, $model->getOriginal('components')); - - static::assertCount(4, $model->components); - - foreach ($model->components as $k => $component) { - static::assertInstanceOf(Component::class, $component); - static::assertEquals($data[$k]['module'], $component->module); - } - - static::assertJsonStringEqualsJsonString(Json::encode($data), $model->getRawOriginal('components')); - static::assertJsonStringEqualsJsonString( - '[{"name":"news"},{"name":"news"},{"name":"news"},{"name":"news"}]', - $model->components->toJson() - ); - } - - public function testCreateKeyCollection(): void - { - $data = [ - (string)Uuid::uuid4() => self::createComponent(), - (string)Uuid::uuid4() => self::createComponent(true), - (string)Uuid::uuid4() => self::createComponent(), - (string)Uuid::uuid4() => self::createComponent(), - ]; - - $model = CasterCollection::create(['components' => $data]); - - // dd($model->components); - static::assertInstanceOf(ComponentCollection::class, $model->components); - static::assertInstanceOf(ComponentCollection::class, $model->getOriginal('components')); - - static::assertCount(4, $model->components); - - foreach ($model->components as $k => $component) { - static::assertInstanceOf(Component::class, $component); - static::assertEquals($data[$k]['module'], $component->module); - } - - static::assertJsonStringEqualsJsonString(Json::encode($data), $model->getRawOriginal('components')); - } - - public function testCreateAndCheckDirty(): void - { - $data = [ - self::createComponent(), - self::createComponent(true), - ]; - $model = CasterDirtyCollection::make(['arrays' => $data]); - - - static::assertTrue($model->isDirty('arrays')); - static::assertEquals( - '[{"module":"news","isMain":false,"params":[]},{"module":"news","isMain":true,"params":[]}]' , - $model->getDirty()['arrays'] - ); - - $model->save(); - - $model->fill(['arrays' => $data]); - - static::assertFalse($model->isDirty('arrays')); - static::assertEmpty($model->getDirty()); - - - $model->fill(['arrays' => [self::createComponent(), self::createComponent(),self::createComponent(),]]); - - static::assertTrue($model->isDirty('arrays')); - static::assertEquals( - '[{"module":"news","isMain":false,"params":[]},{"module":"news","isMain":false,"params":[]},{"module":"news","isMain":false,"params":[]}]', - $model->getDirty()['arrays'] - ); - - $model->save(); - - static::assertEquals( - '[{"module":"news","isMain":false,"params":[]},{"module":"news","isMain":false,"params":[]},{"module":"news","isMain":false,"params":[]}]', - $model->getRawOriginal('arrays') - ); - } - - public function testCreateAndCheckDirtyArray(): void - { - $data = [ - self::createComponent(), - self::createComponent(true), - self::createComponent(), - self::createComponent(), - ]; - - $model = CasterDirtyCollection::make(['components' => $data]); - - - static::assertTrue($model->isDirty('components')); - static::assertEquals( - '[{"module":"news","isMain":false,"params":[]},' . - '{"module":"news","isMain":true,"params":[]},' . - '{"module":"news","isMain":false,"params":[]},' . - '{"module":"news","isMain":false,"params":[]}]', - $model->getDirty()['components'] - ); - - $model->save(); - - $model->fill(['components' => $data]); - - static::assertFalse($model->isDirty('components')); - static::assertEmpty($model->getDirty()); - - - $model->fill(['components' => [self::createComponent(), self::createComponent()]]); - - static::assertTrue($model->isDirty('components')); - static::assertEquals( - '[{"module":"news","isMain":false,"params":[]},{"module":"news","isMain":false,"params":[]}]', - $model->getDirty()['components'] - ); - - $model->save(); - - static::assertEquals( - '[{"module":"news","isMain":false,"params":[]},{"module":"news","isMain":false,"params":[]}]', - $model->getRawOriginal('components') - ); - } - - /** - * @return void - */ - protected function setUp(): void - { - parent::setUp(); - - $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); - } -} diff --git a/tests/Functional/CasterTraitTest.php b/tests/Functional/CasterTraitTest.php deleted file mode 100755 index 78b4eee..0000000 --- a/tests/Functional/CasterTraitTest.php +++ /dev/null @@ -1,391 +0,0 @@ -create( - [ - 'geo_point' => null, - ] - ); - - static::assertCount(5, $list); - - /** @var TestModel $item */ - foreach ($list as $item) { - static::assertInstanceOf(TestModel::class, $item); - static::assertNotEmpty($item->title); - static::assertIsString($item->title); - - static::assertIsString($item->str); - static::assertNotEmpty($item->str); - static::assertNull($item->str_empty); - static::assertNull($item->int); - static::assertNull($item->geo_point); - - static::assertIsBool($item->enabled); - static::assertNull($item->config); - static::assertEmpty($item->config); - static::assertNull($item->params); - static::assertNull($item->getOriginal('params')); - } - } - - public function testCreateAndGetWithNullParamsAndStatusIsNull(): void - { - $model = TestModel::create( - [ - 'title' => 'test', - 'str' => "test2", - 'enabled' => false, - ] - ); - - static::assertNull($model->title); - static::assertEquals('test2', $model->str); - - static::assertNull($model->str_empty); - static::assertNull($model->int); - - static::assertFalse($model->enabled); - static::assertNull($model->status); - static::assertNull($model->config); - static::assertEmpty($model->config); - static::assertNull($model->params); - static::assertNull($model->getOriginal('params')); - static::assertEquals([], $model->getDirty()); - - $model->status = Status::STATUS_INSTALLED; - static::assertEquals(['status' => Status::STATUS_INSTALLED], $model->getDirty()); - - $model->save(); - - static::assertEquals([], $model->getDirty()); - } - - public function testCreateAndGetWithNullParamsAndStatusIsNull2(): void - { - $model = TestModel::create( - [ - 'title' => 'test', - 'str' => "test2", - 'enabled' => false, - 'status' => null, - ] - ); - - static::assertNull($model->title); - static::assertEquals('test2', $model->str); - - static::assertNull($model->str_empty); - static::assertNull($model->int); - - static::assertFalse($model->enabled); - static::assertNull($model->status); - - static::assertNull($model->config); - static::assertEmpty($model->config); - static::assertNull($model->params); - static::assertNull($model->getOriginal('params')); - static::assertEquals([], $model->getDirty()); - - $model->status = Status::STATUS_INSTALLED; - static::assertEquals(['status' => Status::STATUS_INSTALLED], $model->getDirty()); - - $model->save(); - - self::assertInstanceOf(Status::class, $model->status); - self::assertEquals(Status::STATUS_INSTALLED, $model->status->key()); - static::assertEquals([], $model->getDirty()); - } - - public function testCreateAndGetWithEmptyArrayParams(): void - { - /** @var Collection $list */ - $list = TestModelFactory::times(5)->create( - [ - 'params' => [], - 'config' => [], - 'str_empty' => '', - 'int' => 0, - ] - ); - - static::assertCount(5, $list); - - /** @var TestModel $item */ - foreach ($list as $item) { - static::assertInstanceOf(TestModel::class, $item); - static::assertNotEmpty($item->title); - static::assertIsString($item->title); - static::assertIsBool($item->enabled); - static::assertIsArray($item->config); - static::assertEquals([], $item->config); - - static::assertIsString($item->str); - static::assertNotEmpty($item->str); - static::assertIsString($item->str_empty); - static::assertEmpty($item->str_empty); - static::assertIsInt($item->int); - static::assertEquals(0, $item->int); - - static::assertInstanceOf(Params::class, $item->getOriginal('params')); - - static::assertIsString($item->getRawOriginal('params')); - - static::assertEquals('[]', $item->getRawOriginal('params')); - - static::assertInstanceOf(Params::class, $item->params); - static::assertEquals( - [ - 'key' => null, - 'config' => [], - 'testParam' => null, - ], - $item->params->toArray() - ); - } - } - - public function testCreateAndGetWithFillArrayParams(): void - { - /** @var Collection $list */ - $list = TestModelFactory::times(5)->create( - [ - 'str' => 'string', - 'str_empty' => 'string empty', - 'int' => 7, - 'config' => ['key' => 2], - 'params' => [ - 'key' => 1, - 'config' => ['test' => 'value'], - 'testParam' => 'val', - ], - ] - ); - - static::assertCount(5, $list); - - /** @var TestModel $item */ - foreach ($list as $item) { - static::assertInstanceOf(TestModel::class, $item); - static::assertNotEmpty($item->title); - static::assertIsString($item->title); - static::assertIsBool($item->enabled); - - static::assertIsString($item->str); - static::assertEquals('string', $item->str); - static::assertIsString($item->str_empty); - static::assertEquals('string empty', $item->str_empty); - static::assertIsInt($item->int); - static::assertEquals(7, $item->int); - - static::assertEquals(['key' => 2], $item->config); - static::assertEquals('{"key":2}', $item->getRawOriginal('config')); - static::assertIsString($item->getRawOriginal('params')); - static::assertEquals( - '{"key":1,"config":{"test":"value"},"testParam":"val"}', - $item->getRawOriginal('params') - ); - - static::assertInstanceOf(Params::class, $item->params); - static::assertEquals( - [ - 'key' => 1, - 'config' => ['test' => 'value'], - 'testParam' => 'val', - ], - $item->params->toArray() - ); - } - } - - public function testCreateGeoPoint(): void - { - $model = TestModel::create( - [ - 'geo_point' => new GeoPoint(111.02, 21.20), - ] - ); - - static::assertInstanceOf(GeoPoint::class, $model->geo_point); - static::assertEquals(111.02, $model->geo_point->x); - static::assertEquals(21.20, $model->geo_point->y); - static::assertEquals('(111.02,21.2)', $model->geo_point->value()); - static::assertEquals([111.02, 21.2], $model->geo_point->toArray()); - static::assertEquals('{"longitude":111.02,"latitude":21.2}', $model->geo_point->toJson()); - } - - - public function testCreateAndGetWithClassParams(): void - { - /** @var Collection $list */ - $list = TestModelFactory::times(5)->create( - [ - 'str_empty' => null, - 'config' => [ - 'key' => ['key' => 2], - ], - 'params' => new Params( - [ - 'key' => 1, - 'config' => ['test' => 'value'], - 'testParam' => 'val', - ] - ), - ] - ); - - static::assertCount(5, $list); - - /** @var TestModel $item */ - foreach ($list as $item) { - static::assertInstanceOf(TestModel::class, $item); - static::assertNotEmpty($item->title); - static::assertIsString($item->title); - static::assertIsBool($item->enabled); - - static::assertIsString($item->str); - static::assertNotEmpty($item->str); - static::assertNull($item->str_empty); - - static::assertEquals(['key' => ['key' => 2]], $item->config); - static::assertEquals('{"key":{"key":2}}', $item->getRawOriginal('config')); - static::assertIsString($item->getRawOriginal('params')); - static::assertEquals( - '{"key":1,"config":{"test":"value"},"testParam":"val"}', - $item->getRawOriginal('params') - ); - - static::assertInstanceOf(Params::class, $item->params); - static::assertEquals( - [ - 'key' => 1, - 'config' => ['test' => 'value'], - 'testParam' => 'val', - ], - $item->params->toArray() - ); - } - } - - - public function testCreateAndCheckDirty(): void - { - $model = TestDirtyModel::make( - [ - 'params' => [ - 'key' => 1, - ], - ] - ); - - static::assertTrue($model->isDirty('params')); - static::assertEquals('{"key":1}', $model->getDirty()['params']); - - $model->save(); - - $model->fill( - [ - 'params' => [ - 'key' => 1, - ], - ] - ); - - static::assertFalse($model->isDirty('params')); - static::assertEmpty($model->getDirty()); - - - $model->fill( - [ - 'params' => [ - 'key' => 2, - ], - ] - ); - - static::assertTrue($model->isDirty('params')); - static::assertEquals('{"key":2}', $model->getDirty()['params']); - - $model->save(); - - static::assertEquals('{"key":2}', $model->getRawOriginal('params')); - } - - - public function testCreateAndCheckDirtyPgArray(): void - { - $model = PgArrayModel::make(['tags' => ['key', 'tag1']]); - - static::assertTrue($model->isDirty('tags')); - static::assertEquals('{key,tag1}', $model->getDirty()['tags']); - - $model->save(); - - $model->fill(['tags' => ['key', 'tag1']]); - - static::assertFalse($model->isDirty('tags')); - static::assertEmpty($model->getDirty()); - - - $model->fill(['tags' => ['key', 'tag2']]); - - static::assertTrue($model->isDirty('tags')); - static::assertEquals('{key,tag2}', $model->getDirty()['tags']); - - $model->save(); - - static::assertEquals('{key,tag2}', $model->getRawOriginal('tags')); - } - - public function testCreateEmptyParams(): void - { - $params = new Params(); - - static::assertInstanceOf(Params::class, $params); - static::assertEquals( - [ - 'key' => null, - 'config' => [], - 'testParam' => null, - ], - $params->toArray() - ); - } - - public function testCreateFullEmptyParams(): void - { - $params = new EmptyParams(); - - static::assertInstanceOf(EmptyParams::class, $params); - static::assertEquals([], $params->toArray()); - static::assertEquals('{}', $params->toJson()); - } - - /** - * @return void - */ - protected function setUp(): void - { - parent::setUp(); - - $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); - } -} diff --git a/tests/Functional/PgArrayTraitTest.php b/tests/Functional/PgArrayTraitTest.php deleted file mode 100755 index e19da2d..0000000 --- a/tests/Functional/PgArrayTraitTest.php +++ /dev/null @@ -1,223 +0,0 @@ -title); - static::assertNull($model->tags); - static::assertNull($model->getOriginal('tags')); - } - - public function testCreateAndGetWithEmptyArrayTags(): void - { - /** @var PgArrayModel $model */ - $model = PgArrayModel::create(['title' => 'test title', 'tags' => []]); - - static::assertInstanceOf(PgArrayModel::class, $model); - static::assertEquals('{}', $model->getRawOriginal('tags')); - static::assertEquals('test title', $model->title); - static::assertEquals([], $model->tags); - } - - public function testCreateAndGetWithFillArrayTags(): void - { - /** @var PgArrayModel $model */ - $model = PgArrayModel::create(['title' => 'test title', 'tags' => ['key', 'key2', '2']]); - - static::assertInstanceOf(PgArrayModel::class, $model); - static::assertEquals('test title', $model->title); - static::assertEquals(['key', 'key2', '2'], $model->tags); - static::assertEquals('{key,key2,2}', $model->getRawOriginal('tags')); - } - - public function testCreateAndGetWithFillArrayNullableTags(): void - { - /** @var PgArrayModel $model */ - $model = PgArrayModel::create(['tags' => ['key', null, '', '2']]); - - static::assertInstanceOf(PgArrayModel::class, $model); - static::assertEquals(['key', '2'], $model->tags); - static::assertEquals('{key,2}', $model->getRawOriginal('tags')); - } - - public function testCreateAndFindByTag(): void - { - PgArrayModel::create(['tags' => ['key', null, '', '2']]); - - static::assertNotNull(PgArrayModel::byTag('key')->first()); - static::assertNotNull(PgArrayModel::byTag('2')->first()); - static::assertNull(PgArrayModel::byTag('test')->first()); - } - - public function testFindOnlyOneValue(): void - { - $model0 = PgArrayModel::create(['tags' => ['2']]); - $model1 = PgArrayModel::create(['tags' => ['1000', null, '', '2']]); - $model2 = PgArrayModel::create(['tags' => ['2', '1', '3']]); - $model3 = PgArrayModel::create(['tags' => ['2']]); - $model4 = PgArrayModel::create(['tags' => []]); - $model5 = PgArrayModel::create(['tags' => []]); - $model6 = PgArrayModel::create(['tags' => []]); - $model7 = PgArrayModel::create(['tags' => [null]]); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContainsOnly($q, 'tags', '2'); - $result = $q->get(); - // dd($result->map->toArray()); - static::assertCount(6, $result); - } - - - public function testFindContainValue(): void - { - $model0 = PgArrayModel::create(['tags' => ['2']]); - $model1 = PgArrayModel::create(['tags' => ['1000', null, '', '2']]); - $model2 = PgArrayModel::create(['tags' => ['2', '1', '3']]); - $model3 = PgArrayModel::create(['tags' => ['2']]); - $model4 = PgArrayModel::create(['tags' => []]); - $model5 = PgArrayModel::create(['tags' => []]); - $model6 = PgArrayModel::create(['tags' => []]); - $model7 = PgArrayModel::create(['tags' => [null]]); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', '2'); - $result = $q->get(); - static::assertCount(4, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', ['2']); - $result = $q->get(); - static::assertCount(4, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', ['2', '3']); - $result = $q->get(); - static::assertCount(1, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', '3'); - $result = $q->get(); - static::assertCount(1, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', null); - $result = $q->get(); - static::assertCount(8, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', ''); - $result = $q->get(); - static::assertCount(8, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', 'null'); - $result = $q->get(); - static::assertCount(0, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', static fn() => '{2}'); - $result = $q->get(); - static::assertCount(4, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', static fn() => '{2,4}'); - $result = $q->get(); - static::assertCount(0, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', static fn() => '{2,3}'); - $result = $q->get(); - static::assertCount(1, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContains($q, 'tags', static fn() => '{}'); - $result = $q->get(); - static::assertCount(8, $result); - } - - - public function testFindContainAnyValue(): void - { - $model0 = PgArrayModel::create(['tags' => ['2']]); - $model1 = PgArrayModel::create(['tags' => ['1000', null, '', '2']]); - $model2 = PgArrayModel::create(['tags' => ['2', '1', '3']]); - $model3 = PgArrayModel::create(['tags' => ['2']]); - $model4 = PgArrayModel::create(['tags' => []]); - $model5 = PgArrayModel::create(['tags' => []]); - $model6 = PgArrayModel::create(['tags' => []]); - $model7 = PgArrayModel::create(['tags' => [null]]); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContainsAny($q, 'tags', '2'); - $result = $q->get(); - static::assertCount(4, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContainsAny($q, 'tags', '3'); - $result = $q->get(); - static::assertCount(1, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContainsAny($q, 'tags', null); - $result = $q->get(); - static::assertCount(0, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContainsAny($q, 'tags', ''); - $result = $q->get(); - static::assertCount(0, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayContainsAny($q, 'tags', 'null'); - $result = $q->get(); - static::assertCount(0, $result); - } - - public function testFindOverlapArray(): void - { - $model0 = PgArrayModel::create(['tags' => ['2']]); - $model1 = PgArrayModel::create(['tags' => ['1000', null, '', '2']]); - $model2 = PgArrayModel::create(['tags' => ['2', '1', '3']]); - $model3 = PgArrayModel::create(['tags' => ['2']]); - $model4 = PgArrayModel::create(['tags' => []]); - $model5 = PgArrayModel::create(['tags' => []]); - $model6 = PgArrayModel::create(['tags' => ['4', '10', '3']]); - $model7 = PgArrayModel::create(['tags' => [null]]); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayOverlapWith($q, 'tags', ['2', '3']); - $result = $q->get(); - static::assertCount(5, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayOverlapWith($q, 'tags', []); - $result = $q->get(); - static::assertCount(0, $result); - - $q = $model1->newModelQuery(); - $model1->scopeWherePgArrayOverlapWith($q, 'tags', ['3']); - $result = $q->get(); - static::assertCount(2, $result); - } - - /** - * @return void - */ - protected function setUp(): void - { - parent::setUp(); - - $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); - } -} diff --git a/tests/Functional/PostgresArrayTest.php b/tests/Functional/PostgresArrayTest.php new file mode 100644 index 0000000..24b4293 --- /dev/null +++ b/tests/Functional/PostgresArrayTest.php @@ -0,0 +1,84 @@ +markTestSkipped('PostgreSQL only test'); + } + + $this->getConnection()->getSchemaBuilder()->create( + 'pg_table', + function (Blueprint $table) { + $table->id(); + $table->jsonb('tags')->nullable(); + $table->jsonb('tag_ids')->nullable(); + $table->string('title')->nullable(); + $table->timestamps(); + } + ); + + // Postgres actually uses specialized array types, but Laravel's jsonb can sometimes be used or we can use raw. + // The trait uses @> operator which is for arrays or jsonb. + // Let's use raw to create a real array column for the test if possible. + DB::statement('ALTER TABLE pg_table DROP COLUMN tags'); + DB::statement('ALTER TABLE pg_table ADD COLUMN tags text[]'); + } + + protected function tearDown(): void + { + $this->getConnection()->getSchemaBuilder()->dropIfExists('pg_table'); + parent::tearDown(); + } + + #[Test] + public function it_can_filter_by_pg_array_contains() + { + PgArrayModel::create(['tags' => ['php', 'laravel', 'support']]); + PgArrayModel::create(['tags' => ['php', 'react']]); + PgArrayModel::create(['tags' => ['javascript']]); + + $this->assertCount(1, PgArrayModel::wherePgArrayContains('tags', ['php', 'laravel'])->get()); + $this->assertCount(2, PgArrayModel::wherePgArrayContains('tags', ['php'])->get()); + } + + #[Test] + public function it_can_filter_by_pg_array_contains_any() + { + PgArrayModel::create(['tags' => ['php', 'laravel']]); + PgArrayModel::create(['tags' => ['javascript']]); + + $this->assertCount(1, PgArrayModel::wherePgArrayContainsAny('tags', 'php')->get()); + } + + #[Test] + public function it_can_filter_by_pg_array_contains_only() + { + PgArrayModel::create(['tags' => ['php', 'php']]); + PgArrayModel::create(['tags' => ['php', 'laravel']]); + PgArrayModel::create(['tags' => ['javascript']]); + + $this->assertCount(1, PgArrayModel::wherePgArrayContainsOnly('tags', 'php')->get()); + } + + #[Test] + public function it_can_filter_by_pg_array_overlap() + { + PgArrayModel::create(['tags' => ['php', 'laravel']]); + PgArrayModel::create(['tags' => ['javascript', 'react']]); + + $this->assertCount(1, PgArrayModel::wherePgArrayOverlapWith('tags', ['php', 'python'])->get()); + } +} diff --git a/tests/Functional/UuidTraitTest.php b/tests/Functional/UuidTraitTest.php deleted file mode 100755 index 71ae831..0000000 --- a/tests/Functional/UuidTraitTest.php +++ /dev/null @@ -1,35 +0,0 @@ -loadMigrationsFrom(__DIR__ . '/../database/migrations_uuid'); - - static::assertTrue(Schema::hasTable('uuid_table')); - static::assertTrue(Schema::hasColumn('uuid_table', 'id')); - static::assertTrue(Schema::hasColumn('uuid_table', 'title')); - - static::assertTrue(Schema::hasTable('uuid_table2')); - static::assertTrue(Schema::hasColumn('uuid_table2', 'id')); - static::assertTrue(Schema::hasColumn('uuid_table2', 'table_id')); - - static::assertTrue(Schema::hasTable('uuid_table3')); - static::assertTrue(Schema::hasColumn('uuid_table3', 'id')); - static::assertTrue(Schema::hasColumn('uuid_table3', 'table_id')); - } - - /** - * @return void - */ - protected function setUp(): void - { - parent::setUp(); - } -} diff --git a/tests/Rules/AuthorizedTest.php b/tests/Rules/AuthorizedTest.php index 646809c..1646aac 100755 --- a/tests/Rules/AuthorizedTest.php +++ b/tests/Rules/AuthorizedTest.php @@ -6,6 +6,7 @@ use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Lang; +use Illuminate\Support\Facades\Validator; use Php\Support\Laravel\Rules\Authorized; use Php\Support\Laravel\Tests\AbstractTestCase; use Php\Support\Laravel\Tests\Database\Factories\TestModelFactory; @@ -39,7 +40,7 @@ public function it_will_return_true_if_the_gate_returns_true_for_the_given_abili $this->actingAs($user); - self::assertTrue($rule->passes('attribute', $model->getKey())); + self::assertTrue(Validator::make(['attribute' => $model->getKey()], ['attribute' => $rule])->passes()); } #[Test] @@ -54,7 +55,7 @@ public function it_will_return_false_if_noone_is_logged_in() ] ); - self::assertFalse($rule->passes('attribute', $model->getKey())); + self::assertFalse(Validator::make(['attribute' => $model->getKey()], ['attribute' => $rule])->passes()); } #[Test] @@ -62,14 +63,7 @@ public function it_will_return_false_if_the_model_is_not_found() { $rule = new Authorized('edit', TestModel::class); - /*$user = UserFactory::new()->create(); - $model = TestModelFactory::new()->create( - [ - 'user_id' => $user->getKey(), - ] - );*/ - - self::assertFalse($rule->passes('attribute', '2')); + self::assertFalse(Validator::make(['attribute' => '2'], ['attribute' => $rule])->passes()); } #[Test] @@ -77,12 +71,7 @@ public function it_will_return_false_if_the_gate_returns_false() { $rule = new Authorized('edit', TestModel::class); - /* $user = UserFactory::new()->create(); - $model = TestModelFactory::new()->create( - ['user_id' => 2] - );*/ - - self::assertFalse($rule->passes('attribute', '1')); + self::assertFalse(Validator::make(['attribute' => '1'], ['attribute' => $rule])->passes()); } #[Test] @@ -96,8 +85,9 @@ public function it_passes_attribute_ability_and_class_name_to_the_validation_mes $rule = new Authorized('edit', TestModel::class); - $rule->passes('name_field', 'John Doe'); + $validator = Validator::make(['name_field' => 'John Doe'], ['name_field' => $rule]); - self::assertEquals('name_field edit and TestModel', $rule->message()); + self::assertFalse($validator->passes()); + self::assertEquals('name_field edit and TestModel', $validator->errors()->first('name_field')); } } diff --git a/tests/Rules/DelimitedTest.php b/tests/Rules/DelimitedTest.php index ee5ba93..f2618ab 100755 --- a/tests/Rules/DelimitedTest.php +++ b/tests/Rules/DelimitedTest.php @@ -4,6 +4,7 @@ namespace Php\Support\Laravel\Tests\Rules; +use Illuminate\Support\Facades\Validator; use Php\Support\Laravel\Rules\Delimited; use Php\Support\Laravel\Tests\AbstractTestCase; use PHPUnit\Framework\Attributes\Test; @@ -100,8 +101,8 @@ public function it_can_accept_a_rule_as_an_array() { $rule = new Delimited(['email']); - $this->assertTrue($rule->passes('attribute', 'sebastian@example.com, alex@example.com, brent@example.com')); - $this->assertFalse($rule->passes('attribute', 'blablabla')); + $this->assertTrue(Validator::make(['attribute' => 'sebastian@example.com, alex@example.com, brent@example.com'], ['attribute' => $rule])->passes()); + $this->assertFalse(Validator::make(['attribute' => 'blablabla'], ['attribute' => $rule])->passes()); } #[Test] @@ -109,9 +110,9 @@ public function it_can_use_composite_rules() { $rule = new Delimited('email|max:20'); - $this->assertTrue($rule->passes('attribute', 'short@example.com')); - $this->assertFalse($rule->passes('attribute', 'short')); - $this->assertFalse($rule->passes('attribute', 'loooooooonnnggg@example.com')); + $this->assertTrue(Validator::make(['attribute' => 'short@example.com'], ['attribute' => $rule])->passes()); + $this->assertFalse(Validator::make(['attribute' => 'short'], ['attribute' => $rule])->passes()); + $this->assertFalse(Validator::make(['attribute' => 'loooooooonnnggg@example.com'], ['attribute' => $rule])->passes()); } @@ -119,21 +120,21 @@ public function it_can_use_composite_rules() public function it_can_handle_numeric_values_properly() { $rule = new Delimited('numeric'); - $this->assertTrue($rule->min(2)->passes('attribute', '0, 1')); + $this->assertTrue(Validator::make(['attribute' => '0, 1'], ['attribute' => $rule->min(2)])->passes()); } - protected function assertRulePasses(string $value) + protected function assertRulePasses($value) { $this->assertTrue($this->rulePasses($value)); } - protected function assertRuleFails(string $value) + protected function assertRuleFails($value) { $this->assertFalse($this->rulePasses($value)); } - public function rulePasses(string $value): bool + public function rulePasses($value): bool { - return $this->rule->passes('attribute', $value); + return Validator::make(['attribute' => $value], ['attribute' => $this->rule])->passes(); } } diff --git a/tests/TestClasses/Casts/PostgresArrayCast.php b/tests/TestClasses/Casts/PostgresArrayCast.php new file mode 100644 index 0000000..d083d7f --- /dev/null +++ b/tests/TestClasses/Casts/PostgresArrayCast.php @@ -0,0 +1,39 @@ + + */ +class PostgresArrayCast implements CastsAttributes +{ + public function get(Model $model, string $key, mixed $value, array $attributes): ?array + { + if ($value === null) { + return null; + } + + return Arr::fromPostgresArray((string)$value); + } + + public function set(Model $model, string $key, mixed $value, array $attributes): ?string + { + if ($value === null) { + return null; + } + + return Arr::toPostgresArray((array)$value); + } +} diff --git a/tests/TestClasses/Models/PgArrayModel.php b/tests/TestClasses/Models/PgArrayModel.php index fcc3a85..4b5bdce 100755 --- a/tests/TestClasses/Models/PgArrayModel.php +++ b/tests/TestClasses/Models/PgArrayModel.php @@ -6,8 +6,7 @@ use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Model; -use Php\Support\Laravel\Caster\HasCasts; -use Php\Support\Laravel\Caster\PgArray; +use Php\Support\Laravel\Tests\TestClasses\Casts\PostgresArrayCast; use Php\Support\Laravel\Traits\Models\PostgresArray; /** @@ -23,7 +22,6 @@ */ class PgArrayModel extends Model { - use HasCasts; use PostgresArray; public $timestamps = false; @@ -37,8 +35,8 @@ class PgArrayModel extends Model ]; protected $casts = [ - 'tags' => PgArray::class, - // 'tag_ids' => PgArray::class, + 'tags' => PostgresArrayCast::class, + 'tag_ids' => PostgresArrayCast::class, ]; public function scopeByTag(Builder $query, string $value) diff --git a/tests/TestClasses/Models/TestModel.php b/tests/TestClasses/Models/TestModel.php index 6d79fca..c0af31a 100755 --- a/tests/TestClasses/Models/TestModel.php +++ b/tests/TestClasses/Models/TestModel.php @@ -6,19 +6,12 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Foundation\Auth\User; -use Php\Support\Laravel\Caster\GeoPoint; -use Php\Support\Laravel\Caster\HasCasts; -use Php\Support\Laravel\Tests\TestClasses\Entity\Params; -use Php\Support\Laravel\Tests\TestClasses\Entity\Status; /** * Class TestModel * @package Php\Support\Laravel\Tests\Models * @property boolean $enabled * @property string $title - * @property Params $params - * @property Status $status - * @property GeoPoint $geo_point * @property array $config * @property string $str * @property string $str_empty @@ -28,32 +21,24 @@ */ class TestModel extends Model { - use HasCasts; - public $timestamps = false; protected $keyType = 'string'; protected $table = 'test_table'; protected $fillable = [ - 'params', 'config', 'str', - 'status', 'str_empty', 'int', 'enabled', - 'geo_point', ]; protected $casts = [ 'enabled' => 'bool', - 'params' => Params::class, - 'status' => Status::class, 'config' => 'array', 'str' => 'string', 'str_empty' => 'string', 'int' => 'int', - 'geo_point' => GeoPoint::class, ]; public function user(): BelongsTo diff --git a/tests/database/factories/TestModelFactory.php b/tests/database/factories/TestModelFactory.php index 8d929d4..2f38f57 100755 --- a/tests/database/factories/TestModelFactory.php +++ b/tests/database/factories/TestModelFactory.php @@ -3,8 +3,6 @@ namespace Php\Support\Laravel\Tests\Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; -use Php\Support\Laravel\Caster\GeoPoint; -use Php\Support\Laravel\Tests\TestClasses\Entity\Status; use Php\Support\Laravel\Tests\TestClasses\Models\TestModel; class TestModelFactory extends Factory @@ -19,11 +17,9 @@ class TestModelFactory extends Factory public function definition(): array { return [ - 'title' => $this->faker->sentence, - 'str' => $this->faker->title, - 'enabled' => $this->faker->randomElement([true, false]), - 'status' => $this->faker->randomElement(Status::STATUSES), - 'geo_point' => new GeoPoint($this->faker->randomFloat(), $this->faker->randomFloat()), + 'title' => $this->faker->sentence, + 'str' => $this->faker->title, + 'enabled' => $this->faker->randomElement([true, false]), ]; } } diff --git a/tests/database/migrations/2020_01_22_075141_create_caster_table.php b/tests/database/migrations/2020_01_22_075141_create_caster_table.php deleted file mode 100755 index 7d82292..0000000 --- a/tests/database/migrations/2020_01_22_075141_create_caster_table.php +++ /dev/null @@ -1,87 +0,0 @@ -increments('id'); - $table->string('name'); - $table->string('email'); - $table->string('password'); - $table->string('remember_token'); - $table->timestamps(); - } - ); - - Schema::create( - 'test_table', - static function (Blueprint $table) { - static::columnUUID($table)->primary(); - - $table->string('title')->nullable(); - $table->boolean('enabled')->default(false); - $table->jsonb('params')->nullable(); - $table->string('status')->nullable(); - $table->jsonb('config')->nullable(); - $table->string('str')->nullable(); - $table->string('str_empty')->nullable(); - $table->integer('int')->default(0); - $table->integer('user_id')->nullable(); - } - ); - - DB::statement('ALTER TABLE test_table ADD COLUMN geo_point point'); - - Schema::create( - 'pg_table', - static function (Blueprint $table) { - static::columnUUID($table)->primary(); - $table->string('title')->nullable(); - } - ); - - DB::statement('ALTER TABLE pg_table ADD COLUMN tags varchar(255)[]'); - DB::statement('ALTER TABLE pg_table ADD COLUMN tag_ids integer[]'); - - - Schema::create( - 'test_table_caster', - static function (Blueprint $table) { - static::columnUUID($table)->primary(); - - $table->jsonb('components')->nullable(); - $table->jsonb('arrays')->nullable(); - } - ); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('test_table_caster'); - Schema::dropIfExists('pg_table'); - Schema::dropIfExists('test_table'); - Schema::dropIfExists('users'); - } - -} diff --git a/tests/database/migrations/2020_01_22_075141_create_test_tables.php b/tests/database/migrations/2020_01_22_075141_create_test_tables.php new file mode 100755 index 0000000..28d8367 --- /dev/null +++ b/tests/database/migrations/2020_01_22_075141_create_test_tables.php @@ -0,0 +1,46 @@ +increments('id'); + $table->string('name'); + $table->string('email'); + $table->string('password'); + $table->string('remember_token'); + $table->timestamps(); + } + ); + + Schema::create( + 'test_table', + static function (Blueprint $table) { + $table->uuid('id')->primary()->default(DB::raw('gen_random_uuid()')); + + $table->string('title')->nullable(); + $table->boolean('enabled')->default(false); + $table->jsonb('config')->nullable(); + $table->string('str')->nullable(); + $table->string('str_empty')->nullable(); + $table->integer('int')->default(0); + $table->integer('user_id')->nullable(); + } + ); + } + + public function down(): void + { + Schema::dropIfExists('test_table'); + Schema::dropIfExists('users'); + } +}; diff --git a/tests/database/migrations/sortable/2020_02_04_075141_create_sortable_table.php b/tests/database/migrations/sortable/2020_02_04_075141_create_sortable_table.php index 3403ea5..66d38ff 100755 --- a/tests/database/migrations/sortable/2020_02_04_075141_create_sortable_table.php +++ b/tests/database/migrations/sortable/2020_02_04_075141_create_sortable_table.php @@ -5,11 +5,10 @@ use Illuminate\Support\Facades\Schema; use Php\Support\Laravel\Sorting\Database\Sortable; use Php\Support\Laravel\Tests\TestClasses\Models\SortEntity; -use Php\Support\Laravel\Traits\Database\UUID; class CreateSortableTable extends Migration { - use Sortable, UUID; + use Sortable; /** * Run the migrations. diff --git a/tests/database/migrations/sortable/2020_04_04_133841_create_sort_entities_with_sorting_restrictions_table.php b/tests/database/migrations/sortable/2020_04_04_133841_create_sort_entities_with_sorting_restrictions_table.php index a18d035..88d22f7 100755 --- a/tests/database/migrations/sortable/2020_04_04_133841_create_sort_entities_with_sorting_restrictions_table.php +++ b/tests/database/migrations/sortable/2020_04_04_133841_create_sort_entities_with_sorting_restrictions_table.php @@ -2,13 +2,13 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; use Php\Support\Laravel\Sorting\Database\Sortable; -use Php\Support\Laravel\Traits\Database\UUID; class CreateSortEntitiesWithSortingRestrictionsTable extends Migration { - use Sortable, UUID; + use Sortable; /** * Run the migrations. @@ -20,7 +20,7 @@ public function up() Schema::create( 'sort_entities_with_sorting_restrictions', static function (Blueprint $table) { - static::columnUUID($table)->primary(); + $table->uuid('id')->primary()->default(DB::raw('gen_random_uuid()')); static::columnSortingPosition($table); $table->string('model_type'); $table->string('model_id'); diff --git a/tests/database/migrations/sortable/2021_01_21_092141_create_sortable_table_w_custom_col.php b/tests/database/migrations/sortable/2021_01_21_092141_create_sortable_table_w_custom_col.php index 1efe06f..d2fc465 100755 --- a/tests/database/migrations/sortable/2021_01_21_092141_create_sortable_table_w_custom_col.php +++ b/tests/database/migrations/sortable/2021_01_21_092141_create_sortable_table_w_custom_col.php @@ -4,12 +4,12 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; use Php\Support\Laravel\Sorting\Database\Sortable; +use Illuminate\Support\Facades\DB; use Php\Support\Laravel\Tests\TestClasses\Models\SortCustomColumnModel; -use Php\Support\Laravel\Traits\Database\UUID; class CreateSortableTableWCustomCol extends Migration { - use Sortable, UUID; + use Sortable; /** * Run the migrations. @@ -21,7 +21,7 @@ public function up() Schema::create( 'sort_entities_custom_col', static function (Blueprint $table) { - static::columnUUID($table)->primary(); + $table->uuid('id')->primary()->default(DB::raw('gen_random_uuid()')); static::columnSortingPosition($table, SortCustomColumnModel::getSortingColumnName()); $table->string('title')->nullable(); } diff --git a/tests/database/migrations_uuid/2020_01_22_075141_create_uuid_table.php b/tests/database/migrations_uuid/2020_01_22_075141_create_uuid_table.php deleted file mode 100755 index 859d01c..0000000 --- a/tests/database/migrations_uuid/2020_01_22_075141_create_uuid_table.php +++ /dev/null @@ -1,76 +0,0 @@ -primary(); - - $table->string('title')->nullable(); - } - ); - - - Schema::create( - 'uuid_table2', - static function (Blueprint $table) { - static::columnUUID($table)->primary(); - static::columnUUID($table, 'table_id', null)->index(); - // $table->foreign('table_id')->references('id')->on('uuid_table')->onDelete('cascade'); - } - ); - - $driverName = DB::getDriverName(); - - switch ($driverName) { - case 'pgsql': - DB::statement('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";'); - $expression = 'uuid_generate_v4()'; - break; - case 'mysql': - $expression = 'UUID()'; - break; - default: - $expression = ''; - } - - Schema::create( - 'uuid_table3', - static function (Blueprint $table) use ($expression) { - static::columnUUID($table)->primary(); - static::columnUUID($table, 'table_id', new Expression($expression))->index(); - //$table->foreign('table_id')->references('id')->on('uuid_table'); - } - ); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('uuid_table'); - Schema::dropIfExists('uuid_table2'); - Schema::dropIfExists('uuid_table3'); - } - -}