mirror of
https://github.com/barryvdh/laravel-ide-helper.git
synced 2026-08-18 10:07:12 +00:00
Compare commits
29
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c9b88f4b0 | ||
|
|
7345b1bff4 | ||
|
|
0fa3161af3 | ||
|
|
ee7b0cf6bd | ||
|
|
7cd11e292c | ||
|
|
392d5cfc80 | ||
|
|
3d8fccd700 | ||
|
|
e9b62b6ee0 | ||
|
|
37dfcf9e14 | ||
|
|
573c9f3f57 | ||
|
|
fd3cfbe09d | ||
|
|
3bd70eafd0 | ||
|
|
5aca186d92 | ||
|
|
148f956272 | ||
|
|
cff155b0d3 | ||
|
|
d87ec5835d | ||
|
|
b0dcd7c62f | ||
|
|
2ac73f2953 | ||
|
|
c95825a745 | ||
|
|
db606f30d1 | ||
|
|
b106f7ee85 | ||
|
|
d61d20357e | ||
|
|
e9283c40a2 | ||
|
|
12a0d7d54c | ||
|
|
9ef25f60e7 | ||
|
|
8dff6bb5ff | ||
|
|
53854ea7d9 | ||
|
|
1fa84a3b65 | ||
|
|
5e973967a7 |
@@ -12,7 +12,7 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Git checkout
|
- name: Git checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Validate Composer configuration
|
- name: Validate Composer configuration
|
||||||
run: composer validate --strict
|
run: composer validate --strict
|
||||||
@@ -23,6 +23,6 @@ jobs:
|
|||||||
composer global require ergebnis/composer-normalize
|
composer global require ergebnis/composer-normalize
|
||||||
composer normalize
|
composer normalize
|
||||||
|
|
||||||
- uses: stefanzweifel/git-auto-commit-action@v6
|
- uses: stefanzweifel/git-auto-commit-action@v7
|
||||||
with:
|
with:
|
||||||
commit_message: normalize composer.json
|
commit_message: normalize composer.json
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- run: composer fix-style
|
- run: composer fix-style
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- uses: stefanzweifel/git-auto-commit-action@v6
|
- uses: stefanzweifel/git-auto-commit-action@v7
|
||||||
with:
|
with:
|
||||||
commit_message: composer fix-style
|
commit_message: composer fix-style
|
||||||
commit_author: laravel-ide-helper <[email protected]>
|
commit_author: laravel-ide-helper <[email protected]>
|
||||||
|
|||||||
@@ -1,75 +1,79 @@
|
|||||||
name: Integration Tests
|
name: Integration Tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- "*"
|
- "*"
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * *'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
php-laravel-integration-tests:
|
php-laravel-integration-tests:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
timeout-minutes: 15
|
|
||||||
env:
|
|
||||||
COMPOSER_NO_INTERACTION: 1
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
php: [8.4, 8.3, 8.2]
|
|
||||||
laravel: [11.x, 12.x]
|
|
||||||
|
|
||||||
name: P${{ matrix.php }} - Laravel${{ matrix.laravel }}
|
timeout-minutes: 15
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
path: src
|
|
||||||
|
|
||||||
- name: Setup PHP
|
env:
|
||||||
uses: shivammathur/setup-php@v2
|
COMPOSER_NO_INTERACTION: 1
|
||||||
with:
|
|
||||||
php-version: ${{ matrix.php }}
|
|
||||||
coverage: none
|
|
||||||
|
|
||||||
- name: Install dependencies
|
strategy:
|
||||||
run: |
|
fail-fast: false
|
||||||
composer create-project --prefer-dist laravel/laravel:${{ matrix.laravel }} --stability=dev --no-progress sample
|
matrix:
|
||||||
cd sample
|
php: [8.5, 8.4, 8.3, 8.2]
|
||||||
composer config minimum-stability dev
|
laravel: [11.x, 12.x, 13.x]
|
||||||
composer update --prefer-stable --prefer-dist --no-progress
|
exclude:
|
||||||
|
- laravel: 13.x
|
||||||
|
php: 8.2
|
||||||
|
|
||||||
- name: Add package from source
|
name: P${{ matrix.php }} - Laravel${{ matrix.laravel }}
|
||||||
run: |
|
|
||||||
cd sample
|
|
||||||
sed -e 's|"type": "project",|&\n"repositories": [ { "type": "path", "url": "../src" } ],|' -i composer.json
|
|
||||||
composer require --dev "barryvdh/laravel-ide-helper:*" --with-all-dependencies
|
|
||||||
|
|
||||||
- name: Execute generate run
|
steps:
|
||||||
run: |
|
- name: Checkout code
|
||||||
cd sample
|
uses: actions/checkout@v6
|
||||||
php artisan ide-helper:generate
|
with:
|
||||||
|
path: src
|
||||||
|
|
||||||
- name: Execute meta run
|
- name: Setup PHP
|
||||||
run: |
|
uses: shivammathur/setup-php@v2
|
||||||
cd sample
|
with:
|
||||||
php artisan ide-helper:meta -v
|
php-version: ${{ matrix.php }}
|
||||||
|
coverage: none
|
||||||
|
|
||||||
- name: Check file existence
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
ls sample/_ide_helper.php
|
composer create-project --prefer-dist laravel/laravel:${{ matrix.laravel }} --stability=dev --no-progress sample
|
||||||
ls sample/.phpstorm.meta.php
|
cd sample
|
||||||
|
composer config minimum-stability dev
|
||||||
|
composer update --prefer-stable --prefer-dist --no-progress
|
||||||
|
|
||||||
|
- name: Add package from source
|
||||||
|
run: |
|
||||||
|
cd sample
|
||||||
|
sed -e 's|"type": "project",|&\n"repositories": [ { "type": "path", "url": "../src" } ],|' -i composer.json
|
||||||
|
composer require --dev "barryvdh/laravel-ide-helper:*" --with-all-dependencies
|
||||||
|
|
||||||
- name: Check logs
|
- name: Execute generate run
|
||||||
run: |
|
run: |
|
||||||
if [ `ls -1q "sample/storage/logs/" | wc -l` -gt 0 ]; then
|
cd sample
|
||||||
for logfile in sample/storage/logs/*; do
|
php artisan ide-helper:generate
|
||||||
echo "-- $logfile --"
|
|
||||||
cat $logfile
|
- name: Execute meta run
|
||||||
done
|
run: |
|
||||||
exit 1
|
cd sample
|
||||||
fi
|
php artisan ide-helper:meta -v
|
||||||
|
|
||||||
|
- name: Check file existence
|
||||||
|
run: |
|
||||||
|
ls sample/_ide_helper.php
|
||||||
|
ls sample/.phpstorm.meta.php
|
||||||
|
|
||||||
|
- name: Check logs
|
||||||
|
run: |
|
||||||
|
if [ `ls -1q "sample/storage/logs/" | wc -l` -gt 0 ]; then
|
||||||
|
for logfile in sample/storage/logs/*; do
|
||||||
|
echo "-- $logfile --"
|
||||||
|
cat $logfile
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ jobs:
|
|||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
@@ -25,4 +25,4 @@ jobs:
|
|||||||
run: composer install --prefer-dist --no-progress --no-suggest
|
run: composer install --prefer-dist --no-progress --no-suggest
|
||||||
|
|
||||||
- name: Analyze
|
- name: Analyze
|
||||||
run: composer analyze
|
run: vendor/bin/phpstan --no-progress --error-format=github
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- "*"
|
- "*"
|
||||||
schedule:
|
|
||||||
- cron: '0 0 * * *'
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
php-tests:
|
php-tests:
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
|
|
||||||
env:
|
env:
|
||||||
COMPOSER_NO_INTERACTION: 1
|
COMPOSER_NO_INTERACTION: 1
|
||||||
|
|
||||||
@@ -21,37 +21,41 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest]
|
os: [ubuntu-latest]
|
||||||
php: [8.4, 8.3, 8.2]
|
php: [8.5, 8.4, 8.3, 8.2]
|
||||||
laravel: [~11.15, 12.x]
|
laravel: [12.x, 13.x, ~11.15]
|
||||||
stability: [prefer-lowest, prefer-stable]
|
stability: [prefer-lowest, prefer-stable]
|
||||||
include:
|
include:
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
php: 8.3
|
php: 8.3
|
||||||
laravel: 12.x
|
laravel: 12.x
|
||||||
stability: prefer-stable
|
stability: prefer-stable
|
||||||
|
exclude:
|
||||||
|
- laravel: 13.x
|
||||||
|
php: 8.2
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Set git to use LF
|
- name: Set git to use LF
|
||||||
if: ${{ matrix.os == 'windows-latest' }}
|
if: "${{ matrix.os == 'windows-latest' }}"
|
||||||
run: |
|
run: |
|
||||||
git config --global core.autocrlf false
|
git config --global core.autocrlf false
|
||||||
git config --global core.eol lf
|
git config --global core.eol lf
|
||||||
|
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php }}
|
php-version: ${{ matrix.php }}
|
||||||
coverage: none
|
coverage: none
|
||||||
extensions: pdo_sqlite, fileinfo
|
extensions: pdo_sqlite, fileinfo
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
composer remove vimeo/psalm --no-update --dev
|
composer remove vimeo/psalm --no-update --dev
|
||||||
composer remove friendsofphp/php-cs-fixer --no-update --dev
|
composer remove friendsofphp/php-cs-fixer --no-update --dev
|
||||||
composer require "laravel/framework:${{ matrix.laravel }}" --no-update --no-progress
|
composer require "laravel/framework:${{ matrix.laravel }}" --no-update --no-progress
|
||||||
composer update --prefer-dist --no-progress --${{ matrix.stability }}
|
composer update --prefer-dist --no-progress --${{ matrix.stability }}
|
||||||
|
|
||||||
- name: Execute Unit Tests
|
- name: Execute Unit Tests
|
||||||
run: composer test-ci
|
run: composer test-ci
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v6
|
||||||
with:
|
with:
|
||||||
ref: ${{ github.event.release.target_commitish }}
|
ref: ${{ github.event.release.target_commitish }}
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
release-notes: ${{ github.event.release.body }}
|
release-notes: ${{ github.event.release.body }}
|
||||||
|
|
||||||
- name: Commit updated CHANGELOG
|
- name: Commit updated CHANGELOG
|
||||||
uses: stefanzweifel/git-auto-commit-action@v6
|
uses: stefanzweifel/git-auto-commit-action@v7
|
||||||
with:
|
with:
|
||||||
branch: ${{ github.event.release.target_commitish }}
|
branch: ${{ github.event.release.target_commitish }}
|
||||||
commit_message: Update CHANGELOG
|
commit_message: Update CHANGELOG
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
|
/auth.json
|
||||||
|
/build
|
||||||
/.idea
|
/.idea
|
||||||
/.php-cs-fixer.cache
|
/.php-cs-fixer.cache
|
||||||
/.php-cs-fixer.php
|
/.php-cs-fixer.php
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require __DIR__ . '/vendor/autoload.php';
|
|||||||
|
|
||||||
$finder = PhpCsFixer\Finder::create()
|
$finder = PhpCsFixer\Finder::create()
|
||||||
->in(__DIR__)
|
->in(__DIR__)
|
||||||
->exclude('tests');
|
->exclude(['tests', 'build']);
|
||||||
|
|
||||||
$config = require __DIR__ . '/.php-cs-fixer.common.php';
|
$config = require __DIR__ . '/.php-cs-fixer.common.php';
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,59 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v3.6.1 - 2025-12-10
|
||||||
|
|
||||||
|
### What's Changed
|
||||||
|
|
||||||
|
* Fix `methodsto` typo in README by @peterchrjoergensen in https://github.com/barryvdh/laravel-ide-helper/pull/1723
|
||||||
|
* Bump actions/checkout from 4 to 5 in the deps group by @dependabot[bot] in https://github.com/barryvdh/laravel-ide-helper/pull/1731
|
||||||
|
* Fix typos in documentation and code comments by @kei1111 in https://github.com/barryvdh/laravel-ide-helper/pull/1733
|
||||||
|
* Add php 8.5 support by @sergiy-petrov in https://github.com/barryvdh/laravel-ide-helper/pull/1735
|
||||||
|
* Fix alias fake error by @WentTheFox in https://github.com/barryvdh/laravel-ide-helper/pull/1745
|
||||||
|
* Remove calls to PHP 8.5-deprecated `setAccessible` by @jnoordsij in https://github.com/barryvdh/laravel-ide-helper/pull/1744
|
||||||
|
* Bump the deps group across 1 directory with 2 updates by @dependabot[bot] in https://github.com/barryvdh/laravel-ide-helper/pull/1743
|
||||||
|
* Add support for `decimal` column type by @BrainStone in https://github.com/barryvdh/laravel-ide-helper/pull/1739
|
||||||
|
|
||||||
|
### New Contributors
|
||||||
|
|
||||||
|
* @peterchrjoergensen made their first contribution in https://github.com/barryvdh/laravel-ide-helper/pull/1723
|
||||||
|
* @kei1111 made their first contribution in https://github.com/barryvdh/laravel-ide-helper/pull/1733
|
||||||
|
* @WentTheFox made their first contribution in https://github.com/barryvdh/laravel-ide-helper/pull/1745
|
||||||
|
* @BrainStone made their first contribution in https://github.com/barryvdh/laravel-ide-helper/pull/1739
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/barryvdh/laravel-ide-helper/compare/v3.6.0...v3.6.1
|
||||||
|
|
||||||
|
## v3.6.0 - 2025-07-18
|
||||||
|
|
||||||
|
### What's Changed
|
||||||
|
|
||||||
|
* fix: Change AsArrayObject cast to be Laravel's ArrayObject by @wsamoht in https://github.com/barryvdh/laravel-ide-helper/pull/1675
|
||||||
|
* Add extends declaration for Macroable classes to fix missing inherited methods by @KentarouTakeda in https://github.com/barryvdh/laravel-ide-helper/pull/1674
|
||||||
|
* fix(meta): ignore aliases in the autoloader (Fixes #1671) by @pataar in https://github.com/barryvdh/laravel-ide-helper/pull/1686
|
||||||
|
* feat(ModelsCommand): add support for the new Scope attribute by @pataar in https://github.com/barryvdh/laravel-ide-helper/pull/1694
|
||||||
|
* fix type change for scope default float parameter by @nivseb in https://github.com/barryvdh/laravel-ide-helper/pull/1697
|
||||||
|
* Revert #1629 - *Allow adding custom Macroable classes* by @erikn69 in https://github.com/barryvdh/laravel-ide-helper/pull/1707
|
||||||
|
* Configurable macro return type defaults by @erikn69 in https://github.com/barryvdh/laravel-ide-helper/pull/1711
|
||||||
|
* docs(readme): add Laravel 12 support information by @SantosVilanculos in https://github.com/barryvdh/laravel-ide-helper/pull/1717
|
||||||
|
* Add multi-level directory support for translation files by @RosiersRobin in https://github.com/barryvdh/laravel-ide-helper/pull/1718
|
||||||
|
* Support `AsCollection::of($map)`, `AsCollection::using($class, $map)` by @erikn69 in https://github.com/barryvdh/laravel-ide-helper/pull/1714
|
||||||
|
* fix: Fixed wrong doc for SoftDeletes `withTrashed` method by @eldair in https://github.com/barryvdh/laravel-ide-helper/pull/1688
|
||||||
|
* Support other OS on tests by @erikn69 in https://github.com/barryvdh/laravel-ide-helper/pull/1715
|
||||||
|
* Fix tests on windows by @barryvdh in https://github.com/barryvdh/laravel-ide-helper/pull/1720
|
||||||
|
* Bump stefanzweifel/git-auto-commit-action from 5 to 6 in the deps group by @dependabot[bot] in https://github.com/barryvdh/laravel-ide-helper/pull/1719
|
||||||
|
* Update .gitattributes - avoid all `.php-cs-fixer` files on vendor by @erikn69 in https://github.com/barryvdh/laravel-ide-helper/pull/1708
|
||||||
|
* fix(ModelsCommand): use 'string' as realType for 'encrypted' casts by @pataar in https://github.com/barryvdh/laravel-ide-helper/pull/1698
|
||||||
|
* Trim strings and bump reflection docblock by @barryvdh in https://github.com/barryvdh/laravel-ide-helper/pull/1721
|
||||||
|
* Add magic *_exists properties by @erikn69 in https://github.com/barryvdh/laravel-ide-helper/pull/1712
|
||||||
|
|
||||||
|
### New Contributors
|
||||||
|
|
||||||
|
* @wsamoht made their first contribution in https://github.com/barryvdh/laravel-ide-helper/pull/1675
|
||||||
|
* @nivseb made their first contribution in https://github.com/barryvdh/laravel-ide-helper/pull/1697
|
||||||
|
* @SantosVilanculos made their first contribution in https://github.com/barryvdh/laravel-ide-helper/pull/1717
|
||||||
|
* @RosiersRobin made their first contribution in https://github.com/barryvdh/laravel-ide-helper/pull/1718
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/barryvdh/laravel-ide-helper/compare/v3.5.5...v3.6.0
|
||||||
|
|
||||||
## v3.5.5 - 2025-02-21
|
## v3.5.5 - 2025-02-21
|
||||||
|
|
||||||
### What's Changed
|
### What's Changed
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ php artisan ide-helper:models -RW
|
|||||||
|
|
||||||
If you don't want the full _ide_helper.php file, you can run add `--write-eloquent-helper` to the model command to generate small version, which is required for the `@mixin \Eloquent` to be able to add the QueryBuilder methods.
|
If you don't want the full _ide_helper.php file, you can run add `--write-eloquent-helper` to the model command to generate small version, which is required for the `@mixin \Eloquent` to be able to add the QueryBuilder methods.
|
||||||
|
|
||||||
If you don't want to add all the phpdocs to your Models directly, you can use `--nowrite` to create a seperate file. The `--write-mixin` option can be used to only add a `@mixin` to your models, but add the generated phpdocs in a seperate file. This avoids having the results marked as duplicate.
|
If you don't want to add all the phpdocs to your Models directly, you can use `--nowrite` to create a separate file. The `--write-mixin` option can be used to only add a `@mixin` to your models, but add the generated phpdocs in a separate file. This avoids having the results marked as duplicate.
|
||||||
|
|
||||||
|
|
||||||
_Check out [this Laracasts video](https://laracasts.com/series/how-to-be-awesome-in-phpstorm/episodes/15) for a quick introduction/explanation!_
|
_Check out [this Laracasts video](https://laracasts.com/series/how-to-be-awesome-in-phpstorm/episodes/15) for a quick introduction/explanation!_
|
||||||
@@ -212,7 +212,7 @@ If for some reason it's undesired to have them generated (one for each column),
|
|||||||
|
|
||||||
#### Magic `*_count` and `*_exists` properties
|
#### Magic `*_count` and `*_exists` properties
|
||||||
|
|
||||||
You may use the [`::withCount`](https://laravel.com/docs/master/eloquent-relationships#counting-related-models) and [`::withExists`](https://laravel.com/docs/master/eloquent-relationships#other-aggregate-functions) methodsto count the number results from a relationship without actually loading them. Those results are then placed in attributes following the `<columname>_count` and `<columname>_exists` convention.
|
You may use the [`::withCount`](https://laravel.com/docs/master/eloquent-relationships#counting-related-models) and [`::withExists`](https://laravel.com/docs/master/eloquent-relationships#other-aggregate-functions) methods to count the number results from a relationship without actually loading them. Those results are then placed in attributes following the `<columnname>_count` and `<columnname>_exists` convention.
|
||||||
|
|
||||||
By default, these attributes are generated in the phpdoc. You can turn them off by setting the config `write_model_relation_count_properties` and `write_model_relation_exists_properties` to `false`.
|
By default, these attributes are generated in the phpdoc. You can turn them off by setting the config `write_model_relation_count_properties` and `write_model_relation_exists_properties` to `false`.
|
||||||
|
|
||||||
|
|||||||
+13
-12
@@ -25,21 +25,22 @@
|
|||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"barryvdh/reflection-docblock": "^2.4",
|
"barryvdh/reflection-docblock": "^2.4",
|
||||||
"composer/class-map-generator": "^1.0",
|
"composer/class-map-generator": "^1.0",
|
||||||
"illuminate/console": "^11.15 || ^12",
|
"illuminate/console": "^11.15 || ^12 || ^13.0",
|
||||||
"illuminate/database": "^11.15 || ^12",
|
"illuminate/database": "^11.15 || ^12 || ^13.0",
|
||||||
"illuminate/filesystem": "^11.15 || ^12",
|
"illuminate/filesystem": "^11.15 || ^12 || ^13.0",
|
||||||
"illuminate/support": "^11.15 || ^12"
|
"illuminate/support": "^11.15 || ^12 || ^13.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"ext-pdo_sqlite": "*",
|
"ext-pdo_sqlite": "*",
|
||||||
"friendsofphp/php-cs-fixer": "^3",
|
"friendsofphp/php-cs-fixer": "^3",
|
||||||
"illuminate/config": "^11.15 || ^12",
|
"illuminate/config": "^11.15 || ^12 || ^13.0",
|
||||||
"illuminate/view": "^11.15 || ^12",
|
"illuminate/view": "^11.15 || ^12 || ^13.0",
|
||||||
|
"larastan/larastan": "^3.1",
|
||||||
"mockery/mockery": "^1.4",
|
"mockery/mockery": "^1.4",
|
||||||
"orchestra/testbench": "^9.2 || ^10",
|
"orchestra/testbench": "^9.2 || ^10 || ^11.0",
|
||||||
"phpunit/phpunit": "^10.5 || ^11.5.3",
|
"phpstan/phpstan-phpunit": "^2.0",
|
||||||
|
"phpunit/phpunit": "^10.5 || ^11.5.3 || ^12.5.12",
|
||||||
"spatie/phpunit-snapshot-assertions": "^4 || ^5",
|
"spatie/phpunit-snapshot-assertions": "^4 || ^5",
|
||||||
"vimeo/psalm": "^5.4",
|
|
||||||
"vlucas/phpdotenv": "^5"
|
"vlucas/phpdotenv": "^5"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
@@ -74,7 +75,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"analyze": "psalm",
|
"analyze": "phpstan",
|
||||||
|
"analyze-set-baseline": "phpstan --generate-baseline",
|
||||||
"check-style": [
|
"check-style": [
|
||||||
"php-cs-fixer fix --diff --diff-format=udiff --dry-run",
|
"php-cs-fixer fix --diff --diff-format=udiff --dry-run",
|
||||||
"php-cs-fixer fix --diff --diff-format=udiff --dry-run --config=.php_cs.tests.php"
|
"php-cs-fixer fix --diff --diff-format=udiff --dry-run --config=.php_cs.tests.php"
|
||||||
@@ -83,9 +85,8 @@
|
|||||||
"php-cs-fixer fix",
|
"php-cs-fixer fix",
|
||||||
"php-cs-fixer fix --config=.php-cs-fixer.tests.php"
|
"php-cs-fixer fix --config=.php-cs-fixer.tests.php"
|
||||||
],
|
],
|
||||||
"psalm-set-baseline": "psalm --set-baseline=psalm-baseline.xml",
|
|
||||||
"test": "phpunit",
|
"test": "phpunit",
|
||||||
"test-ci": "phpunit -d --without-creating-snapshots",
|
"test-ci": "phpunit",
|
||||||
"test-regenerate": "phpunit -d --update-snapshots"
|
"test-regenerate": "phpunit -d --update-snapshots"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+49
-29
@@ -49,17 +49,14 @@ return [
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Factory builders
|
| Write model query methods
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| Set to true to generate factory generators for better factory()
|
| Set to false to disable generated docs for the 'query()', 'newQuery()' and 'newModelQuery()' methods.
|
||||||
| method auto-completion.
|
|
||||||
|
|
|
||||||
| Deprecated for Laravel 8 or latest.
|
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'include_factory_builders' => false,
|
'write_query_methods' => true,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@@ -204,29 +201,29 @@ return [
|
|||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Support for camel cased models
|
| Support for camel cased models
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
|
||||||
| There are some Laravel packages (such as Eloquence) that allow for accessing
|
| There are some Laravel packages (such as Eloquence) that allow for accessing
|
||||||
| Eloquent model properties via camel case, instead of snake case.
|
| Eloquent model properties via camel case, instead of snake case.
|
||||||
|
|
|
|
||||||
| Enabling this option will support these packages by saving all model
|
| Enabling this option will support these packages by saving all model
|
||||||
| properties as camel case, instead of snake case.
|
| properties as camel case, instead of snake case.
|
||||||
|
|
|
|
||||||
| For example, normally you would see this:
|
| For example, normally you would see this:
|
||||||
|
|
|
|
||||||
| * @property \Illuminate\Support\Carbon $created_at
|
| * @property \Illuminate\Support\Carbon $created_at
|
||||||
| * @property \Illuminate\Support\Carbon $updated_at
|
| * @property \Illuminate\Support\Carbon $updated_at
|
||||||
|
|
|
|
||||||
| With this enabled, the properties will be this:
|
| With this enabled, the properties will be this:
|
||||||
|
|
|
|
||||||
| * @property \Illuminate\Support\Carbon $createdAt
|
| * @property \Illuminate\Support\Carbon $createdAt
|
||||||
| * @property \Illuminate\Support\Carbon $updatedAt
|
| * @property \Illuminate\Support\Carbon $updatedAt
|
||||||
|
|
|
|
||||||
| Note, it is currently an all-or-nothing option.
|
| Note, it is currently an all-or-nothing option.
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
'model_camel_case_properties' => false,
|
'model_camel_case_properties' => false,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -339,6 +336,29 @@ return [
|
|||||||
|
|
||||||
'enforce_nullable_relationships' => true,
|
'enforce_nullable_relationships' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Make soft deletable relations nullable
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When set to true (default), relationships to models using SoftDeletes trait
|
||||||
|
| will be marked as nullable. This is because soft-deleted records are excluded
|
||||||
|
| from queries by default, meaning even non-nullable foreign keys can return
|
||||||
|
| null when the related model is soft-deleted.
|
||||||
|
|
|
||||||
|
| Default: true
|
||||||
|
| A relationship to a soft-deletable model will include |null in the type:
|
||||||
|
| * @property-read Team|null $team
|
||||||
|
|
|
||||||
|
| Option: false
|
||||||
|
| A relationship to a soft-deletable model will NOT include |null (unless
|
||||||
|
| nullable for other reasons such as nullable foreign key column):
|
||||||
|
| * @property-read Team $team
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'soft_deletes_force_nullable' => true,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Run artisan commands after migrations to generate model helpers
|
| Run artisan commands after migrations to generate model helpers
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ $reflection = new ReflectionClass($loader);
|
|||||||
$property = $reflection->hasProperty('paths')
|
$property = $reflection->hasProperty('paths')
|
||||||
? $reflection->getProperty('paths')
|
? $reflection->getProperty('paths')
|
||||||
: $reflection->getProperty('path');
|
: $reflection->getProperty('path');
|
||||||
$property->setAccessible(true);
|
|
||||||
|
|
||||||
$paths = Illuminate\Support\Arr::wrap($property->getValue($loader));
|
$paths = Illuminate\Support\Arr::wrap($property->getValue($loader));
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
parameters:
|
||||||
|
ignoreErrors:
|
||||||
|
-
|
||||||
|
message: '#^File ends with a trailing whitespace\. This may cause problems when running the code in the web browser\. Remove the closing \?\> mark or remove the whitespace\.$#'
|
||||||
|
identifier: whitespace.fileEnd
|
||||||
|
count: 1
|
||||||
|
path: resources/views/helper.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined method Illuminate\\Contracts\\Filesystem\\Filesystem\:\:requireOnce\(\)\.$#'
|
||||||
|
identifier: method.notFound
|
||||||
|
count: 1
|
||||||
|
path: src/Console/MetaCommand.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined method Illuminate\\Contracts\\Foundation\\Application\:\:getBindings\(\)\.$#'
|
||||||
|
identifier: method.notFound
|
||||||
|
count: 1
|
||||||
|
path: src/Console/MetaCommand.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined method Barryvdh\\Reflection\\DocBlock\\Tag\:\:getMethodName\(\)\.$#'
|
||||||
|
identifier: method.notFound
|
||||||
|
count: 1
|
||||||
|
path: src/Console/ModelsCommand.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined method Barryvdh\\Reflection\\DocBlock\\Tag\:\:getType\(\)\.$#'
|
||||||
|
identifier: method.notFound
|
||||||
|
count: 1
|
||||||
|
path: src/Console/ModelsCommand.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined method Barryvdh\\Reflection\\DocBlock\\Tag\:\:getVariableName\(\)\.$#'
|
||||||
|
identifier: method.notFound
|
||||||
|
count: 1
|
||||||
|
path: src/Console/ModelsCommand.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined method Illuminate\\Support\\Optional\:\:getNumberOfParameters\(\)\.$#'
|
||||||
|
identifier: method.notFound
|
||||||
|
count: 1
|
||||||
|
path: src/Console/ModelsCommand.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined method Illuminate\\Support\\Optional\:\:getParameters\(\)\.$#'
|
||||||
|
identifier: method.notFound
|
||||||
|
count: 1
|
||||||
|
path: src/Console/ModelsCommand.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined method Illuminate\\Support\\Optional\:\:getReturnType\(\)\.$#'
|
||||||
|
identifier: method.notFound
|
||||||
|
count: 1
|
||||||
|
path: src/Console/ModelsCommand.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined static method Illuminate\\Database\\Eloquent\\Model\:\:newFactory\(\)\.$#'
|
||||||
|
identifier: staticMethod.notFound
|
||||||
|
count: 2
|
||||||
|
path: src/Console/ModelsCommand.php
|
||||||
|
|
||||||
|
-
|
||||||
|
message: '#^Call to an undefined method ReflectionFunctionAbstract\:\:getDeclaringClass\(\)\.$#'
|
||||||
|
identifier: method.notFound
|
||||||
|
count: 1
|
||||||
|
path: src/Method.php
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
includes:
|
||||||
|
- phpstan-baseline.neon
|
||||||
|
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
level: 2
|
||||||
|
paths:
|
||||||
|
- src
|
||||||
|
- resources/views
|
||||||
|
excludePaths:
|
||||||
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<files psalm-version="5.4.0@62db5d4f6a7ae0a20f7cc5a4952d730272fc0863">
|
|
||||||
<file src="src/Factories.php">
|
|
||||||
<UndefinedClass occurrences="2">
|
|
||||||
<code>Factory</code>
|
|
||||||
<code>Factory</code>
|
|
||||||
</UndefinedClass>
|
|
||||||
</file>
|
|
||||||
<file src="src/Generator.php">
|
|
||||||
<UndefinedClass occurrences="6">
|
|
||||||
<code>\Auth</code>
|
|
||||||
<code>\Cache</code>
|
|
||||||
<code>\Cache</code>
|
|
||||||
<code>\DB</code>
|
|
||||||
<code>\Queue</code>
|
|
||||||
<code>\Storage</code>
|
|
||||||
</UndefinedClass>
|
|
||||||
</file>
|
|
||||||
<file src="src/Console/ModelsCommand.php">
|
|
||||||
<UndefinedClass occurrences="1">
|
|
||||||
<code>\UnitEnum</code>
|
|
||||||
</UndefinedClass>
|
|
||||||
</file>
|
|
||||||
</files>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<psalm
|
|
||||||
errorLevel="7"
|
|
||||||
resolveFromConfigFile="true"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="https://getpsalm.org/schema/config"
|
|
||||||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
|
||||||
errorBaseline="psalm-baseline.xml"
|
|
||||||
>
|
|
||||||
<projectFiles>
|
|
||||||
<directory name="src" />
|
|
||||||
<ignoreFiles>
|
|
||||||
<directory name="vendor" />
|
|
||||||
</ignoreFiles>
|
|
||||||
</projectFiles>
|
|
||||||
</psalm>
|
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
/**
|
/**
|
||||||
* @var Barryvdh\LaravelIdeHelper\Alias[][] $namespaces_by_alias_ns
|
* @var Barryvdh\LaravelIdeHelper\Alias[][] $namespaces_by_alias_ns
|
||||||
* @var Barryvdh\LaravelIdeHelper\Alias[][] $namespaces_by_extends_ns
|
* @var Barryvdh\LaravelIdeHelper\Alias[][] $namespaces_by_extends_ns
|
||||||
|
* @var string[] $real_time_facades
|
||||||
* @var bool $include_fluent
|
* @var bool $include_fluent
|
||||||
* @var string $helpers
|
* @var string $helpers
|
||||||
*/
|
*/
|
||||||
@@ -119,12 +120,3 @@ namespace Illuminate\Support {
|
|||||||
}
|
}
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<?php foreach ($factories as $factory) : ?>
|
|
||||||
namespace <?=$factory->getNamespaceName()?> {
|
|
||||||
/**
|
|
||||||
* @method \Illuminate\Database\Eloquent\Collection|<?=$factory->getShortName()?>[]|<?=$factory->getShortName()?> create($attributes = [])
|
|
||||||
* @method \Illuminate\Database\Eloquent\Collection|<?=$factory->getShortName()?>[]|<?=$factory->getShortName()?> make($attributes = [])
|
|
||||||
*/
|
|
||||||
class <?=$factory->getShortName()?>FactoryBuilder extends \Illuminate\Database\Eloquent\FactoryBuilder {}
|
|
||||||
}
|
|
||||||
<?php endforeach; ?>
|
|
||||||
|
|||||||
+14
-11
@@ -1,4 +1,16 @@
|
|||||||
<?= '<?php' ?>
|
<?= '<?php' ?>
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @var array $bindings
|
||||||
|
* @var string[] $methods
|
||||||
|
* @var string[] $configMethods
|
||||||
|
* @var Illuminate\Support\Collection $configValues
|
||||||
|
* @var array<string, array> $expectedArgumentSets
|
||||||
|
* @var array $expectedArguments
|
||||||
|
* @var string[] $userMethods
|
||||||
|
* @var string $userModel/
|
||||||
|
* */
|
||||||
|
?>
|
||||||
|
|
||||||
/* @noinspection ALL */
|
/* @noinspection ALL */
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@@ -35,15 +47,6 @@ namespace PHPSTORM_META {
|
|||||||
]));
|
]));
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
|
|
||||||
<?php if (count($factories)) : ?>
|
|
||||||
override(\factory(0), map([
|
|
||||||
'' => '@FactoryBuilder',
|
|
||||||
<?php foreach ($factories as $factory) : ?>
|
|
||||||
'<?= $factory->getName() ?>' => \<?= $factory->getName() ?>FactoryBuilder::class,
|
|
||||||
<?php endforeach; ?>
|
|
||||||
]));
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
override(\Illuminate\Foundation\Testing\Concerns\InteractsWithContainer::mock(0), map(["" => "@&\Mockery\MockInterface"]));
|
override(\Illuminate\Foundation\Testing\Concerns\InteractsWithContainer::mock(0), map(["" => "@&\Mockery\MockInterface"]));
|
||||||
override(\Illuminate\Foundation\Testing\Concerns\InteractsWithContainer::partialMock(0), map(["" => "@&\Mockery\MockInterface"]));
|
override(\Illuminate\Foundation\Testing\Concerns\InteractsWithContainer::partialMock(0), map(["" => "@&\Mockery\MockInterface"]));
|
||||||
override(\Illuminate\Foundation\Testing\Concerns\InteractsWithContainer::instance(0), type(1));
|
override(\Illuminate\Foundation\Testing\Concerns\InteractsWithContainer::instance(0), type(1));
|
||||||
@@ -79,7 +82,7 @@ namespace PHPSTORM_META {
|
|||||||
override(\tap(0), type(0));
|
override(\tap(0), type(0));
|
||||||
override(\optional(0), type(0));
|
override(\optional(0), type(0));
|
||||||
|
|
||||||
<?php if (isset($expectedArgumentSets)): ?>
|
<?php if ($expectedArgumentSets): ?>
|
||||||
<?php foreach ($expectedArgumentSets as $name => $argumentsList) : ?>
|
<?php foreach ($expectedArgumentSets as $name => $argumentsList) : ?>
|
||||||
registerArgumentsSet('<?= $name ?>', <?php foreach ($argumentsList as $i => $arg) : ?><?php if ($i % 5 == 0) {
|
registerArgumentsSet('<?= $name ?>', <?php foreach ($argumentsList as $i => $arg) : ?><?php if ($i % 5 == 0) {
|
||||||
echo "\n";
|
echo "\n";
|
||||||
@@ -87,7 +90,7 @@ namespace PHPSTORM_META {
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<?php if (isset($expectedArguments)) : ?>
|
<?php if ($expectedArguments) : ?>
|
||||||
<?php foreach ($expectedArguments as $arguments) : ?>
|
<?php foreach ($expectedArguments as $arguments) : ?>
|
||||||
<?php
|
<?php
|
||||||
$classes = isset($arguments['class']) ? (array) $arguments['class'] : [null];
|
$classes = isset($arguments['class']) ? (array) $arguments['class'] : [null];
|
||||||
|
|||||||
+19
-17
@@ -101,7 +101,7 @@ class Alias
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($facade === '\Illuminate\Database\Eloquent\Model') {
|
if ($facade === '\Illuminate\Database\Eloquent\Model') {
|
||||||
$this->usedMethods = ['decrement', 'increment'];
|
$this->usedMethods = ['decrement' => true, 'increment' => true];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,11 +248,17 @@ class Alias
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$reflection = new \ReflectionMethod($facade, 'fake');
|
||||||
|
if ($reflection->getNumberOfRequiredParameters() > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$real = $facade::getFacadeRoot();
|
$real = $facade::getFacadeRoot();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$facade::fake();
|
$facade::fake();
|
||||||
$fake = $facade::getFacadeRoot();
|
$fake = $facade::getFacadeRoot();
|
||||||
|
|
||||||
if ($fake !== $real) {
|
if ($fake !== $real) {
|
||||||
$this->addClass(get_class($fake));
|
$this->addClass(get_class($fake));
|
||||||
}
|
}
|
||||||
@@ -319,9 +325,8 @@ class Alias
|
|||||||
/**
|
/**
|
||||||
* Get the real root of a facade
|
* Get the real root of a facade
|
||||||
*
|
*
|
||||||
* @return bool|string
|
|
||||||
*/
|
*/
|
||||||
protected function detectRoot()
|
protected function detectRoot(): void
|
||||||
{
|
{
|
||||||
$facade = $this->facade;
|
$facade = $this->facade;
|
||||||
|
|
||||||
@@ -376,11 +381,10 @@ class Alias
|
|||||||
$method = new \ReflectionMethod($className, $name);
|
$method = new \ReflectionMethod($className, $name);
|
||||||
$class = new ReflectionClass($className);
|
$class = new ReflectionClass($className);
|
||||||
|
|
||||||
if (!in_array($magic, $this->usedMethods)) {
|
if (!isset($this->usedMethods[$magic])) {
|
||||||
if ($class !== $this->root) {
|
if ($class !== $this->root) {
|
||||||
$this->methods[] = new Method(
|
$this->methods[] = new Method(
|
||||||
$method,
|
$method,
|
||||||
$this->alias,
|
|
||||||
$class,
|
$class,
|
||||||
$magic,
|
$magic,
|
||||||
$this->interfaces,
|
$this->interfaces,
|
||||||
@@ -389,7 +393,7 @@ class Alias
|
|||||||
$this->getTemplateNames()
|
$this->getTemplateNames()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$this->usedMethods[] = $magic;
|
$this->usedMethods[$magic] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,7 +401,6 @@ class Alias
|
|||||||
/**
|
/**
|
||||||
* Get the methods for one or multiple classes.
|
* Get the methods for one or multiple classes.
|
||||||
*
|
*
|
||||||
* @return string
|
|
||||||
*/
|
*/
|
||||||
protected function detectMethods()
|
protected function detectMethods()
|
||||||
{
|
{
|
||||||
@@ -407,13 +410,12 @@ class Alias
|
|||||||
$methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
|
$methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||||
if ($methods) {
|
if ($methods) {
|
||||||
foreach ($methods as $method) {
|
foreach ($methods as $method) {
|
||||||
if (!in_array($method->name, $this->usedMethods)) {
|
if (!isset($this->usedMethods[$method->name])) {
|
||||||
// Only add the methods to the output when the root is not the same as the class.
|
// Only add the methods to the output when the root is not the same as the class.
|
||||||
// And don't add the __*() methods
|
// And don't add the __*() methods
|
||||||
if ($this->extends !== $class && substr($method->name, 0, 2) !== '__') {
|
if ($this->extends !== $class && substr($method->name, 0, 2) !== '__') {
|
||||||
$this->methods[] = new Method(
|
$this->methods[] = new Method(
|
||||||
$method,
|
$method,
|
||||||
$this->alias,
|
|
||||||
$reflection,
|
$reflection,
|
||||||
$method->name,
|
$method->name,
|
||||||
$this->interfaces,
|
$this->interfaces,
|
||||||
@@ -422,7 +424,7 @@ class Alias
|
|||||||
$this->getTemplateNames(),
|
$this->getTemplateNames(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$this->usedMethods[] = $method->name;
|
$this->usedMethods[$method->name] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,7 +435,7 @@ class Alias
|
|||||||
$properties = $reflection->getStaticProperties();
|
$properties = $reflection->getStaticProperties();
|
||||||
$macros = isset($properties['macros']) ? $properties['macros'] : [];
|
$macros = isset($properties['macros']) ? $properties['macros'] : [];
|
||||||
foreach ($macros as $macro_name => $macro_func) {
|
foreach ($macros as $macro_name => $macro_func) {
|
||||||
if (!in_array($macro_name, $this->usedMethods)) {
|
if (!isset($this->usedMethods[$macro_name])) {
|
||||||
try {
|
try {
|
||||||
$method = $this->getMacroFunction($macro_func);
|
$method = $this->getMacroFunction($macro_func);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
@@ -443,14 +445,13 @@ class Alias
|
|||||||
// Add macros
|
// Add macros
|
||||||
$this->methods[] = new Macro(
|
$this->methods[] = new Macro(
|
||||||
$method,
|
$method,
|
||||||
$this->alias,
|
|
||||||
$reflection,
|
$reflection,
|
||||||
$macro_name,
|
$macro_name,
|
||||||
$this->interfaces,
|
$this->interfaces,
|
||||||
$this->classAliases,
|
$this->classAliases,
|
||||||
$this->getReturnTypeNormalizers($reflection)
|
$this->getReturnTypeNormalizers($reflection)
|
||||||
);
|
);
|
||||||
$this->usedMethods[] = $macro_name;
|
$this->usedMethods[$macro_name] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -588,12 +589,13 @@ class Alias
|
|||||||
*/
|
*/
|
||||||
protected function removeDuplicateMethodsFromPhpDoc()
|
protected function removeDuplicateMethodsFromPhpDoc()
|
||||||
{
|
{
|
||||||
$methodNames = array_map(function (Method $method) {
|
$methodNames = [];
|
||||||
return $method->getName();
|
foreach ($this->getMethods() as $method) {
|
||||||
}, $this->getMethods());
|
$methodNames[$method->getName()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($this->phpdoc->getTags() as $tag) {
|
foreach ($this->phpdoc->getTags() as $tag) {
|
||||||
if ($tag instanceof MethodTag && in_array($tag->getMethodName(), $methodNames)) {
|
if ($tag instanceof MethodTag && isset($methodNames[$tag->getMethodName()])) {
|
||||||
$this->phpdoc->deleteTag($tag);
|
$this->phpdoc->deleteTag($tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
namespace Barryvdh\LaravelIdeHelper\Console;
|
namespace Barryvdh\LaravelIdeHelper\Console;
|
||||||
|
|
||||||
use Barryvdh\LaravelIdeHelper\Factories;
|
|
||||||
use Dotenv\Parser\Entry;
|
use Dotenv\Parser\Entry;
|
||||||
use Dotenv\Parser\Parser;
|
use Dotenv\Parser\Parser;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
@@ -108,9 +107,6 @@ class MetaCommand extends Command
|
|||||||
*/
|
*/
|
||||||
public function handle()
|
public function handle()
|
||||||
{
|
{
|
||||||
// Needs to run before exception handler is registered
|
|
||||||
$factories = $this->config->get('ide-helper.include_factory_builders') ? Factories::all() : [];
|
|
||||||
|
|
||||||
$ourAutoloader = $this->registerClassAutoloadExceptions();
|
$ourAutoloader = $this->registerClassAutoloadExceptions();
|
||||||
|
|
||||||
$bindings = [];
|
$bindings = [];
|
||||||
@@ -149,7 +145,6 @@ class MetaCommand extends Command
|
|||||||
$content = $this->view->make('ide-helper::meta', [
|
$content = $this->view->make('ide-helper::meta', [
|
||||||
'bindings' => $bindings,
|
'bindings' => $bindings,
|
||||||
'methods' => $this->methods,
|
'methods' => $this->methods,
|
||||||
'factories' => $factories,
|
|
||||||
'configMethods' => $this->configMethods,
|
'configMethods' => $this->configMethods,
|
||||||
'configValues' => $configValues,
|
'configValues' => $configValues,
|
||||||
'expectedArgumentSets' => $this->getExpectedArgumentSets(),
|
'expectedArgumentSets' => $this->getExpectedArgumentSets(),
|
||||||
|
|||||||
+153
-41
@@ -123,6 +123,14 @@ class ModelsCommand extends Command
|
|||||||
protected $reset;
|
protected $reset;
|
||||||
protected $phpstorm_noinspections;
|
protected $phpstorm_noinspections;
|
||||||
protected $write_model_external_builder_methods;
|
protected $write_model_external_builder_methods;
|
||||||
|
/**
|
||||||
|
* @var array<string, \SplFileObject>
|
||||||
|
*/
|
||||||
|
protected $fileCache = [];
|
||||||
|
/**
|
||||||
|
* @var array<string, Context>
|
||||||
|
*/
|
||||||
|
protected $contextCache = [];
|
||||||
/**
|
/**
|
||||||
* @var array<string, true>
|
* @var array<string, true>
|
||||||
*/
|
*/
|
||||||
@@ -526,7 +534,7 @@ class ModelsCommand extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($isNullable) {
|
if ($isNullable) {
|
||||||
$type .= '|null';
|
$type = $this->wrapIntersectionType($type) . '|null';
|
||||||
} else {
|
} else {
|
||||||
$type = str_replace($nullString, '', $type);
|
$type = str_replace($nullString, '', $type);
|
||||||
}
|
}
|
||||||
@@ -534,6 +542,22 @@ class ModelsCommand extends Command
|
|||||||
return $type;
|
return $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a bare intersection type in parentheses for correct DNF syntax.
|
||||||
|
*
|
||||||
|
* For example, `A&B` becomes `(A&B)` so that adding `|null` produces
|
||||||
|
* `(A&B)|null` instead of the ambiguous `A&B|null`.
|
||||||
|
* Types that are already parenthesized or contain union types are returned as-is.
|
||||||
|
*/
|
||||||
|
protected function wrapIntersectionType(string $type): string
|
||||||
|
{
|
||||||
|
if (str_contains($type, '&') && !str_contains($type, '|') && $type[0] !== '(') {
|
||||||
|
return '(' . $type . ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the override type for the give type.
|
* Returns the override type for the give type.
|
||||||
*
|
*
|
||||||
@@ -584,6 +608,8 @@ class ModelsCommand extends Command
|
|||||||
'float', 'real', 'float4',
|
'float', 'real', 'float4',
|
||||||
'double', 'float8' => 'float',
|
'double', 'float8' => 'float',
|
||||||
|
|
||||||
|
'decimal', 'numeric' => 'numeric',
|
||||||
|
|
||||||
default => 'string',
|
default => 'string',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -694,13 +720,16 @@ class ModelsCommand extends Command
|
|||||||
);
|
);
|
||||||
$this->setMethod($name, $builder . '<static>|' . $modelName, $args, $comment);
|
$this->setMethod($name, $builder . '<static>|' . $modelName, $args, $comment);
|
||||||
}
|
}
|
||||||
} elseif (in_array($method, ['query', 'newQuery', 'newModelQuery'])) {
|
} elseif (in_array($method, ['query', 'newQuery', 'newModelQuery'])
|
||||||
$builder = $this->getClassNameInDestinationFile($model, get_class($model->newModelQuery()));
|
) {
|
||||||
|
if ($this->laravel['config']->get('ide-helper.write_query_methods', true)) {
|
||||||
|
$builder = $this->getClassNameInDestinationFile($model, get_class($model->newModelQuery()));
|
||||||
|
|
||||||
$this->setMethod(
|
$this->setMethod(
|
||||||
$method,
|
$method,
|
||||||
$builder . '<static>|' . $this->getClassNameInDestinationFile($model, get_class($model))
|
$builder . '<static>|' . $this->getClassNameInDestinationFile($model, get_class($model))
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->write_model_external_builder_methods) {
|
if ($this->write_model_external_builder_methods) {
|
||||||
$this->writeModelExternalBuilderMethods($model);
|
$this->writeModelExternalBuilderMethods($model);
|
||||||
@@ -719,14 +748,19 @@ class ModelsCommand extends Command
|
|||||||
$type = (string)$this->getReturnTypeFromDocBlock($reflection);
|
$type = (string)$this->getReturnTypeFromDocBlock($reflection);
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = new \SplFileObject($reflection->getFileName());
|
$fileName = $reflection->getFileName();
|
||||||
|
if (!isset($this->fileCache[$fileName])) {
|
||||||
|
$this->fileCache[$fileName] = new \SplFileObject($fileName);
|
||||||
|
}
|
||||||
|
$file = $this->fileCache[$fileName];
|
||||||
$file->seek($reflection->getStartLine() - 1);
|
$file->seek($reflection->getStartLine() - 1);
|
||||||
|
|
||||||
$code = '';
|
$lines = [];
|
||||||
while ($file->key() < $reflection->getEndLine()) {
|
while ($file->key() < $reflection->getEndLine()) {
|
||||||
$code .= $file->current();
|
$lines[] = $file->current();
|
||||||
$file->next();
|
$file->next();
|
||||||
}
|
}
|
||||||
|
$code = implode('', $lines);
|
||||||
$code = trim(preg_replace('/\s\s+/', '', $code));
|
$code = trim(preg_replace('/\s\s+/', '', $code));
|
||||||
$begin = strpos($code, 'function(');
|
$begin = strpos($code, 'function(');
|
||||||
$code = substr($code, $begin, strrpos($code, '}') - $begin + 1);
|
$code = substr($code, $begin, strrpos($code, '}') - $begin + 1);
|
||||||
@@ -887,7 +921,6 @@ class ModelsCommand extends Command
|
|||||||
|
|
||||||
if (in_array($relation, ['hasOne', 'hasOneThrough', 'morphOne'], true)) {
|
if (in_array($relation, ['hasOne', 'hasOneThrough', 'morphOne'], true)) {
|
||||||
$defaultProp = $reflectionObj->getProperty('withDefault');
|
$defaultProp = $reflectionObj->getProperty('withDefault');
|
||||||
$defaultProp->setAccessible(true);
|
|
||||||
|
|
||||||
return !$defaultProp->getValue($relationObj);
|
return !$defaultProp->getValue($relationObj);
|
||||||
}
|
}
|
||||||
@@ -897,7 +930,6 @@ class ModelsCommand extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
$fkProp = $reflectionObj->getProperty('foreignKey');
|
$fkProp = $reflectionObj->getProperty('foreignKey');
|
||||||
$fkProp->setAccessible(true);
|
|
||||||
|
|
||||||
$enforceNullableRelation = $this->laravel['config']->get('ide-helper.enforce_nullable_relationships', true);
|
$enforceNullableRelation = $this->laravel['config']->get('ide-helper.enforce_nullable_relationships', true);
|
||||||
|
|
||||||
@@ -911,9 +943,31 @@ class ModelsCommand extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->relatedModelUsesSoftDeletes($relationObj)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the related model uses the SoftDeletes trait
|
||||||
|
*
|
||||||
|
* @param Relation $relationObj
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function relatedModelUsesSoftDeletes(Relation $relationObj): bool
|
||||||
|
{
|
||||||
|
if (!$this->laravel['config']->get('ide-helper.soft_deletes_force_nullable', true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$relatedModel = $relationObj->getRelated();
|
||||||
|
|
||||||
|
return in_array('Illuminate\\Database\\Eloquent\\SoftDeletes', class_uses_recursive($relatedModel));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the morphTo relation is nullable
|
* Check if the morphTo relation is nullable
|
||||||
*
|
*
|
||||||
@@ -930,7 +984,6 @@ class ModelsCommand extends Command
|
|||||||
}
|
}
|
||||||
|
|
||||||
$fkProp = $reflectionObj->getProperty('foreignKey');
|
$fkProp = $reflectionObj->getProperty('foreignKey');
|
||||||
$fkProp->setAccessible(true);
|
|
||||||
|
|
||||||
foreach (Arr::wrap($fkProp->getValue($relationObj)) as $foreignKey) {
|
foreach (Arr::wrap($fkProp->getValue($relationObj)) as $foreignKey) {
|
||||||
if (isset($this->nullableColumns[$foreignKey])) {
|
if (isset($this->nullableColumns[$foreignKey])) {
|
||||||
@@ -961,7 +1014,7 @@ class ModelsCommand extends Command
|
|||||||
if ($type !== null) {
|
if ($type !== null) {
|
||||||
$newType = $this->getTypeOverride($type);
|
$newType = $this->getTypeOverride($type);
|
||||||
if ($nullable) {
|
if ($nullable) {
|
||||||
$newType .= '|null';
|
$newType = $this->wrapIntersectionType($newType) . '|null';
|
||||||
}
|
}
|
||||||
$this->properties[$name]['type'] = $newType;
|
$this->properties[$name]['type'] = $newType;
|
||||||
}
|
}
|
||||||
@@ -1112,6 +1165,7 @@ class ModelsCommand extends Command
|
|||||||
|
|
||||||
$serializer = new DocBlockSerializer();
|
$serializer = new DocBlockSerializer();
|
||||||
$docComment = $serializer->getDocComment($phpdoc);
|
$docComment = $serializer->getDocComment($phpdoc);
|
||||||
|
$mixinClassName = null;
|
||||||
|
|
||||||
if ($this->write_mixin) {
|
if ($this->write_mixin) {
|
||||||
$phpdocMixin = new DocBlock($reflection, new Context($namespace));
|
$phpdocMixin = new DocBlock($reflection, new Context($namespace));
|
||||||
@@ -1148,6 +1202,14 @@ class ModelsCommand extends Command
|
|||||||
$replace = "{$modelDocComment}\n";
|
$replace = "{$modelDocComment}\n";
|
||||||
$pos = strpos($contents, "final class {$classname}") ?: strpos($contents, "class {$classname}");
|
$pos = strpos($contents, "final class {$classname}") ?: strpos($contents, "class {$classname}");
|
||||||
if ($pos !== false) {
|
if ($pos !== false) {
|
||||||
|
// If PHP 8 attributes (e.g. #[ObservedBy(...)]) precede the class
|
||||||
|
// declaration, insert the docblock before the first attribute so that
|
||||||
|
// the resulting order is: docblock → attributes → class.
|
||||||
|
$before = substr($contents, 0, $pos);
|
||||||
|
if (preg_match('/((?:#\[.+?\]\s*)+)$/s', $before, $matches)) {
|
||||||
|
$pos -= strlen($matches[1]);
|
||||||
|
$replace = "{$modelDocComment}\n";
|
||||||
|
}
|
||||||
$contents = substr_replace($contents, $replace, $pos, 0);
|
$contents = substr_replace($contents, $replace, $pos, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1253,13 +1315,18 @@ class ModelsCommand extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ?array $cachedRelationTypes = null;
|
||||||
|
protected ?array $cachedRelationReturnTypes = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the available relation types
|
* Returns the available relation types
|
||||||
*/
|
*/
|
||||||
protected function getRelationTypes(): array
|
protected function getRelationTypes(): array
|
||||||
{
|
{
|
||||||
$configuredRelations = $this->laravel['config']->get('ide-helper.additional_relation_types', []);
|
return $this->cachedRelationTypes ??= array_merge(
|
||||||
return array_merge(self::RELATION_TYPES, $configuredRelations);
|
self::RELATION_TYPES,
|
||||||
|
$this->laravel['config']->get('ide-helper.additional_relation_types', [])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1267,7 +1334,7 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected function getRelationReturnTypes(): array
|
protected function getRelationReturnTypes(): array
|
||||||
{
|
{
|
||||||
return $this->laravel['config']->get('ide-helper.additional_relation_return_types', []);
|
return $this->cachedRelationReturnTypes ??= $this->laravel['config']->get('ide-helper.additional_relation_return_types', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1283,9 +1350,6 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected function getAttributeTypes(Model $model, \ReflectionMethod $reflectionMethod): Collection
|
protected function getAttributeTypes(Model $model, \ReflectionMethod $reflectionMethod): Collection
|
||||||
{
|
{
|
||||||
// Private/protected ReflectionMethods require setAccessible prior to PHP 8.1
|
|
||||||
$reflectionMethod->setAccessible(true);
|
|
||||||
|
|
||||||
/** @var Attribute $attribute */
|
/** @var Attribute $attribute */
|
||||||
$attribute = $reflectionMethod->invoke($model);
|
$attribute = $reflectionMethod->invoke($model);
|
||||||
|
|
||||||
@@ -1345,11 +1409,7 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected function getCommentFromDocBlock(\ReflectionMethod $reflection)
|
protected function getCommentFromDocBlock(\ReflectionMethod $reflection)
|
||||||
{
|
{
|
||||||
$phpDocContext = (new ContextFactory())->createFromReflector($reflection);
|
$context = $this->getDocBlockContext($reflection);
|
||||||
$context = new Context(
|
|
||||||
$phpDocContext->getNamespace(),
|
|
||||||
$phpDocContext->getNamespaceAliases()
|
|
||||||
);
|
|
||||||
$comment = '';
|
$comment = '';
|
||||||
$phpdoc = new DocBlock($reflection, $context);
|
$phpdoc = new DocBlock($reflection, $context);
|
||||||
|
|
||||||
@@ -1370,11 +1430,7 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected function getReturnTypeFromDocBlock(\ReflectionMethod $reflection, ?\Reflector $reflectorForContext = null)
|
protected function getReturnTypeFromDocBlock(\ReflectionMethod $reflection, ?\Reflector $reflectorForContext = null)
|
||||||
{
|
{
|
||||||
$phpDocContext = (new ContextFactory())->createFromReflector($reflectorForContext ?? $reflection);
|
$context = $this->getDocBlockContext($reflectorForContext ?? $reflection);
|
||||||
$context = new Context(
|
|
||||||
$phpDocContext->getNamespace(),
|
|
||||||
$phpDocContext->getNamespaceAliases()
|
|
||||||
);
|
|
||||||
$type = null;
|
$type = null;
|
||||||
$phpdoc = new DocBlock($reflection, $context);
|
$phpdoc = new DocBlock($reflection, $context);
|
||||||
|
|
||||||
@@ -1392,6 +1448,31 @@ class ModelsCommand extends Command
|
|||||||
return $type;
|
return $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getDocBlockContext(\Reflector $reflector): Context
|
||||||
|
{
|
||||||
|
if ($reflector instanceof \ReflectionMethod) {
|
||||||
|
$key = $reflector->getDeclaringClass()->getName();
|
||||||
|
} elseif ($reflector instanceof ReflectionClass) {
|
||||||
|
$key = $reflector->getName();
|
||||||
|
} else {
|
||||||
|
$phpDocContext = (new ContextFactory())->createFromReflector($reflector);
|
||||||
|
return new Context(
|
||||||
|
$phpDocContext->getNamespace(),
|
||||||
|
$phpDocContext->getNamespaceAliases()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->contextCache[$key])) {
|
||||||
|
$phpDocContext = (new ContextFactory())->createFromReflector($reflector);
|
||||||
|
$this->contextCache[$key] = new Context(
|
||||||
|
$phpDocContext->getNamespace(),
|
||||||
|
$phpDocContext->getNamespaceAliases()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->contextCache[$key];
|
||||||
|
}
|
||||||
|
|
||||||
protected function getReturnTypeFromReflection(\ReflectionMethod $reflection): ?string
|
protected function getReturnTypeFromReflection(\ReflectionMethod $reflection): ?string
|
||||||
{
|
{
|
||||||
$returnType = $reflection->getReturnType();
|
$returnType = $reflection->getReturnType();
|
||||||
@@ -1597,9 +1678,10 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected function getUsedClassNames(ReflectionClass $reflection): array
|
protected function getUsedClassNames(ReflectionClass $reflection): array
|
||||||
{
|
{
|
||||||
|
$context = $this->getDocBlockContext($reflection);
|
||||||
$namespaceAliases = array_flip(array_map(function ($alias) {
|
$namespaceAliases = array_flip(array_map(function ($alias) {
|
||||||
return ltrim($alias, '\\');
|
return ltrim($alias, '\\');
|
||||||
}, (new ContextFactory())->createFromReflector($reflection)->getNamespaceAliases()));
|
}, $context->getNamespaceAliases()));
|
||||||
$namespaceAliases[$reflection->getName()] = $reflection->getShortName();
|
$namespaceAliases[$reflection->getName()] = $reflection->getShortName();
|
||||||
|
|
||||||
return $namespaceAliases;
|
return $namespaceAliases;
|
||||||
@@ -1643,7 +1725,8 @@ class ModelsCommand extends Command
|
|||||||
$type = implode('|', $types);
|
$type = implode('|', $types);
|
||||||
|
|
||||||
if ($paramType->allowsNull()) {
|
if ($paramType->allowsNull()) {
|
||||||
if (count($types) == 1) {
|
// Use ?Type syntax only for single named types, not for intersection types
|
||||||
|
if (count($types) == 1 && !str_starts_with($type, '(')) {
|
||||||
$type = '?' . $type;
|
$type = '?' . $type;
|
||||||
} else {
|
} else {
|
||||||
$type .= '|null';
|
$type .= '|null';
|
||||||
@@ -1661,7 +1744,7 @@ class ModelsCommand extends Command
|
|||||||
|
|
||||||
preg_match(
|
preg_match(
|
||||||
'/@param ((?:(?:[\w?|\\\\<>])+(?:\[])?)+)/',
|
'/@param ((?:(?:[\w?|\\\\<>])+(?:\[])?)+)/',
|
||||||
$docComment ?? '',
|
$docComment,
|
||||||
$matches
|
$matches
|
||||||
);
|
);
|
||||||
$type = $matches[1] ?? '';
|
$type = $matches[1] ?? '';
|
||||||
@@ -1716,24 +1799,53 @@ class ModelsCommand extends Command
|
|||||||
return $type;
|
return $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function extractReflectionTypes(ReflectionType $reflection_type)
|
protected function extractReflectionTypes(ReflectionType $reflection_type): array
|
||||||
{
|
{
|
||||||
if ($reflection_type instanceof ReflectionNamedType) {
|
if ($reflection_type instanceof ReflectionNamedType) {
|
||||||
$types[] = $this->getReflectionNamedType($reflection_type);
|
return [$this->getReflectionNamedType($reflection_type)];
|
||||||
} else {
|
}
|
||||||
$types = [];
|
|
||||||
foreach ($reflection_type->getTypes() as $named_type) {
|
if ($reflection_type instanceof \ReflectionIntersectionType) {
|
||||||
if ($named_type->getName() === 'null') {
|
return [$this->formatIntersectionType($reflection_type)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($reflection_type instanceof \ReflectionUnionType) {
|
||||||
|
return $this->extractUnionTypes($reflection_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown type - return empty array as fallback
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function extractUnionTypes(\ReflectionUnionType $union_type): array
|
||||||
|
{
|
||||||
|
$types = [];
|
||||||
|
|
||||||
|
foreach ($union_type->getTypes() as $inner_type) {
|
||||||
|
if ($inner_type instanceof ReflectionNamedType) {
|
||||||
|
if ($inner_type->getName() === 'null') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
$types[] = $this->getReflectionNamedType($inner_type);
|
||||||
$types[] = $this->getReflectionNamedType($named_type);
|
} elseif ($inner_type instanceof \ReflectionIntersectionType) {
|
||||||
|
$types[] = $this->formatIntersectionType($inner_type);
|
||||||
}
|
}
|
||||||
|
// ReflectionUnionType cannot be nested per PHP's DNF rules
|
||||||
}
|
}
|
||||||
|
|
||||||
return $types;
|
return $types;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formatIntersectionType(\ReflectionIntersectionType $intersection_type): string
|
||||||
|
{
|
||||||
|
$parts = [];
|
||||||
|
foreach ($intersection_type->getTypes() as $type) {
|
||||||
|
$parts[] = $this->getReflectionNamedType($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '(' . implode('&', $parts) . ')';
|
||||||
|
}
|
||||||
|
|
||||||
protected function getReflectionNamedType(ReflectionNamedType $paramType): string
|
protected function getReflectionNamedType(ReflectionNamedType $paramType): string
|
||||||
{
|
{
|
||||||
$parameterName = $paramType->getName();
|
$parameterName = $paramType->getName();
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Barryvdh\LaravelIdeHelper;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Illuminate\Database\Eloquent\Factory;
|
|
||||||
use ReflectionClass;
|
|
||||||
|
|
||||||
class Factories
|
|
||||||
{
|
|
||||||
public static function all()
|
|
||||||
{
|
|
||||||
$factories = [];
|
|
||||||
|
|
||||||
if (static::isLaravelSevenOrLower()) {
|
|
||||||
$factory = app(Factory::class);
|
|
||||||
|
|
||||||
$definitions = (new ReflectionClass(Factory::class))->getProperty('definitions');
|
|
||||||
$definitions->setAccessible(true);
|
|
||||||
|
|
||||||
foreach ($definitions->getValue($factory) as $factory_target => $config) {
|
|
||||||
try {
|
|
||||||
$factories[] = new ReflectionClass($factory_target);
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $factories;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static function isLaravelSevenOrLower()
|
|
||||||
{
|
|
||||||
return class_exists('Illuminate\Database\Eloquent\Factory');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-2
@@ -74,7 +74,7 @@ class Generator
|
|||||||
/**
|
/**
|
||||||
* Generate the helper file contents;
|
* Generate the helper file contents;
|
||||||
*
|
*
|
||||||
* @return string;
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function generate()
|
public function generate()
|
||||||
{
|
{
|
||||||
@@ -85,7 +85,6 @@ class Generator
|
|||||||
->with('real_time_facades', $this->getRealTimeFacades())
|
->with('real_time_facades', $this->getRealTimeFacades())
|
||||||
->with('helpers', $this->detectHelpers())
|
->with('helpers', $this->detectHelpers())
|
||||||
->with('include_fluent', $this->config->get('ide-helper.include_fluent', true))
|
->with('include_fluent', $this->config->get('ide-helper.include_fluent', true))
|
||||||
->with('factories', $this->config->get('ide-helper.include_factory_builders') ? Factories::all() : [])
|
|
||||||
->render();
|
->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+39
-10
@@ -15,7 +15,6 @@ class Macro extends Method
|
|||||||
* Macro constructor.
|
* Macro constructor.
|
||||||
*
|
*
|
||||||
* @param \ReflectionFunctionAbstract $method
|
* @param \ReflectionFunctionAbstract $method
|
||||||
* @param string $alias
|
|
||||||
* @param \ReflectionClass $class
|
* @param \ReflectionClass $class
|
||||||
* @param null $methodName
|
* @param null $methodName
|
||||||
* @param array $interfaces
|
* @param array $interfaces
|
||||||
@@ -24,14 +23,13 @@ class Macro extends Method
|
|||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
$method,
|
$method,
|
||||||
$alias,
|
|
||||||
$class,
|
$class,
|
||||||
$methodName = null,
|
$methodName = null,
|
||||||
$interfaces = [],
|
$interfaces = [],
|
||||||
$classAliases = [],
|
$classAliases = [],
|
||||||
$returnTypeNormalizers = []
|
$returnTypeNormalizers = []
|
||||||
) {
|
) {
|
||||||
parent::__construct($method, $alias, $class, $methodName, $interfaces, $classAliases, $returnTypeNormalizers);
|
parent::__construct($method, $class, $methodName, $interfaces, $classAliases, $returnTypeNormalizers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function setDefaultReturnTypes(array $map = [])
|
public static function setDefaultReturnTypes(array $map = [])
|
||||||
@@ -75,8 +73,8 @@ class Macro extends Method
|
|||||||
|
|
||||||
$type = $this->concatReflectionTypes($return);
|
$type = $this->concatReflectionTypes($return);
|
||||||
|
|
||||||
/** @psalm-suppress UndefinedClass */
|
|
||||||
if (!$return instanceof \ReflectionUnionType) {
|
if (!$return instanceof \ReflectionUnionType) {
|
||||||
|
/** @phpstan-ignore method.notFound */
|
||||||
$type .= $this->root === "\\{$builder}" && $return->getName() === $builder ? '|static' : '';
|
$type .= $this->root === "\\{$builder}" && $return->getName() === $builder ? '|static' : '';
|
||||||
$type .= $return->allowsNull() ? '|null' : '';
|
$type .= $return->allowsNull() ? '|null' : '';
|
||||||
}
|
}
|
||||||
@@ -93,17 +91,48 @@ class Macro extends Method
|
|||||||
|
|
||||||
protected function concatReflectionTypes(?\ReflectionType $type): string
|
protected function concatReflectionTypes(?\ReflectionType $type): string
|
||||||
{
|
{
|
||||||
/** @psalm-suppress UndefinedClass */
|
if ($type instanceof \ReflectionNamedType) {
|
||||||
$returnTypes = $type instanceof \ReflectionUnionType
|
return $type->getName();
|
||||||
? $type->getTypes()
|
}
|
||||||
: [$type];
|
|
||||||
|
|
||||||
return Collection::make($returnTypes)
|
if ($type instanceof \ReflectionIntersectionType) {
|
||||||
|
return $this->formatIntersectionType($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($type instanceof \ReflectionUnionType) {
|
||||||
|
return $this->formatUnionType($type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown or null type
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function formatUnionType(\ReflectionUnionType $type): string
|
||||||
|
{
|
||||||
|
return Collection::make($type->getTypes())
|
||||||
|
->map(function (\ReflectionType $inner) {
|
||||||
|
if ($inner instanceof \ReflectionNamedType) {
|
||||||
|
return $inner->getName();
|
||||||
|
}
|
||||||
|
if ($inner instanceof \ReflectionIntersectionType) {
|
||||||
|
return $this->formatIntersectionType($inner);
|
||||||
|
}
|
||||||
|
// ReflectionUnionType cannot be nested per PHP's DNF rules
|
||||||
|
return null;
|
||||||
|
})
|
||||||
->filter()
|
->filter()
|
||||||
->map->getName()
|
|
||||||
->implode('|');
|
->implode('|');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function formatIntersectionType(\ReflectionIntersectionType $type): string
|
||||||
|
{
|
||||||
|
$parts = Collection::make($type->getTypes())
|
||||||
|
->map(fn (\ReflectionNamedType $t) => $t->getName())
|
||||||
|
->toArray();
|
||||||
|
|
||||||
|
return '(' . implode('&', $parts) . ')';
|
||||||
|
}
|
||||||
|
|
||||||
protected function addLocationToPhpDoc()
|
protected function addLocationToPhpDoc()
|
||||||
{
|
{
|
||||||
if ($this->method->name === '__invoke') {
|
if ($this->method->name === '__invoke') {
|
||||||
|
|||||||
+3
-4
@@ -44,7 +44,6 @@ class Method
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param \ReflectionMethod|\ReflectionFunctionAbstract $method
|
* @param \ReflectionMethod|\ReflectionFunctionAbstract $method
|
||||||
* @param string $alias
|
|
||||||
* @param \ReflectionClass $class
|
* @param \ReflectionClass $class
|
||||||
* @param string|null $methodName
|
* @param string|null $methodName
|
||||||
* @param array $interfaces
|
* @param array $interfaces
|
||||||
@@ -52,7 +51,7 @@ class Method
|
|||||||
* @param array $returnTypeNormalizers
|
* @param array $returnTypeNormalizers
|
||||||
* @param string[] $templateNames
|
* @param string[] $templateNames
|
||||||
*/
|
*/
|
||||||
public function __construct($method, $alias, $class, $methodName = null, $interfaces = [], array $classAliases = [], array $returnTypeNormalizers = [], array $templateNames = [])
|
public function __construct($method, $class, $methodName = null, $interfaces = [], array $classAliases = [], array $returnTypeNormalizers = [], array $templateNames = [])
|
||||||
{
|
{
|
||||||
$this->method = $method;
|
$this->method = $method;
|
||||||
$this->interfaces = $interfaces;
|
$this->interfaces = $interfaces;
|
||||||
@@ -178,7 +177,7 @@ class Method
|
|||||||
/**
|
/**
|
||||||
* Get the parameters for this method
|
* Get the parameters for this method
|
||||||
*
|
*
|
||||||
* @param bool $implode Wether to implode the array or not
|
* @param bool $implode Whether to implode the array or not
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getParams($implode = true)
|
public function getParams($implode = true)
|
||||||
@@ -208,7 +207,7 @@ class Method
|
|||||||
/**
|
/**
|
||||||
* Get the parameters for this method including default values
|
* Get the parameters for this method including default values
|
||||||
*
|
*
|
||||||
* @param bool $implode Wether to implode the array or not
|
* @param bool $implode Whether to implode the array or not
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getParamsWithDefault($implode = true)
|
public function getParamsWithDefault($implode = true)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use Barryvdh\LaravelIdeHelper\Macro;
|
|||||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||||
use Illuminate\Database\Query\Builder;
|
use Illuminate\Database\Query\Builder;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
use Illuminate\Support\Facades\Facade;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
@@ -66,6 +67,22 @@ class AliasTest extends TestCase
|
|||||||
$this->assertNotNull($this->getAliasMacro($alias, EloquentBuilder::class, $macro));
|
$this->assertNotNull($this->getAliasMacro($alias, EloquentBuilder::class, $macro));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers ::detectFake
|
||||||
|
*/
|
||||||
|
public function testNoExceptionOnRequiredFakeParameters(): void
|
||||||
|
{
|
||||||
|
// Mock
|
||||||
|
$alias = new AliasMock();
|
||||||
|
|
||||||
|
// Prepare
|
||||||
|
$alias->setFacade(MockFacade::class);
|
||||||
|
$this->expectNotToPerformAssertions();
|
||||||
|
|
||||||
|
// Test
|
||||||
|
$alias->detectFake();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @covers ::detectTemplateNames
|
* @covers ::detectTemplateNames
|
||||||
*/
|
*/
|
||||||
@@ -118,4 +135,26 @@ class AliasMock extends Alias
|
|||||||
{
|
{
|
||||||
parent::detectMethods();
|
parent::detectMethods();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function detectFake()
|
||||||
|
{
|
||||||
|
parent::detectFake();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFacade(string $facade)
|
||||||
|
{
|
||||||
|
$this->facade = $facade;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockFacade extends Facade
|
||||||
|
{
|
||||||
|
protected static function getFacadeAccessor()
|
||||||
|
{
|
||||||
|
return 'Illuminate\Foundation\Exceptions\Handler';
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fake(string $test1, $test2 = null)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\DnfTypes\Models;
|
||||||
|
|
||||||
|
use ArrayAccess;
|
||||||
|
use Countable;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Iterator;
|
||||||
|
use Stringable;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test model covering all DNF type scenarios from PHP RFC.
|
||||||
|
*
|
||||||
|
* @see https://wiki.php.net/rfc/dnf_types
|
||||||
|
*/
|
||||||
|
class DnfTypeModel extends Model
|
||||||
|
{
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 1: (A&B)|null - Intersection with null
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic DNF: intersection OR null.
|
||||||
|
*/
|
||||||
|
public function getBasicDnfAttribute(): (Countable&Iterator)|null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 2: (A&B)|D - Intersection OR single type (no null)
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intersection OR single class type.
|
||||||
|
*/
|
||||||
|
public function getIntersectionOrClassAttribute(): (Countable&Iterator)|\stdClass
|
||||||
|
{
|
||||||
|
return new \stdClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 3: C|(X&D)|null - Single type OR intersection OR null
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single type OR intersection OR null.
|
||||||
|
*/
|
||||||
|
public function getSingleOrIntersectionOrNullAttribute(): \stdClass|(Countable&Iterator)|null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 4: (A&B&D)|int|null - Triple intersection OR primitive OR null
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triple intersection OR primitive OR null.
|
||||||
|
*/
|
||||||
|
public function getTripleIntersectionAttribute(): (Countable&Iterator&Traversable)|int|null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 5: (A&B)|(C&D)|null - Multiple intersection segments
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiple intersection segments OR null.
|
||||||
|
*/
|
||||||
|
public function getMultipleIntersectionsAttribute(): (Countable&Iterator)|(ArrayAccess&Stringable)|null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 6: (A&B)|(C&D)|(E&F) - Multiple intersections without null
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiple intersection segments without null.
|
||||||
|
*/
|
||||||
|
public function getMultipleIntersectionsNoNullAttribute(): (Countable&Iterator)|(ArrayAccess&Stringable)|(Traversable&Countable)
|
||||||
|
{
|
||||||
|
return new class () implements Countable, Iterator {
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function current(): mixed
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function key(): mixed
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewind(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Pure intersection type (A&B) - No union, just intersection
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pure intersection type without union.
|
||||||
|
*/
|
||||||
|
public function getPureIntersectionAttribute(): Countable&Iterator
|
||||||
|
{
|
||||||
|
return new class () implements Countable, Iterator {
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function current(): mixed
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function key(): mixed
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewind(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Parameter context: DNF types in method parameters
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope with DNF parameter: (A&B)|null.
|
||||||
|
*/
|
||||||
|
public function scopeWithBasicDnfParam(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
(Countable&Iterator)|null $param
|
||||||
|
): \Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope with complex DNF parameter: C|(A&B)|null.
|
||||||
|
*/
|
||||||
|
public function scopeWithComplexDnfParam(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
\stdClass|(Countable&Iterator)|null $param
|
||||||
|
): \Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope with multiple intersection parameters.
|
||||||
|
*/
|
||||||
|
public function scopeWithMultipleIntersectionParam(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
(Countable&Iterator)|(ArrayAccess&Stringable) $param
|
||||||
|
): \Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope with intersection OR primitive parameter.
|
||||||
|
*/
|
||||||
|
public function scopeWithIntersectionOrPrimitive(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
(Countable&Iterator)|int $param
|
||||||
|
): \Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Mixed: DNF in both parameter and return type
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DNF in both parameter and return type.
|
||||||
|
*/
|
||||||
|
public function scopeWithDnfParamAndReturn(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
(Countable&Iterator)|null $param
|
||||||
|
): (Countable&Iterator)|\Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\DnfTypes;
|
||||||
|
|
||||||
|
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
|
||||||
|
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
|
||||||
|
|
||||||
|
class Test extends AbstractModelsCommand
|
||||||
|
{
|
||||||
|
public function test(): void
|
||||||
|
{
|
||||||
|
$command = $this->app->make(ModelsCommand::class);
|
||||||
|
|
||||||
|
$tester = $this->runCommand($command, [
|
||||||
|
'--write' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(0, $tester->getStatusCode());
|
||||||
|
$this->assertStringContainsString('Written new phpDocBlock to', $tester->getDisplay());
|
||||||
|
$this->assertMatchesMockedSnapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,234 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\DnfTypes\Models;
|
||||||
|
|
||||||
|
use ArrayAccess;
|
||||||
|
use Countable;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Iterator;
|
||||||
|
use Stringable;
|
||||||
|
use Traversable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test model covering all DNF type scenarios from PHP RFC.
|
||||||
|
*
|
||||||
|
* @see https://wiki.php.net/rfc/dnf_types
|
||||||
|
* @property-read (\Countable&\Iterator)|null $basic_dnf
|
||||||
|
* @property-read (\Countable&\Iterator)|\stdClass $intersection_or_class
|
||||||
|
* @property-read (\Countable&\Iterator)|(\ArrayAccess&\Stringable)|null $multiple_intersections
|
||||||
|
* @property-read (\Countable&\Iterator)|(\ArrayAccess&\Stringable)|(\Traversable&\Countable) $multiple_intersections_no_null
|
||||||
|
* @property-read (\Countable&\Iterator) $pure_intersection
|
||||||
|
* @property-read \stdClass|(\Countable&\Iterator)|null $single_or_intersection_or_null
|
||||||
|
* @property-read (\Countable&\Iterator&\Traversable)|int|null $triple_intersection
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DnfTypeModel newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DnfTypeModel newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DnfTypeModel query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DnfTypeModel withBasicDnfParam((\Countable&\Iterator)|null $param)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DnfTypeModel withComplexDnfParam(\stdClass|(\Countable&\Iterator)|null $param)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DnfTypeModel withDnfParamAndReturn((\Countable&\Iterator)|null $param)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DnfTypeModel withIntersectionOrPrimitive((\Countable&\Iterator)|int $param)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|DnfTypeModel withMultipleIntersectionParam((\Countable&\Iterator)|(\ArrayAccess&\Stringable) $param)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class DnfTypeModel extends Model
|
||||||
|
{
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 1: (A&B)|null - Intersection with null
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic DNF: intersection OR null.
|
||||||
|
*/
|
||||||
|
public function getBasicDnfAttribute(): (Countable&Iterator)|null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 2: (A&B)|D - Intersection OR single type (no null)
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intersection OR single class type.
|
||||||
|
*/
|
||||||
|
public function getIntersectionOrClassAttribute(): (Countable&Iterator)|\stdClass
|
||||||
|
{
|
||||||
|
return new \stdClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 3: C|(X&D)|null - Single type OR intersection OR null
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single type OR intersection OR null.
|
||||||
|
*/
|
||||||
|
public function getSingleOrIntersectionOrNullAttribute(): \stdClass|(Countable&Iterator)|null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 4: (A&B&D)|int|null - Triple intersection OR primitive OR null
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triple intersection OR primitive OR null.
|
||||||
|
*/
|
||||||
|
public function getTripleIntersectionAttribute(): (Countable&Iterator&Traversable)|int|null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 5: (A&B)|(C&D)|null - Multiple intersection segments
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiple intersection segments OR null.
|
||||||
|
*/
|
||||||
|
public function getMultipleIntersectionsAttribute(): (Countable&Iterator)|(ArrayAccess&Stringable)|null
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// RFC Example 6: (A&B)|(C&D)|(E&F) - Multiple intersections without null
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiple intersection segments without null.
|
||||||
|
*/
|
||||||
|
public function getMultipleIntersectionsNoNullAttribute(): (Countable&Iterator)|(ArrayAccess&Stringable)|(Traversable&Countable)
|
||||||
|
{
|
||||||
|
return new class () implements Countable, Iterator {
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function current(): mixed
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function key(): mixed
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewind(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Pure intersection type (A&B) - No union, just intersection
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pure intersection type without union.
|
||||||
|
*/
|
||||||
|
public function getPureIntersectionAttribute(): Countable&Iterator
|
||||||
|
{
|
||||||
|
return new class () implements Countable, Iterator {
|
||||||
|
public function count(): int
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function current(): mixed
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function key(): mixed
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function next(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function rewind(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function valid(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Parameter context: DNF types in method parameters
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope with DNF parameter: (A&B)|null.
|
||||||
|
*/
|
||||||
|
public function scopeWithBasicDnfParam(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
(Countable&Iterator)|null $param
|
||||||
|
): \Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope with complex DNF parameter: C|(A&B)|null.
|
||||||
|
*/
|
||||||
|
public function scopeWithComplexDnfParam(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
\stdClass|(Countable&Iterator)|null $param
|
||||||
|
): \Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope with multiple intersection parameters.
|
||||||
|
*/
|
||||||
|
public function scopeWithMultipleIntersectionParam(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
(Countable&Iterator)|(ArrayAccess&Stringable) $param
|
||||||
|
): \Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope with intersection OR primitive parameter.
|
||||||
|
*/
|
||||||
|
public function scopeWithIntersectionOrPrimitive(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
(Countable&Iterator)|int $param
|
||||||
|
): \Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Mixed: DNF in both parameter and return type
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DNF in both parameter and return type.
|
||||||
|
*/
|
||||||
|
public function scopeWithDnfParamAndReturn(
|
||||||
|
\Illuminate\Database\Query\Builder $query,
|
||||||
|
(Countable&Iterator)|null $param
|
||||||
|
): (Countable&Iterator)|\Illuminate\Database\Query\Builder {
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-2
@@ -48,8 +48,8 @@ namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\DoesNotGenerateP
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
+2
-2
@@ -44,8 +44,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
+2
-2
@@ -42,8 +42,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
* @property float $floatNotNullable
|
* @property float $floatNotNullable
|
||||||
* @property float|null $doubleNullable
|
* @property float|null $doubleNullable
|
||||||
* @property float $doubleNotNullable
|
* @property float $doubleNotNullable
|
||||||
* @property string|null $decimalNullable
|
* @property numeric|null $decimalNullable
|
||||||
* @property string $decimalNotNullable
|
* @property numeric $decimalNotNullable
|
||||||
* @property int|null $booleanNullable
|
* @property int|null $booleanNullable
|
||||||
* @property int $booleanNotNullable
|
* @property int $booleanNotNullable
|
||||||
* @property string|null $enumNullable
|
* @property string|null $enumNullable
|
||||||
|
|||||||
+2
-2
@@ -42,8 +42,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
+2
-2
@@ -48,8 +48,8 @@ namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWi
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
+2
-2
@@ -43,8 +43,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
+2
-2
@@ -44,8 +44,8 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ use Illuminate\Support\Carbon;
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
+2
-2
@@ -48,8 +48,8 @@ namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWi
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWi
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ use Illuminate\Database\Eloquent\Model;
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\MorphToIntersection\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
abstract class BaseModel extends Model
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\MorphToIntersection\Models;
|
||||||
|
|
||||||
|
interface CanBeAssigned
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\MorphToIntersection\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
|
|
||||||
|
class MorphToIntersection extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'morphs';
|
||||||
|
|
||||||
|
/** @return MorphTo<(BaseModel&CanBeAssigned), $this> */
|
||||||
|
public function assigneeWithParens(): MorphTo
|
||||||
|
{
|
||||||
|
return $this->morphTo(type: 'nullable_relation_morph_to_type', id: 'nullable_relation_morph_to_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return MorphTo<BaseModel&CanBeAssigned, $this> */
|
||||||
|
public function assigneeWithoutParens(): MorphTo
|
||||||
|
{
|
||||||
|
return $this->morphTo(type: 'nullable_relation_morph_to_type', id: 'nullable_relation_morph_to_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return MorphTo<(BaseModel&CanBeAssigned), $this> */
|
||||||
|
public function nonNullableAssignee(): MorphTo
|
||||||
|
{
|
||||||
|
return $this->morphTo(type: 'relation_morph_to_type', id: 'relation_morph_to_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\MorphToIntersection;
|
||||||
|
|
||||||
|
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
|
||||||
|
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
|
||||||
|
|
||||||
|
class Test extends AbstractModelsCommand
|
||||||
|
{
|
||||||
|
public function test(): void
|
||||||
|
{
|
||||||
|
$command = $this->app->make(ModelsCommand::class);
|
||||||
|
|
||||||
|
$tester = $this->runCommand($command, [
|
||||||
|
'--write' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(0, $tester->getStatusCode());
|
||||||
|
$this->assertStringContainsString('Written new phpDocBlock to', $tester->getDisplay());
|
||||||
|
$this->assertMatchesMockedSnapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\MorphToIntersection\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property string $relation_morph_to_type
|
||||||
|
* @property int $relation_morph_to_id
|
||||||
|
* @property string|null $nullable_relation_morph_to_type
|
||||||
|
* @property int|null $nullable_relation_morph_to_id
|
||||||
|
* @property-read (BaseModel&CanBeAssigned)|null $assigneeWithParens
|
||||||
|
* @property-read (BaseModel&CanBeAssigned)|null $assigneeWithoutParens
|
||||||
|
* @property-read (BaseModel&CanBeAssigned) $nonNullableAssignee
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MorphToIntersection newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MorphToIntersection newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MorphToIntersection query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MorphToIntersection whereNullableRelationMorphToId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MorphToIntersection whereNullableRelationMorphToType($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MorphToIntersection whereRelationMorphToId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MorphToIntersection whereRelationMorphToType($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class MorphToIntersection extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'morphs';
|
||||||
|
|
||||||
|
/** @return MorphTo<(BaseModel&CanBeAssigned), $this> */
|
||||||
|
public function assigneeWithParens(): MorphTo
|
||||||
|
{
|
||||||
|
return $this->morphTo(type: 'nullable_relation_morph_to_type', id: 'nullable_relation_morph_to_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return MorphTo<BaseModel&CanBeAssigned, $this> */
|
||||||
|
public function assigneeWithoutParens(): MorphTo
|
||||||
|
{
|
||||||
|
return $this->morphTo(type: 'nullable_relation_morph_to_type', id: 'nullable_relation_morph_to_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return MorphTo<(BaseModel&CanBeAssigned), $this> */
|
||||||
|
public function nonNullableAssignee(): MorphTo
|
||||||
|
{
|
||||||
|
return $this->morphTo(type: 'relation_morph_to_type', id: 'relation_morph_to_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesBeforeClass\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
// Tests: final class + attribute with nested array argument (e.g. ObservedBy([...]))
|
||||||
|
#[ObservedByStub([StubObserver::class])]
|
||||||
|
final class FinalWithNested extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'simples';
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesBeforeClass\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
// Tests: multiple consecutive PHP 8 attributes before the class declaration
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
#[SecondAttribute]
|
||||||
|
class MultipleAttributes extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'simples';
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesBeforeClass\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class Simple extends Model
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesBeforeClass;
|
||||||
|
|
||||||
|
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
|
||||||
|
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
|
||||||
|
|
||||||
|
class Test extends AbstractModelsCommand
|
||||||
|
{
|
||||||
|
public function test(): void
|
||||||
|
{
|
||||||
|
$command = $this->app->make(ModelsCommand::class);
|
||||||
|
|
||||||
|
$tester = $this->runCommand($command, [
|
||||||
|
'--write' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(0, $tester->getStatusCode());
|
||||||
|
$this->assertStringContainsString('Written new phpDocBlock to', $tester->getDisplay());
|
||||||
|
$this->assertMatchesMockedSnapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesBeforeClass\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
// Tests: final class + attribute with nested array argument (e.g. ObservedBy([...]))
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|FinalWithNested newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|FinalWithNested newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|FinalWithNested query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|FinalWithNested whereId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[ObservedByStub([StubObserver::class])]
|
||||||
|
final class FinalWithNested extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'simples';
|
||||||
|
}
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesBeforeClass\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
// Tests: multiple consecutive PHP 8 attributes before the class declaration
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MultipleAttributes newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MultipleAttributes newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MultipleAttributes query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|MultipleAttributes whereId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
#[SecondAttribute]
|
||||||
|
class MultipleAttributes extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'simples';
|
||||||
|
}
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesBeforeClass\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Simple newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Simple newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Simple query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Simple whereId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[\AllowDynamicProperties]
|
||||||
|
class Simple extends Model
|
||||||
|
{
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesClosureInAttribute\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
// Tests: closure expression inside an attribute argument (PHP 8.5+)
|
||||||
|
#[SomeClosureAttr(fn () => true)]
|
||||||
|
class ClosureInAttribute extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'simples';
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesClosureInAttribute;
|
||||||
|
|
||||||
|
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
|
||||||
|
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
|
||||||
|
|
||||||
|
class Test extends AbstractModelsCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @requires PHP 8.5
|
||||||
|
*/
|
||||||
|
public function test(): void
|
||||||
|
{
|
||||||
|
$command = $this->app->make(ModelsCommand::class);
|
||||||
|
|
||||||
|
$tester = $this->runCommand($command, [
|
||||||
|
'--write' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(0, $tester->getStatusCode());
|
||||||
|
$this->assertStringContainsString('Written new phpDocBlock to', $tester->getDisplay());
|
||||||
|
$this->assertMatchesMockedSnapshot();
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\PhpAttributesClosureInAttribute\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
// Tests: closure expression inside an attribute argument (PHP 8.5+)
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ClosureInAttribute newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ClosureInAttribute newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ClosureInAttribute query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ClosureInAttribute whereId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
#[SomeClosureAttr(fn() => true)]
|
||||||
|
class ClosureInAttribute extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'simples';
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\QueryMethods\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Post extends Model
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\QueryMethods;
|
||||||
|
|
||||||
|
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
|
||||||
|
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
|
||||||
|
|
||||||
|
class Test extends AbstractModelsCommand
|
||||||
|
{
|
||||||
|
protected function getEnvironmentSetUp($app)
|
||||||
|
{
|
||||||
|
parent::getEnvironmentSetUp($app);
|
||||||
|
|
||||||
|
$app['config']->set('ide-helper.write_query_methods', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test(): void
|
||||||
|
{
|
||||||
|
$command = $this->app->make(ModelsCommand::class);
|
||||||
|
|
||||||
|
$tester = $this->runCommand($command, [
|
||||||
|
'--write' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(0, $tester->getStatusCode());
|
||||||
|
$this->assertStringContainsString('Written new phpDocBlock to', $tester->getDisplay());
|
||||||
|
$this->assertMatchesMockedSnapshot();
|
||||||
|
$this->assertStringNotContainsString("@method static \Illuminate\Database\Eloquent\Builder<static>|Post query()", $this->mockFilesystemOutput);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\QueryMethods\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property string|null $char_nullable
|
||||||
|
* @property string $char_not_nullable
|
||||||
|
* @property string|null $string_nullable
|
||||||
|
* @property string $string_not_nullable
|
||||||
|
* @property string|null $text_nullable
|
||||||
|
* @property string $text_not_nullable
|
||||||
|
* @property string|null $medium_text_nullable
|
||||||
|
* @property string $medium_text_not_nullable
|
||||||
|
* @property string|null $long_text_nullable
|
||||||
|
* @property string $long_text_not_nullable
|
||||||
|
* @property int|null $integer_nullable
|
||||||
|
* @property int $integer_not_nullable
|
||||||
|
* @property int|null $tiny_integer_nullable
|
||||||
|
* @property int $tiny_integer_not_nullable
|
||||||
|
* @property int|null $small_integer_nullable
|
||||||
|
* @property int $small_integer_not_nullable
|
||||||
|
* @property int|null $medium_integer_nullable
|
||||||
|
* @property int $medium_integer_not_nullable
|
||||||
|
* @property int|null $big_integer_nullable
|
||||||
|
* @property int $big_integer_not_nullable
|
||||||
|
* @property int|null $unsigned_integer_nullable
|
||||||
|
* @property int $unsigned_integer_not_nullable
|
||||||
|
* @property int|null $unsigned_tiny_integer_nullable
|
||||||
|
* @property int $unsigned_tiny_integer_not_nullable
|
||||||
|
* @property int|null $unsigned_small_integer_nullable
|
||||||
|
* @property int $unsigned_small_integer_not_nullable
|
||||||
|
* @property int|null $unsigned_medium_integer_nullable
|
||||||
|
* @property int $unsigned_medium_integer_not_nullable
|
||||||
|
* @property int|null $unsigned_big_integer_nullable
|
||||||
|
* @property int $unsigned_big_integer_not_nullable
|
||||||
|
* @property float|null $float_nullable
|
||||||
|
* @property float $float_not_nullable
|
||||||
|
* @property float|null $double_nullable
|
||||||
|
* @property float $double_not_nullable
|
||||||
|
* @property numeric|null $decimal_nullable
|
||||||
|
* @property numeric $decimal_not_nullable
|
||||||
|
* @property int|null $boolean_nullable
|
||||||
|
* @property int $boolean_not_nullable
|
||||||
|
* @property string|null $enum_nullable
|
||||||
|
* @property string $enum_not_nullable
|
||||||
|
* @property string|null $json_nullable
|
||||||
|
* @property string $json_not_nullable
|
||||||
|
* @property string|null $jsonb_nullable
|
||||||
|
* @property string $jsonb_not_nullable
|
||||||
|
* @property string|null $date_nullable
|
||||||
|
* @property string $date_not_nullable
|
||||||
|
* @property string|null $datetime_nullable
|
||||||
|
* @property string $datetime_not_nullable
|
||||||
|
* @property string|null $datetimetz_nullable
|
||||||
|
* @property string $datetimetz_not_nullable
|
||||||
|
* @property string|null $time_nullable
|
||||||
|
* @property string $time_not_nullable
|
||||||
|
* @property string|null $timetz_nullable
|
||||||
|
* @property string $timetz_not_nullable
|
||||||
|
* @property string|null $timestamp_nullable
|
||||||
|
* @property string $timestamp_not_nullable
|
||||||
|
* @property string|null $timestamptz_nullable
|
||||||
|
* @property string $timestamptz_not_nullable
|
||||||
|
* @property int|null $year_nullable
|
||||||
|
* @property int $year_not_nullable
|
||||||
|
* @property string|null $binary_nullable
|
||||||
|
* @property string $binary_not_nullable
|
||||||
|
* @property string|null $uuid_nullable
|
||||||
|
* @property string $uuid_not_nullable
|
||||||
|
* @property string|null $ipaddress_nullable
|
||||||
|
* @property string $ipaddress_not_nullable
|
||||||
|
* @property string|null $macaddress_nullable
|
||||||
|
* @property string $macaddress_not_nullable
|
||||||
|
* @property \Illuminate\Support\Carbon|null $created_at
|
||||||
|
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereBigIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereBigIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereBinaryNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereBinaryNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereBooleanNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereBooleanNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereCharNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereCharNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereCreatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDateNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDateNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDatetimeNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDatetimeNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDatetimetzNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDatetimetzNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDecimalNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDecimalNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDoubleNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereDoubleNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereEnumNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereEnumNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereFloatNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereFloatNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereIpaddressNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereIpaddressNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereJsonNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereJsonNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereJsonbNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereJsonbNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereLongTextNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereLongTextNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereMacaddressNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereMacaddressNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereMediumIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereMediumIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereMediumTextNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereMediumTextNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereSmallIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereSmallIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereStringNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereStringNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTextNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTextNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTimeNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTimeNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTimestampNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTimestampNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTimestamptzNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTimestamptzNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTimetzNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTimetzNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTinyIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereTinyIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedBigIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedBigIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedMediumIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedMediumIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedSmallIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedSmallIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedTinyIntegerNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUnsignedTinyIntegerNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUpdatedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUuidNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereUuidNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereYearNotNullable($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|Post whereYearNullable($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class Post extends Model
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -81,8 +81,8 @@ namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\QueryScopes\Mode
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
|||||||
* @property float $float_not_nullable
|
* @property float $float_not_nullable
|
||||||
* @property float|null $double_nullable
|
* @property float|null $double_nullable
|
||||||
* @property float $double_not_nullable
|
* @property float $double_not_nullable
|
||||||
* @property string|null $decimal_nullable
|
* @property numeric|null $decimal_nullable
|
||||||
* @property string $decimal_not_nullable
|
* @property numeric $decimal_not_nullable
|
||||||
* @property int|null $boolean_nullable
|
* @property int|null $boolean_nullable
|
||||||
* @property int $boolean_not_nullable
|
* @property int $boolean_not_nullable
|
||||||
* @property string|null $enum_nullable
|
* @property string|null $enum_nullable
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
|
|
||||||
|
class ModelWithRelations extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'models_with_relations';
|
||||||
|
|
||||||
|
public function softDeletable(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(SoftDeletableModel::class, 'soft_deletable_model_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function nonSoftDeletable(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(NonSoftDeletableModel::class, 'non_soft_deletable_model_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function softDeletableHasOne(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(SoftDeletableModel::class, 'model_with_relations_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function nonSoftDeletableHasOne(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(NonSoftDeletableModel::class, 'model_with_relations_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class NonSoftDeletableModel extends Model
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class SoftDeletableModel extends Model
|
||||||
|
{
|
||||||
|
use SoftDeletes;
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations;
|
||||||
|
|
||||||
|
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
|
||||||
|
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
|
||||||
|
use Illuminate\Support\Facades\Config;
|
||||||
|
|
||||||
|
class Test extends AbstractModelsCommand
|
||||||
|
{
|
||||||
|
public function test(): void
|
||||||
|
{
|
||||||
|
$command = $this->app->make(ModelsCommand::class);
|
||||||
|
|
||||||
|
$tester = $this->runCommand($command, [
|
||||||
|
'--write' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(0, $tester->getStatusCode());
|
||||||
|
$this->assertStringContainsString('Written new phpDocBlock to', $tester->getDisplay());
|
||||||
|
$this->assertMatchesMockedSnapshot();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSoftDeletesForceNullableDisabled(): void
|
||||||
|
{
|
||||||
|
Config::set('ide-helper.soft_deletes_force_nullable', false);
|
||||||
|
|
||||||
|
$command = $this->app->make(ModelsCommand::class);
|
||||||
|
|
||||||
|
$tester = $this->runCommand($command, [
|
||||||
|
'--write' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertSame(0, $tester->getStatusCode());
|
||||||
|
$this->assertStringContainsString('Written new phpDocBlock to', $tester->getDisplay());
|
||||||
|
$this->assertMatchesMockedSnapshot();
|
||||||
|
|
||||||
|
Config::set('ide-helper.soft_deletes_force_nullable', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
+99
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $soft_deletable_model_id
|
||||||
|
* @property int $non_soft_deletable_model_id
|
||||||
|
* @property-read \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models\NonSoftDeletableModel $nonSoftDeletable
|
||||||
|
* @property-read \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models\NonSoftDeletableModel|null $nonSoftDeletableHasOne
|
||||||
|
* @property-read \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models\SoftDeletableModel $softDeletable
|
||||||
|
* @property-read \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models\SoftDeletableModel|null $softDeletableHasOne
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations whereNonSoftDeletableModelId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations whereSoftDeletableModelId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class ModelWithRelations extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'models_with_relations';
|
||||||
|
|
||||||
|
public function softDeletable(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(SoftDeletableModel::class, 'soft_deletable_model_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function nonSoftDeletable(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(NonSoftDeletableModel::class, 'non_soft_deletable_model_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function softDeletableHasOne(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(SoftDeletableModel::class, 'model_with_relations_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function nonSoftDeletableHasOne(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(NonSoftDeletableModel::class, 'model_with_relations_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int|null $model_with_relations_id
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel whereModelWithRelationsId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class NonSoftDeletableModel extends Model
|
||||||
|
{
|
||||||
|
}
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int|null $model_with_relations_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel onlyTrashed()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel whereDeletedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel whereModelWithRelationsId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel withTrashed(bool $withTrashed = true)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel withoutTrashed()
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class SoftDeletableModel extends Model
|
||||||
|
{
|
||||||
|
use SoftDeletes;
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int $soft_deletable_model_id
|
||||||
|
* @property int $non_soft_deletable_model_id
|
||||||
|
* @property-read \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models\NonSoftDeletableModel $nonSoftDeletable
|
||||||
|
* @property-read \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models\NonSoftDeletableModel|null $nonSoftDeletableHasOne
|
||||||
|
* @property-read \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models\SoftDeletableModel|null $softDeletable
|
||||||
|
* @property-read \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models\SoftDeletableModel|null $softDeletableHasOne
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations whereNonSoftDeletableModelId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|ModelWithRelations whereSoftDeletableModelId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class ModelWithRelations extends Model
|
||||||
|
{
|
||||||
|
protected $table = 'models_with_relations';
|
||||||
|
|
||||||
|
public function softDeletable(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(SoftDeletableModel::class, 'soft_deletable_model_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function nonSoftDeletable(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(NonSoftDeletableModel::class, 'non_soft_deletable_model_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function softDeletableHasOne(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(SoftDeletableModel::class, 'model_with_relations_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function nonSoftDeletableHasOne(): HasOne
|
||||||
|
{
|
||||||
|
return $this->hasOne(NonSoftDeletableModel::class, 'model_with_relations_id');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int|null $model_with_relations_id
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|NonSoftDeletableModel whereModelWithRelationsId($value)
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class NonSoftDeletableModel extends Model
|
||||||
|
{
|
||||||
|
}
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\SoftDeletesRelations\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $id
|
||||||
|
* @property int|null $model_with_relations_id
|
||||||
|
* @property \Illuminate\Support\Carbon|null $deleted_at
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel newModelQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel newQuery()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel onlyTrashed()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel query()
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel whereDeletedAt($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel whereId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel whereModelWithRelationsId($value)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel withTrashed(bool $withTrashed = true)
|
||||||
|
* @method static \Illuminate\Database\Eloquent\Builder<static>|SoftDeletableModel withoutTrashed()
|
||||||
|
* @mixin \Eloquent
|
||||||
|
*/
|
||||||
|
class SoftDeletableModel extends Model
|
||||||
|
{
|
||||||
|
use SoftDeletes;
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class SoftDeletesRelationsTable extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('soft_deletable_models', function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
$table->unsignedBigInteger('model_with_relations_id')->nullable();
|
||||||
|
$table->softDeletes();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('non_soft_deletable_models', function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
$table->unsignedBigInteger('model_with_relations_id')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('models_with_relations', function (Blueprint $table) {
|
||||||
|
$table->bigIncrements('id');
|
||||||
|
$table->unsignedBigInteger('soft_deletable_model_id');
|
||||||
|
$table->unsignedBigInteger('non_soft_deletable_model_id');
|
||||||
|
|
||||||
|
$table->foreign('soft_deletable_model_id')
|
||||||
|
->references('id')
|
||||||
|
->on('soft_deletable_models');
|
||||||
|
|
||||||
|
$table->foreign('non_soft_deletable_model_id')
|
||||||
|
->references('id')
|
||||||
|
->on('non_soft_deletable_models');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace Barryvdh\LaravelIdeHelper\Tests\Factories;
|
|
||||||
|
|
||||||
use Barryvdh\LaravelIdeHelper\Factories;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
class AllTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testAll(): void
|
|
||||||
{
|
|
||||||
$factories = Factories::all();
|
|
||||||
|
|
||||||
self::assertEmpty($factories);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+60
-3
@@ -207,6 +207,63 @@ class MacroTest extends TestCase
|
|||||||
$this->assertEquals('@return \Stringable|string|null', $this->tagsToString($phpdoc, 'return'));
|
$this->assertEquals('@return \Stringable|string|null', $this->tagsToString($phpdoc, 'return'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testInitPhpDocParamsWithDnfTypes(): void
|
||||||
|
{
|
||||||
|
$phpdoc = (new MacroMock())->getPhpDoc(eval(<<<'PHP'
|
||||||
|
return new ReflectionFunction(
|
||||||
|
/**
|
||||||
|
* Test docblock with DNF types.
|
||||||
|
*/
|
||||||
|
function ((\Countable&\Iterator)|null $a): (\Countable&\Iterator)|\stdClass|null {
|
||||||
|
return $a;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
PHP));
|
||||||
|
|
||||||
|
$this->assertNotNull($phpdoc);
|
||||||
|
$this->assertStringContainsString('Test docblock with DNF types', $phpdoc->getText());
|
||||||
|
$this->assertEquals('@param (Countable&Iterator)|null $a', $this->tagsToString($phpdoc, 'param'));
|
||||||
|
$this->assertEquals('@return (Countable&Iterator)|\stdClass|null', $this->tagsToString($phpdoc, 'return'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInitPhpDocParamsWithPureIntersectionType(): void
|
||||||
|
{
|
||||||
|
$phpdoc = (new MacroMock())->getPhpDoc(eval(<<<'PHP'
|
||||||
|
return new ReflectionFunction(
|
||||||
|
/**
|
||||||
|
* Test docblock with pure intersection type.
|
||||||
|
*/
|
||||||
|
function (\Countable&\Iterator $a): \Countable&\Iterator {
|
||||||
|
return $a;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
PHP));
|
||||||
|
|
||||||
|
$this->assertNotNull($phpdoc);
|
||||||
|
$this->assertStringContainsString('Test docblock with pure intersection type', $phpdoc->getText());
|
||||||
|
$this->assertEquals('@param (Countable&Iterator) $a', $this->tagsToString($phpdoc, 'param'));
|
||||||
|
$this->assertEquals('@return (Countable&Iterator)', $this->tagsToString($phpdoc, 'return'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInitPhpDocParamsWithMultipleIntersections(): void
|
||||||
|
{
|
||||||
|
$phpdoc = (new MacroMock())->getPhpDoc(eval(<<<'PHP'
|
||||||
|
return new ReflectionFunction(
|
||||||
|
/**
|
||||||
|
* Test docblock with multiple intersection segments.
|
||||||
|
*/
|
||||||
|
function ((\Countable&\Iterator)|(\ArrayAccess&\Stringable) $a): (\Countable&\Iterator)|(\ArrayAccess&\Stringable)|null {
|
||||||
|
return $a;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
PHP));
|
||||||
|
|
||||||
|
$this->assertNotNull($phpdoc);
|
||||||
|
$this->assertStringContainsString('Test docblock with multiple intersection segments', $phpdoc->getText());
|
||||||
|
$this->assertEquals('@param (Countable&Iterator)|(ArrayAccess&Stringable) $a', $this->tagsToString($phpdoc, 'param'));
|
||||||
|
$this->assertEquals('@return (Countable&Iterator)|(ArrayAccess&Stringable)|null', $this->tagsToString($phpdoc, 'return'));
|
||||||
|
}
|
||||||
|
|
||||||
protected function tagsToString(DocBlock $docBlock, string $name)
|
protected function tagsToString(DocBlock $docBlock, string $name)
|
||||||
{
|
{
|
||||||
$tags = $docBlock->getTagsByName($name);
|
$tags = $docBlock->getTagsByName($name);
|
||||||
@@ -227,7 +284,7 @@ class MacroTest extends TestCase
|
|||||||
{
|
{
|
||||||
$reflectionMethod = new \ReflectionMethod(UrlGeneratorMacroClass::class, '__invoke');
|
$reflectionMethod = new \ReflectionMethod(UrlGeneratorMacroClass::class, '__invoke');
|
||||||
|
|
||||||
$macro = new Macro($reflectionMethod, UrlGenerator::class, new ReflectionClass(UrlGenerator::class), 'macroName');
|
$macro = new Macro($reflectionMethod, new ReflectionClass(UrlGenerator::class), 'macroName');
|
||||||
|
|
||||||
$this->assertInstanceOf(Macro::class, $macro);
|
$this->assertInstanceOf(Macro::class, $macro);
|
||||||
}
|
}
|
||||||
@@ -239,7 +296,7 @@ class MacroTest extends TestCase
|
|||||||
{
|
{
|
||||||
$reflectionMethod = new \ReflectionMethod(UrlGeneratorMacroClass::class, '__invoke');
|
$reflectionMethod = new \ReflectionMethod(UrlGeneratorMacroClass::class, '__invoke');
|
||||||
|
|
||||||
$macro = new Macro($reflectionMethod, 'URL', new ReflectionClass(UrlGenerator::class), 'macroName');
|
$macro = new Macro($reflectionMethod, new ReflectionClass(UrlGenerator::class), 'macroName');
|
||||||
$output = <<<'DOC'
|
$output = <<<'DOC'
|
||||||
/**
|
/**
|
||||||
* @param string $foo
|
* @param string $foo
|
||||||
@@ -274,7 +331,7 @@ class MacroMock extends Macro
|
|||||||
|
|
||||||
public function getPhpDoc(ReflectionFunctionAbstract $method, ?ReflectionClass $class = null): DocBlock
|
public function getPhpDoc(ReflectionFunctionAbstract $method, ?ReflectionClass $class = null): DocBlock
|
||||||
{
|
{
|
||||||
return (new Macro($method, '', $class ?? $method->getClosureScopeClass()))->phpdoc;
|
return (new Macro($method, $class ?? $method->getClosureScopeClass()))->phpdoc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class MethodTest extends TestCase
|
|||||||
$reflectionClass = new \ReflectionClass(ExampleClass::class);
|
$reflectionClass = new \ReflectionClass(ExampleClass::class);
|
||||||
$reflectionMethod = $reflectionClass->getMethod('setName');
|
$reflectionMethod = $reflectionClass->getMethod('setName');
|
||||||
|
|
||||||
$method = new Method($reflectionMethod, 'Example', $reflectionClass);
|
$method = new Method($reflectionMethod, $reflectionClass);
|
||||||
|
|
||||||
$this->assertInstanceOf(Method::class, $method);
|
$this->assertInstanceOf(Method::class, $method);
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ class MethodTest extends TestCase
|
|||||||
$reflectionClass = new \ReflectionClass(ExampleClass::class);
|
$reflectionClass = new \ReflectionClass(ExampleClass::class);
|
||||||
$reflectionMethod = $reflectionClass->getMethod('setName');
|
$reflectionMethod = $reflectionClass->getMethod('setName');
|
||||||
|
|
||||||
$method = new Method($reflectionMethod, 'Example', $reflectionClass);
|
$method = new Method($reflectionMethod, $reflectionClass);
|
||||||
|
|
||||||
$output = <<<'DOC'
|
$output = <<<'DOC'
|
||||||
/**
|
/**
|
||||||
@@ -60,7 +60,7 @@ DOC;
|
|||||||
$reflectionClass = new \ReflectionClass(EloquentBuilder::class);
|
$reflectionClass = new \ReflectionClass(EloquentBuilder::class);
|
||||||
$reflectionMethod = $reflectionClass->getMethod('upsert');
|
$reflectionMethod = $reflectionClass->getMethod('upsert');
|
||||||
|
|
||||||
$method = new Method($reflectionMethod, 'Builder', $reflectionClass);
|
$method = new Method($reflectionMethod, $reflectionClass);
|
||||||
|
|
||||||
$output = <<<'DOC'
|
$output = <<<'DOC'
|
||||||
/**
|
/**
|
||||||
@@ -92,7 +92,7 @@ DOC;
|
|||||||
$reflectionClass = new \ReflectionClass(EloquentBuilder::class);
|
$reflectionClass = new \ReflectionClass(EloquentBuilder::class);
|
||||||
$reflectionMethod = $reflectionClass->getMethod('where');
|
$reflectionMethod = $reflectionClass->getMethod('where');
|
||||||
|
|
||||||
$method = new Method($reflectionMethod, 'Builder', $reflectionClass, null, [], [], ['$this' => '\\' . EloquentBuilder::class . '<static>']);
|
$method = new Method($reflectionMethod, $reflectionClass, null, [], [], ['$this' => '\\' . EloquentBuilder::class . '<static>']);
|
||||||
|
|
||||||
$output = <<<'DOC'
|
$output = <<<'DOC'
|
||||||
/**
|
/**
|
||||||
@@ -123,7 +123,7 @@ DOC;
|
|||||||
$reflectionClass = new \ReflectionClass(QueryBuilder::class);
|
$reflectionClass = new \ReflectionClass(QueryBuilder::class);
|
||||||
$reflectionMethod = $reflectionClass->getMethod('whereNull');
|
$reflectionMethod = $reflectionClass->getMethod('whereNull');
|
||||||
|
|
||||||
$method = new Method($reflectionMethod, 'Builder', $reflectionClass, null, [], [], ['$this' => '\\' . EloquentBuilder::class . '<static>']);
|
$method = new Method($reflectionMethod, $reflectionClass, null, [], [], ['$this' => '\\' . EloquentBuilder::class . '<static>']);
|
||||||
|
|
||||||
$output = <<<'DOC'
|
$output = <<<'DOC'
|
||||||
/**
|
/**
|
||||||
@@ -154,7 +154,7 @@ DOC;
|
|||||||
$reflectionClass = new \ReflectionClass(ExampleClass::class);
|
$reflectionClass = new \ReflectionClass(ExampleClass::class);
|
||||||
$reflectionMethod = $reflectionClass->getMethod('setSpecialChars');
|
$reflectionMethod = $reflectionClass->getMethod('setSpecialChars');
|
||||||
|
|
||||||
$method = new Method($reflectionMethod, 'Example', $reflectionClass);
|
$method = new Method($reflectionMethod, $reflectionClass);
|
||||||
$this->assertSame('$chars', $method->getParams(true));
|
$this->assertSame('$chars', $method->getParams(true));
|
||||||
$this->assertSame(['$chars'], $method->getParams(false));
|
$this->assertSame(['$chars'], $method->getParams(false));
|
||||||
$this->assertSame('$chars = \'$\\\'\\\\\'', $method->getParamsWithDefault(true));
|
$this->assertSame('$chars = \'$\\\'\\\\\'', $method->getParamsWithDefault(true));
|
||||||
@@ -169,7 +169,7 @@ DOC;
|
|||||||
$reflectionClass = new \ReflectionClass(ExampleClass::class);
|
$reflectionClass = new \ReflectionClass(ExampleClass::class);
|
||||||
$reflectionMethod = $reflectionClass->getMethod('getApplication');
|
$reflectionMethod = $reflectionClass->getMethod('getApplication');
|
||||||
|
|
||||||
$method = new Method($reflectionMethod, 'Example', $reflectionClass, null, [], [
|
$method = new Method($reflectionMethod, $reflectionClass, null, [], [
|
||||||
'Application' => '\\Illuminate\\Foundation\\Application',
|
'Application' => '\\Illuminate\\Foundation\\Application',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ DOC;
|
|||||||
$reflectionClass = new \ReflectionClass(EloquentBuilder::class);
|
$reflectionClass = new \ReflectionClass(EloquentBuilder::class);
|
||||||
$reflectionMethod = $reflectionClass->getMethod('firstOr');
|
$reflectionMethod = $reflectionClass->getMethod('firstOr');
|
||||||
|
|
||||||
$method = new Method($reflectionMethod, 'Builder', $reflectionClass, null, [], [], [], ['TModel']);
|
$method = new Method($reflectionMethod, $reflectionClass, null, [], [], [], ['TModel']);
|
||||||
|
|
||||||
$output = <<<'DOC'
|
$output = <<<'DOC'
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user