Compare commits

...
22 Commits
Author SHA1 Message Date
Bartlomiej Kwarcinski 81d5b223ff Fix Castables issue #1312 (#1388)
* Return Castable class if failed to detect it from return types

* fix-style

* Add CHANGELOG.md entry
2023-02-04 14:56:40 +01:00
Alies LapatsinandBarry vd. Heuvel ce24d4b013 Added support for Laravel 10 (+ update testing matrix) (#1407)
* Laravel 10 support

* Add events v10 to suggestions

* Exclude invalid combinations from testing matrix, test on PHP 8.2

* Update CHANGELOG.md

* Use laravel/laravel dev-master as 10.x version

* Exclude one more laravel-php combination

* Use 10.* instead if dev-master

* Update run-integration-tests.yml

---------

Co-authored-by: Barry vd. Heuvel <[email protected]>
2023-02-04 14:54:33 +01:00
Barry vd. Heuvel edfb05621c IDE Helper for Laravel 2023-02-01 17:24:13 +01:00
Taner KucukyurukandMarkus Podar f0e4cf5e78 Generics annotations support (#1298)
* option to use generics syntax, default to yes in laravel 9

* rename `use_generics_syntax` to `use_generics_annotations`

* update readme and changelog

* remove laravel 9 default override

* include key type in generics annotations

* readme rewording

* set `use_generics_annotations` to `true` by default

* update tests to reflect `use_generics_annotations` being set to `true` by default

* default `use_generics_annotations` setting to true when not set in config

Co-authored-by: Markus Podar <[email protected]>

---------

Co-authored-by: Markus Podar <[email protected]>
2023-01-28 16:48:05 +01:00
Markus Podar 5d9925bab8 gha: fix workflow by allowing the composer-normalize plugin (#1412)
* gha: fix workflow by allowing the composer-normalize plugin

We don't need to enable it in the project itself, but at least in this
workflow which explicitly uses it.

See https://github.com/barryvdh/laravel-ide-helper/actions/runs/3980013548/jobs/6822812621#step:4:34
```
Error: ergebnis/composer-normalize (installed globally) contains a Composer plugin which is blocked by your allow-plugins config. You may add it to the list if you consider it safe.
You can run "composer global config --no-plugins allow-plugins.ergebnis/composer-normalize [true|false]" to enable it (true) or disable it explicitly and suppress this exception (false)
```

* gha: also run this workflow when it is changed itself
2023-01-24 17:32:39 +01:00
Stef van EschandBarry vd. Heuvel 9e50460017 Added support for Laravel 10 (#1406)
* Added support for Laravel 10

* Update run-tests.yml

* Update run-tests.yml

* Update run-integration-tests.yml

Co-authored-by: Barry vd. Heuvel <[email protected]>
2023-01-22 15:01:32 +01:00
Barry vd. Heuvelandlaravel-ide-helper b55769213c Use dev instead of stable (#1409)
* Update run-integration-tests.yml

* composer fix-style

* Update run-integration-tests.yml

Co-authored-by: laravel-ide-helper <[email protected]>
2023-01-22 15:01:12 +01:00
Bentley O'Kane-Chase f055d42b39 Add phpstorm metadata for mock methods when testing (#1405)
* Add phpstorm metadata for testing

* Update CHANGELOG.md
2023-01-17 12:37:15 +01:00
sforwardandSimon Verwaard dda200fd34 Add support for CastsInboundAttributes (#1329)
* Add support for CastsInboundAttributes

* Update changelog

Co-authored-by: Simon Verwaard <[email protected]>
2022-09-13 10:42:06 +02:00
Markus Podar e8ecb3da88 Merge pull request #1367 from krsriq/patch-1 2022-08-21 11:42:25 +02:00
Daniel Schmelz e49c4556dd Fix typo 2022-08-21 08:40:17 +02:00
Daniel Schmelz 2c96c45d5e Fix typos 2022-08-20 10:50:21 +02:00
sforwardandSimon Verwaard 532ae5bec3 Fix database name (#1364)
Co-authored-by: Simon Verwaard <[email protected]>
2022-08-13 22:02:45 +02:00
JefemyandBarry vd. Heuvel c8f0f914e3 Fix issue where \Eloquent is not included when using write_mixin (#1352)
* Check for exact mixin name when writing

* changelog

* add mixin to test class

Co-authored-by: Barry vd. Heuvel <[email protected]>
2022-08-11 12:39:26 +02:00
KentarouTakeda 07f5eaea73 Fix return type of methods provided by SoftDeletes (#1345)
* Fix return type of methods provided by `SoftDeletes`

* Update CHANGELOG

* fix test / update snapshot
2022-08-11 12:36:43 +02:00
Corey McCormick c76fbb5b61 Allow for proper database resolve with schemas (#1349)
* Allow for proper database resolve with schemas

* Remove need to explode database and table name
2022-08-11 12:35:46 +02:00
angeljqv c40fee2a3f Update .gitattributes (#1355) 2022-08-11 12:32:48 +02:00
Wim Reckman 5eadd2c7de Fix model factory method arguments for Laravel >= 9 (#1361) 2022-08-11 12:32:14 +02:00
Barry vd. Heuvelandlaravel-ide-helper 6e26f22c76 Feat useclassmappackage (#1357)
* Use composer/class-map-generator

* composer fix-style

Co-authored-by: laravel-ide-helper <[email protected]>
2022-06-20 15:54:12 +02:00
JefemyandMarkus Podar ee9188acf1 Implement new config to specify return type of custom relations (#1300)
* Implement new config to specify return type of custom relations

* Apply suggestions from code review

Co-authored-by: Markus Podar <[email protected]>

* add test for morphed

* fix test output

* add info about how to add custom relationships

* fix wording

Co-authored-by: Markus Podar <[email protected]>
2022-05-22 20:07:54 +02:00
Markus Podar a567f73140 readme: explicitly state supported version (#1348)
Based on the discussion in https://github.com/barryvdh/laravel-ide-helper/issues/1347
2022-05-21 22:40:30 +02:00
Markus Podar 6a461a7c47 Fix integration tests by fixing a PHP 8.1+ deprecation warnings in ReflectionClass (#1351)
* gha: get more insights when/if logs exist

* Better handle cases when we can receive a concrete instance

The problem with `null` being passed to `ReflectionClass` was always
there but in PHP 8.1+ it triggers a deprecation warnings.

Since having `null` in `$concrete` doesn't make sense to reflect
anything anyway, we just throw a custom exception (which gets caught a
couple lines below) and just carry on.

When using `-v` this can be seen, example:
```
$ ./artisan ide-helper:meta -v
Cannot make 'Faker\Generator': Class 'Faker\Provider\en_US\Barcode' not found.
Cannot make 'Illuminate\Contracts\Auth\Authenticatable': Class  does not exist
Cannot make 'cache.psr6': Class 'Symfony\Component\Cache\Adapter\Psr16Adapter' not found.
Cannot make 'csp-nonce': Class 'Wza3Mf4CXIvCkcp9K3boMUGJoK6S9maO' not found.
Cannot make 'env': Class 'local' not found.
Cannot make 'filesystem.cloud': Disk [s3] does not have a configured driver.
Cannot make 'redis.connection': Redis connection [default] not configured.
A new meta file was written to .phpstorm.meta.php
```

* gha: make sure to run meta with -v to see all output

Helps when debugging things

* Add CHANGELOG.md entry
2022-05-21 22:38:28 +02:00
36 changed files with 576 additions and 482 deletions
+6
View File
@@ -5,5 +5,11 @@
/.gitattributes export-ignore /.gitattributes export-ignore
/.github export-ignore /.github export-ignore
/.gitignore export-ignore /.gitignore export-ignore
/.editorconfig export-ignore
/phpunit.xml.dist export-ignore /phpunit.xml.dist export-ignore
/tests export-ignore /tests export-ignore
/.php_cs.common.php export-ignore
/.php_cs.dist export-ignore
/.php_cs.tests.php export-ignore
/psalm.xml export-ignore
/psalm-baseline.xml export-ignore
+2
View File
@@ -3,6 +3,7 @@ name: normalize composer.json
on: on:
push: push:
paths: paths:
- .github/workflows/composer-normalize.yml
- composer.json - composer.json
jobs: jobs:
@@ -18,6 +19,7 @@ jobs:
- name: Normalize composer.json - name: Normalize composer.json
run: | run: |
composer global config --no-plugins allow-plugins.ergebnis/composer-normalize true
composer global require ergebnis/composer-normalize composer global require ergebnis/composer-normalize
composer normalize composer normalize
+33 -10
View File
@@ -18,7 +18,7 @@ jobs:
COMPOSER_NO_INTERACTION: 1 COMPOSER_NO_INTERACTION: 1
strategy: strategy:
matrix: matrix:
php: [8.1, 8.0, 7.4, 7.3] php: [8.2, 8.1, 8.0, 7.4, 7.3]
lumen: [8.*] lumen: [8.*]
name: P${{ matrix.php }} - Lumen${{ matrix.lumen }} name: P${{ matrix.php }} - Lumen${{ matrix.lumen }}
steps: steps:
@@ -37,6 +37,7 @@ jobs:
run: | run: |
composer create-project --prefer-dist laravel/lumen:${{ matrix.lumen }} --no-progress sample composer create-project --prefer-dist laravel/lumen:${{ matrix.lumen }} --no-progress sample
cd sample cd sample
composer config minimum-stability dev
composer require "league/flysystem:^1" --no-update --no-progress composer require "league/flysystem:^1" --no-update --no-progress
composer update --prefer-stable --prefer-dist --no-progress composer update --prefer-stable --prefer-dist --no-progress
@@ -57,16 +58,22 @@ jobs:
- name: Execute meta run - name: Execute meta run
run: | run: |
cd sample cd sample
php artisan ide-helper:meta php artisan ide-helper:meta -v
- name: Check file existence - name: Check file existence
run: | run: |
ls sample/_ide_helper.php ls sample/_ide_helper.php
ls sample/.phpstorm.meta.php ls sample/.phpstorm.meta.php
- name: Check file count in logs - name: Check logs
run: | run: |
if [ `ls -1q "sample/storage/logs/" | wc -l` -gt 0 ];then exit 1;fi 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
php-laravel-integration-tests: php-laravel-integration-tests:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
@@ -75,9 +82,17 @@ jobs:
COMPOSER_NO_INTERACTION: 1 COMPOSER_NO_INTERACTION: 1
strategy: strategy:
matrix: matrix:
php: [8.1, 8.0, 7.4, 7.3] php: [8.2, 8.1, 8.0, 7.4, 7.3]
laravel: [9.*, 8.*] laravel: [10.*, 9.*, 8.*]
exclude: exclude:
- php: 8.0
laravel: 10.*
- php: 7.4
laravel: 10.*
- php: 7.4
laravel: 10.*
- php: 7.3
laravel: 10.*
- php: 7.4 - php: 7.4
laravel: 9.* laravel: 9.*
- php: 7.3 - php: 7.3
@@ -97,8 +112,9 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: | run: |
composer create-project --prefer-dist laravel/laravel:${{ matrix.laravel }} --no-progress sample composer create-project --prefer-dist laravel/laravel:${{ matrix.laravel }} --stability=dev --no-progress sample
cd sample cd sample
composer config minimum-stability dev
composer update --prefer-stable --prefer-dist --no-progress composer update --prefer-stable --prefer-dist --no-progress
- name: Add package from source - name: Add package from source
@@ -115,13 +131,20 @@ jobs:
- name: Execute meta run - name: Execute meta run
run: | run: |
cd sample cd sample
php artisan ide-helper:meta php artisan ide-helper:meta -v
- name: Check file existence - name: Check file existence
run: | run: |
ls sample/_ide_helper.php ls sample/_ide_helper.php
ls sample/.phpstorm.meta.php ls sample/.phpstorm.meta.php
- name: Check file count in logs
- name: Check logs
run: | run: |
if [ `ls -1q "sample/storage/logs/" | wc -l` -gt 0 ];then exit 1;fi 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
+7 -1
View File
@@ -21,9 +21,15 @@ jobs:
matrix: matrix:
os: [ubuntu-20.04, windows-2019] os: [ubuntu-20.04, windows-2019]
php: [8.1, 8.0, 7.4, 7.3] php: [8.1, 8.0, 7.4, 7.3]
laravel: [8.*, 9.*] laravel: [8.*, 9.*, 10.*]
dependency-version: [prefer-lowest, prefer-stable] dependency-version: [prefer-lowest, prefer-stable]
exclude: exclude:
- php: 8.0
laravel: 10.*
- php: 7.4
laravel: 10.*
- php: 7.3
laravel: 10.*
- php: 8.0 - php: 8.0
dependency-version: prefer-lowest dependency-version: prefer-lowest
- php: 7.4 - php: 7.4
+14
View File
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
[Next release](https://github.com/barryvdh/laravel-ide-helper/compare/v2.12.3...master) [Next release](https://github.com/barryvdh/laravel-ide-helper/compare/v2.12.3...master)
-------------- --------------
### Fixes
- Fix return type of methods provided by `SoftDeletes` [#1345 / KentarouTakeda](https://github.com/barryvdh/laravel-ide-helper/pull/1345)
- Handle PHP 8.1 deprecation warnings when passing `null` to `new \ReflectionClass` [#1351 / mfn](https://github.com/barryvdh/laravel-ide-helper/pull/1351)
- Fix issue where \Eloquent is not included when using write_mixin [#1352 / Jefemy](https://github.com/barryvdh/laravel-ide-helper/pull/1352)
- Fix model factory method arguments for Laravel >= 9 [#1361 / wimski](https://github.com/barryvdh/laravel-ide-helper/pull/1361)
- Improve return type of mock helper methods in tests [#1405 / bentleyo](https://github.com/barryvdh/laravel-ide-helper/pull/1405)
- Fix Castable class if failed to detect it from return types [#1388 / kwarcu](https://github.com/barryvdh/laravel-ide-helper/pull/1388)
### Added
- Added Laravel 10 support [#1407 / lptn](https://github.com/barryvdh/laravel-ide-helper/pull/1407)
- Add support for custom casts that implement `CastsInboundAttributes` [#1329 / sforward](https://github.com/barryvdh/laravel-ide-helper/pull/1329)
- Add option `use_generics_annotations` for collection type hints [#1298 / tanerkay](https://github.com/barryvdh/laravel-ide-helper/pull/1298)
2022-03-06, 2.12.3 2022-03-06, 2.12.3
------------------ ------------------
@@ -27,6 +40,7 @@ All notable changes to this project will be documented in this file.
### Added ### Added
- Add support for custom casts that using `Castable` [#1287 / binotaliu](https://github.com/barryvdh/laravel-ide-helper/pull/1287) - Add support for custom casts that using `Castable` [#1287 / binotaliu](https://github.com/barryvdh/laravel-ide-helper/pull/1287)
- Added Laravel 9 support [#1297 / rcerljenko](https://github.com/barryvdh/laravel-ide-helper/pull/1297) - Added Laravel 9 support [#1297 / rcerljenko](https://github.com/barryvdh/laravel-ide-helper/pull/1297)
- Added option `additional_relation_return_types` for custom relations that don't fit the typical naming scheme
2022-01-03, 2.11.0 2022-01-03, 2.11.0
------------------ ------------------
+32 -4
View File
@@ -1,4 +1,4 @@
# Laravel IDE Helper Generator # IDE Helper Generator for Laravel
[![Tests](https://github.com/barryvdh/laravel-ide-helper/actions/workflows/run-tests.yml/badge.svg)](https://github.com/barryvdh/laravel-ide-helper/actions) [![Tests](https://github.com/barryvdh/laravel-ide-helper/actions/workflows/run-tests.yml/badge.svg)](https://github.com/barryvdh/laravel-ide-helper/actions)
[![Packagist License](https://poser.pugx.org/barryvdh/laravel-ide-helper/license.png)](http://choosealicense.com/licenses/mit/) [![Packagist License](https://poser.pugx.org/barryvdh/laravel-ide-helper/license.png)](http://choosealicense.com/licenses/mit/)
@@ -11,6 +11,8 @@
This package generates helper files that enable your IDE to provide accurate autocompletion. This package generates helper files that enable your IDE to provide accurate autocompletion.
Generation is done based on the files in your project, so they are always up-to-date. Generation is done based on the files in your project, so they are always up-to-date.
It supports Laravel 8+ and PHP 7.3+
- [Installation](#installation) - [Installation](#installation)
- [Usage](#usage) - [Usage](#usage)
- [Automatic PHPDoc generation for Laravel Facades](#automatic-phpdoc-generation-for-laravel-facades) - [Automatic PHPDoc generation for Laravel Facades](#automatic-phpdoc-generation-for-laravel-facades)
@@ -225,6 +227,12 @@ You may use the [`::withCount`](https://laravel.com/docs/master/eloquent-relatio
By default, these attributes are generated in the phpdoc. You can turn them off by setting the config `write_model_relation_count_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` to `false`.
#### Generics annotations
Laravel 9 introduced generics annotations in DocBlocks for collections. PhpStorm 2022.3 and above support the use of generics annotations within `@property` and `@property-read` declarations in DocBlocks, e.g. `Collection<User>` instead of `Collection|User[]`.
These can be disabled by setting the config `use_generics_annotations` to `false`.
#### Support `@comment` based on DocBlock #### Support `@comment` based on DocBlock
In order to better support IDEs, relations and getters/setters can also add a comment to a property like table columns. Therefore a custom docblock `@comment` is used: In order to better support IDEs, relations and getters/setters can also add a comment to a property like table columns. Therefore a custom docblock `@comment` is used:
@@ -279,6 +287,26 @@ For those special cases, you can map them via the config `custom_db_types`. Exam
], ],
``` ```
#### Custom Relationship Types
If you are using relationships not built into Laravel you will need to specify the name and returning class in the config to get proper generation.
```php
'additional_relation_types' => [
'externalHasMany' => \My\Package\externalHasMany::class
],
```
Found relationships will typically generate a return value based on the name of the relationship.
If your custom relationships don't follow this traditional naming scheme you can define its return type manually. The available options are `many` and `morphTo`.
```php
'additional_relation_return_types' => [
'externalHasMultiple' => 'many'
],
```
#### Model Hooks #### Model Hooks
If you need additional information on your model from sources that are not handled by default, you can hook in to the If you need additional information on your model from sources that are not handled by default, you can hook in to the
@@ -325,7 +353,7 @@ If you need PHPDocs support for Fluent methods in migration, for example
$table->string("somestring")->nullable()->index(); $table->string("somestring")->nullable()->index();
``` ```
After publishing vendor, simply change the `include_fluent` line your `config/ide-helper.php` file into: After publishing vendor, simply change the `include_fluent` line in your `config/ide-helper.php` file into:
```php ```php
'include_fluent' => true, 'include_fluent' => true,
@@ -336,7 +364,7 @@ Then run `php artisan ide-helper:generate`, you will now see all Fluent methods
### Auto-completion for factory builders ### Auto-completion for factory builders
If you would like the `factory()->create()` and `factory()->make()` methods to return the correct model class, If you would like the `factory()->create()` and `factory()->make()` methods to return the correct model class,
you can enable custom factory builders with the `include_factory_builders` line your `config/ide-helper.php` file. you can enable custom factory builders with the `include_factory_builders` line in your `config/ide-helper.php` file.
Deprecated for Laravel 8 or latest. Deprecated for Laravel 8 or latest.
```php ```php
@@ -374,7 +402,7 @@ app(App\SomeClass::class);
> Note: When you receive a FatalException: class not found, check your config > Note: When you receive a FatalException: class not found, check your config
> (for example, remove S3 as cloud driver when you don't have S3 configured. Remove Redis ServiceProvider when you don't use it). > (for example, remove S3 as cloud driver when you don't have S3 configured. Remove Redis ServiceProvider when you don't use it).
You can change the generated filename via the config `meta_filename`. This can be useful for cases you want to take advantage the PhpStorm also supports the _directory_ `.phpstorm.meta.php/` which would parse any file places there, should your want provide additional files to PhpStorm. You can change the generated filename via the config `meta_filename`. This can be useful for cases where you want to take advantage of PhpStorm's support of the _directory_ `.phpstorm.meta.php/`: all files placed there are parsed, should you want to provide additional files to PhpStorm.
## Usage with Lumen ## Usage with Lumen
+8 -8
View File
@@ -23,27 +23,27 @@
"php": "^7.3 || ^8.0", "php": "^7.3 || ^8.0",
"ext-json": "*", "ext-json": "*",
"barryvdh/reflection-docblock": "^2.0.6", "barryvdh/reflection-docblock": "^2.0.6",
"composer/pcre": "^1 || ^2 || ^3", "composer/class-map-generator": "^1.0",
"doctrine/dbal": "^2.6 || ^3", "doctrine/dbal": "^2.6 || ^3",
"illuminate/console": "^8 || ^9", "illuminate/console": "^8 || ^9 || ^10",
"illuminate/filesystem": "^8 || ^9", "illuminate/filesystem": "^8 || ^9 || ^10",
"illuminate/support": "^8 || ^9", "illuminate/support": "^8 || ^9 || ^10",
"nikic/php-parser": "^4.7", "nikic/php-parser": "^4.7",
"phpdocumentor/type-resolver": "^1.1.0" "phpdocumentor/type-resolver": "^1.1.0"
}, },
"require-dev": { "require-dev": {
"ext-pdo_sqlite": "*", "ext-pdo_sqlite": "*",
"friendsofphp/php-cs-fixer": "^2", "friendsofphp/php-cs-fixer": "^2",
"illuminate/config": "^8 || ^9", "illuminate/config": "^8 || ^9 || ^10",
"illuminate/view": "^8 || ^9", "illuminate/view": "^8 || ^9 || ^10",
"mockery/mockery": "^1.4", "mockery/mockery": "^1.4",
"orchestra/testbench": "^6 || ^7", "orchestra/testbench": "^6 || ^7 || ^8",
"phpunit/phpunit": "^8.5 || ^9", "phpunit/phpunit": "^8.5 || ^9",
"spatie/phpunit-snapshot-assertions": "^3 || ^4", "spatie/phpunit-snapshot-assertions": "^3 || ^4",
"vimeo/psalm": "^3.12" "vimeo/psalm": "^3.12"
}, },
"suggest": { "suggest": {
"illuminate/events": "Required for automatic helper generation (^6|^7|^8|^9)." "illuminate/events": "Required for automatic helper generation (^6|^7|^8|^9|^10)."
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true, "prefer-stable": true,
+24
View File
@@ -292,6 +292,17 @@ return [
*/ */
'force_fqn' => false, 'force_fqn' => false,
/*
|--------------------------------------------------------------------------
| Use generics syntax
|--------------------------------------------------------------------------
|
| Use generics syntax within DocBlocks,
| e.g. `Collection<User>` instead of `Collection|User[]`.
|
*/
'use_generics_annotations' => true,
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Additional relation types | Additional relation types
@@ -304,6 +315,19 @@ return [
*/ */
'additional_relation_types' => [], 'additional_relation_types' => [],
/*
|--------------------------------------------------------------------------
| Additional relation return types
|--------------------------------------------------------------------------
|
| When using custom relation types its possible for the class name to not contain
| the proper return type of the relation. The key of the array is the relationship
| method name. The value of the array is the return type of the relation.
| e.g. `'relationName' => 'many'`.
|
*/
'additional_relation_return_types' => [],
/* /*
|-------------------------------------------------------------------------- |--------------------------------------------------------------------------
| Run artisan commands after migrations to generate model helpers | Run artisan commands after migrations to generate model helpers
+4
View File
@@ -28,6 +28,10 @@ namespace PHPSTORM_META {
])); ]));
<?php endif; ?> <?php endif; ?>
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::instance(0), type(1));
override(\Illuminate\Foundation\Testing\Concerns\InteractsWithContainer::spy(0), map(["" => "@&\Mockery\MockInterface"]));
override(\Illuminate\Support\Arr::add(0), type(0)); override(\Illuminate\Support\Arr::add(0), type(0));
override(\Illuminate\Support\Arr::except(0), type(0)); override(\Illuminate\Support\Arr::except(0), type(0));
override(\Illuminate\Support\Arr::first(0), elementType(0)); override(\Illuminate\Support\Arr::first(0), elementType(0));
-415
View File
@@ -1,415 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <[email protected]>
* Jordi Boggiano <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/*
* This file is copied from the Symfony package to composer/composer and then copied again here.
*
* (c) Fabien Potencier <[email protected]>
*/
namespace Barryvdh\LaravelIdeHelper;
use Composer\Pcre\Preg;
use Symfony\Component\Finder\Finder;
/**
* ClassMapGenerator
*
* @author Gyula Sallai <[email protected]>
* @author Jordi Boggiano <[email protected]>
*/
class ClassMapGenerator
{
/** @var array<array{name: string, length: int, pattern: non-empty-string}> */
private static $typeConfig;
/** @var non-empty-string */
private static $restPattern;
/**
* Generate a class map file
*
* @param \Traversable<string>|array<string> $dirs Directories or a single path to search in
* @param string $file The name of the class map file
* @return void
*/
public static function dump($dirs, $file)
{
$maps = [];
foreach ($dirs as $dir) {
$maps = array_merge($maps, static::createMap($dir));
}
file_put_contents($file, sprintf('<?php return %s;', var_export($maps, true)));
}
/**
* Checks if the given path is absolute
*
* @param string $path
* @return bool
*
* @see \Composer\Util\Filesystem
* @author Jordi Boggiano <[email protected]>
* @author Johannes M. Schmitt <[email protected]>
*/
public static function isAbsolutePath($path)
{
return substr($path, 0, 1) === '/' || substr($path, 1, 1) === ':' || substr($path, 0, 2) === '\\\\';
}
/**
* Normalize a path. This replaces backslashes with slashes, removes ending
* slash and collapses redundant separators and up-level references.
*
* @param string $path Path to the file or directory
* @return string
*
* @see \Composer\Util\Filesystem
* @author Jordi Boggiano <[email protected]>
* @author Johannes M. Schmitt <[email protected]>
*/
public static function normalizePath($path)
{
$parts = [];
$path = strtr($path, '\\', '/');
$prefix = '';
$absolute = false;
// extract a prefix being a protocol://, protocol:, protocol://drive: or simply drive:
if (preg_match('{^( [0-9a-z]{2,}+: (?: // (?: [a-z]: )? )? | [a-z]: )}ix', $path, $match)) {
$prefix = $match[1];
$path = substr($path, strlen($prefix));
}
if (substr($path, 0, 1) === '/') {
$absolute = true;
$path = substr($path, 1);
}
$up = false;
foreach (explode('/', $path) as $chunk) {
if ('..' === $chunk && ($absolute || $up)) {
array_pop($parts);
$up = !(empty($parts) || '..' === end($parts));
} elseif ('.' !== $chunk && '' !== $chunk) {
$parts[] = $chunk;
$up = '..' !== $chunk;
}
}
return $prefix . ($absolute ? '/' : '') . implode('/', $parts);
}
/**
* Iterate over all files in the given directory searching for classes
*
* @param \Traversable<\SplFileInfo>|string|array<string> $path The path to search in or an iterator
* @param string $excluded Regex that matches file paths to be excluded from the classmap
* @param ?\Composer\IO\IOInterface $io IO object
* @param ?string $namespace Optional namespace prefix to filter by
* @param ?string $autoloadType psr-0|psr-4 Optional autoload standard to use mapping rules
* @param array<string, true> $scannedFiles
* @return array<class-string, string> A class map array
* @throws \RuntimeException When the path is neither an existing file nor directory
*/
public static function createMap($path, $excluded = null, $io = null, $namespace = null, $autoloadType = null, &$scannedFiles = [])
{
$basePath = $path;
if (is_string($path)) {
if (is_file($path)) {
$path = [new \SplFileInfo($path)];
} elseif (is_dir($path) || strpos($path, '*') !== false) {
$path = Finder::create()->files()->followLinks()->name('/\.(php|inc|hh)$/')->in($path);
} else {
throw new \RuntimeException(
'Could not scan for classes inside "' . $path .
'" which does not appear to be a file nor a folder'
);
}
} elseif (null !== $autoloadType) {
throw new \RuntimeException('Path must be a string when specifying an autoload type');
}
$map = [];
$cwd = realpath(getcwd());
foreach ($path as $file) {
$filePath = $file->getPathname();
if (!in_array(pathinfo($filePath, PATHINFO_EXTENSION), ['php', 'inc', 'hh'])) {
continue;
}
if (!self::isAbsolutePath($filePath)) {
$filePath = $cwd . '/' . $filePath;
$filePath = self::normalizePath($filePath);
} else {
$filePath = Preg::replace('{[\\\\/]{2,}}', '/', $filePath);
}
$realPath = realpath($filePath);
// if a list of scanned files is given, avoid scanning twice the same file to save cycles and avoid generating warnings
// in case a PSR-0/4 declaration follows another more specific one, or a classmap declaration, which covered this file already
if (isset($scannedFiles[$realPath])) {
continue;
}
// check the realpath of the file against the excluded paths as the path might be a symlink and the excluded path is realpath'd so symlink are resolved
if ($excluded && Preg::isMatch($excluded, strtr($realPath, '\\', '/'))) {
continue;
}
// check non-realpath of file for directories symlink in project dir
if ($excluded && Preg::isMatch($excluded, strtr($filePath, '\\', '/'))) {
continue;
}
$classes = self::findClasses($filePath);
if (null !== $autoloadType) {
$classes = self::filterByNamespace($classes, $filePath, $namespace, $autoloadType, $basePath, $io);
// if no valid class was found in the file then we do not mark it as scanned as it might still be matched by another rule later
if ($classes) {
$scannedFiles[$realPath] = true;
}
} else {
// classmap autoload rules always collect all classes so for these we definitely do not want to scan again
$scannedFiles[$realPath] = true;
}
foreach ($classes as $class) {
// skip classes not within the given namespace prefix
if (null === $autoloadType && null !== $namespace && '' !== $namespace && 0 !== strpos($class, $namespace)) {
continue;
}
if (!isset($map[$class])) {
$map[$class] = $filePath;
} elseif ($io && $map[$class] !== $filePath && !Preg::isMatch('{/(test|fixture|example|stub)s?/}i', strtr($map[$class] . ' ' . $filePath, '\\', '/'))) {
$io->writeError(
'<warning>Warning: Ambiguous class resolution, "' . $class . '"' .
' was found in both "' . $map[$class] . '" and "' . $filePath . '", the first will be used.</warning>'
);
}
}
}
return $map;
}
/**
* Remove classes which could not have been loaded by namespace autoloaders
*
* @param array<int, class-string> $classes found classes in given file
* @param string $filePath current file
* @param string $baseNamespace prefix of given autoload mapping
* @param string $namespaceType psr-0|psr-4
* @param string $basePath root directory of given autoload mapping
* @param ?\Composer\IO\IOInterface $io IO object
* @return array<int, class-string> valid classes
*/
private static function filterByNamespace($classes, $filePath, $baseNamespace, $namespaceType, $basePath, $io)
{
$validClasses = [];
$rejectedClasses = [];
$realSubPath = substr($filePath, strlen($basePath) + 1);
$dotPosition = strrpos($realSubPath, '.');
$realSubPath = substr($realSubPath, 0, $dotPosition === false ? PHP_INT_MAX : $dotPosition);
foreach ($classes as $class) {
// silently skip if ns doesn't have common root
if ('' !== $baseNamespace && 0 !== strpos($class, $baseNamespace)) {
continue;
}
// transform class name to file path and validate
if ('psr-0' === $namespaceType) {
$namespaceLength = strrpos($class, '\\');
if (false !== $namespaceLength) {
$namespace = substr($class, 0, $namespaceLength + 1);
$className = substr($class, $namespaceLength + 1);
$subPath = str_replace('\\', DIRECTORY_SEPARATOR, $namespace)
. str_replace('_', DIRECTORY_SEPARATOR, $className);
} else {
$subPath = str_replace('_', DIRECTORY_SEPARATOR, $class);
}
} elseif ('psr-4' === $namespaceType) {
$subNamespace = ('' !== $baseNamespace) ? substr($class, strlen($baseNamespace)) : $class;
$subPath = str_replace('\\', DIRECTORY_SEPARATOR, $subNamespace);
} else {
throw new \RuntimeException("namespaceType must be psr-0 or psr-4, $namespaceType given");
}
if ($subPath === $realSubPath) {
$validClasses[] = $class;
} else {
$rejectedClasses[] = $class;
}
}
// warn only if no valid classes, else silently skip invalid
if (empty($validClasses)) {
foreach ($rejectedClasses as $class) {
if ($io) {
$io->writeError("<warning>Class $class located in " . Preg::replace('{^' . preg_quote(getcwd()) . '}', '.', $filePath, 1) . " does not comply with $namespaceType autoloading standard. Skipping.</warning>");
}
}
return [];
}
return $validClasses;
}
/**
* Extract the classes in the given file
*
* @param string $path The file to check
* @throws \RuntimeException
* @return array<int, class-string> The found classes
*/
private static function findClasses($path)
{
$extraTypes = self::getExtraTypes();
// Use @ here instead of Silencer to actively suppress 'unhelpful' output
// @link https://github.com/composer/composer/pull/4886
$contents = @php_strip_whitespace($path);
if (!$contents) {
if (!file_exists($path)) {
$message = 'File at "%s" does not exist, check your classmap definitions';
} elseif (!is_readable($path)) {
$message = 'File at "%s" is not readable, check its permissions';
} elseif ('' === trim((string) file_get_contents($path))) {
// The input file was really empty and thus contains no classes
return [];
} else {
$message = 'File at "%s" could not be parsed as PHP, it may be binary or corrupted';
}
$error = error_get_last();
if (isset($error['message'])) {
$message .= PHP_EOL . 'The following message may be helpful:' . PHP_EOL . $error['message'];
}
throw new \RuntimeException(sprintf($message, $path));
}
// return early if there is no chance of matching anything in this file
Preg::matchAll('{\b(?:class|interface|trait' . $extraTypes . ')\s}i', $contents, $matches);
if (!$matches) {
return [];
}
// strip heredocs/nowdocs
$contents = preg_replace('{<<<[ \t]*([\'"]?)(\w+)\\1(?:\r\n|\n|\r)(?:.*?)(?:\r\n|\n|\r)(?:\s*)\\2(?=\s+|[;,.)])}s', 'null', $contents);
// strip strings
$contents = preg_replace('{"[^"\\\\]*+(\\\\.[^"\\\\]*+)*+"|\'[^\'\\\\]*+(\\\\.[^\'\\\\]*+)*+\'}s', 'null', $contents);
// strip leading non-php code if needed
if (substr($contents, 0, 2) !== '<?') {
$contents = preg_replace('{^.+?<\?}s', '<?', $contents, 1, $replacements);
if ($replacements === 0) {
return [];
}
}
// strip non-php blocks in the file
$contents = preg_replace('{\?>(?:[^<]++|<(?!\?))*+<\?}s', '?><?', $contents);
// strip trailing non-php code if needed
$pos = strrpos($contents, '?>');
if (false !== $pos && false === strpos(substr($contents, $pos), '<?')) {
$contents = substr($contents, 0, $pos);
}
// strip comments if short open tags are in the file
if (preg_match('{(<\?)(?!(php|hh))}i', $contents)) {
$contents = preg_replace('{//.* | /\*(?:[^*]++|\*(?!/))*\*/}x', '', $contents);
}
Preg::matchAll('{
(?:
\b(?<![\$:>])(?P<type>class|interface|trait' . $extraTypes . ') \s++ (?P<name>[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+)
| \b(?<![\$:>])(?P<ns>namespace) (?P<nsname>\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;]
)
}ix', $contents, $matches);
$classes = [];
$namespace = '';
for ($i = 0, $len = count($matches['type']); $i < $len; $i++) {
if (!empty($matches['ns'][$i])) {
$namespace = str_replace([' ', "\t", "\r", "\n"], '', $matches['nsname'][$i]) . '\\';
} else {
$name = $matches['name'][$i];
// skip anon classes extending/implementing
if ($name === 'extends' || $name === 'implements') {
continue;
}
if ($name[0] === ':') {
// This is an XHP class, https://github.com/facebook/xhp
$name = 'xhp' . substr(str_replace(['-', ':'], ['_', '__'], $name), 1);
} elseif ($matches['type'][$i] === 'enum') {
// something like:
// enum Foo: int { HERP = '123'; }
// The regex above captures the colon, which isn't part of
// the class name.
// or:
// enum Foo:int { HERP = '123'; }
// The regex above captures the colon and type, which isn't part of
// the class name.
$colonPos = strrpos($name, ':');
if (false !== $colonPos) {
$name = substr($name, 0, $colonPos);
}
}
$classes[] = ltrim($namespace . $name, '\\');
}
}
return $classes;
}
/**
* @return string
*/
private static function getExtraTypes()
{
static $extraTypes = null;
if (null === $extraTypes) {
$extraTypes = '';
if (PHP_VERSION_ID >= 80100 || (defined('HHVM_VERSION') && version_compare(HHVM_VERSION, '3.3', '>='))) {
$extraTypes .= '|enum';
}
self::setTypeConfig(array_merge(['class', 'interface', 'trait'], array_filter(explode('|', $extraTypes))));
}
return $extraTypes;
}
/**
* @param string[] $types
* @return void
*
* @see \Composer\Autoload\PhpFileCleaner
* @author Jordi Boggiano <[email protected]>
* @author Johannes M. Schmitt <[email protected]>
*/
private static function setTypeConfig($types)
{
foreach ($types as $type) {
self::$typeConfig[$type[0]] = [
'name' => $type,
'length' => strlen($type),
'pattern' => '{.\b(?<![\$:>])' . $type . '\s++[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+}Ais',
];
}
self::$restPattern = '{[^?"\'</' . implode('', array_keys(self::$typeConfig)) . ']+}A';
}
}
+6
View File
@@ -13,6 +13,7 @@ namespace Barryvdh\LaravelIdeHelper\Console;
use Barryvdh\LaravelIdeHelper\Factories; use Barryvdh\LaravelIdeHelper\Factories;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use RuntimeException;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@@ -95,6 +96,11 @@ class MetaCommand extends Command
try { try {
$concrete = $this->laravel->make($abstract); $concrete = $this->laravel->make($abstract);
if ($concrete === null) {
throw new RuntimeException("Cannot create instance for '$abstract', received 'null'");
}
$reflectionClass = new \ReflectionClass($concrete); $reflectionClass = new \ReflectionClass($concrete);
if (is_object($concrete) && !$reflectionClass->isAnonymous()) { if (is_object($concrete) && !$reflectionClass->isAnonymous()) {
$bindings[$abstract] = get_class($concrete); $bindings[$abstract] = get_class($concrete);
+66 -15
View File
@@ -11,17 +11,18 @@
namespace Barryvdh\LaravelIdeHelper\Console; namespace Barryvdh\LaravelIdeHelper\Console;
use Barryvdh\LaravelIdeHelper\ClassMapGenerator;
use Barryvdh\LaravelIdeHelper\Contracts\ModelHookInterface; use Barryvdh\LaravelIdeHelper\Contracts\ModelHookInterface;
use Barryvdh\Reflection\DocBlock; use Barryvdh\Reflection\DocBlock;
use Barryvdh\Reflection\DocBlock\Context; use Barryvdh\Reflection\DocBlock\Context;
use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer; use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer;
use Barryvdh\Reflection\DocBlock\Tag; use Barryvdh\Reflection\DocBlock\Tag;
use Composer\ClassMapGenerator\ClassMapGenerator;
use Doctrine\DBAL\Exception as DBALException; use Doctrine\DBAL\Exception as DBALException;
use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Types\Type;
use Illuminate\Console\Command; use Illuminate\Console\Command;
use Illuminate\Contracts\Database\Eloquent\Castable; use Illuminate\Contracts\Database\Eloquent\Castable;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes; use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@@ -429,6 +430,9 @@ class ModelsCommand extends Command
if (!isset($this->properties[$name])) { if (!isset($this->properties[$name])) {
continue; continue;
} }
if ($this->isInboundCast($realType)) {
continue;
}
$realType = $this->checkForCastableCasts($realType, $params); $realType = $this->checkForCastableCasts($realType, $params);
$realType = $this->checkForCustomLaravelCasts($realType); $realType = $this->checkForCustomLaravelCasts($realType);
@@ -463,6 +467,7 @@ class ModelsCommand extends Command
*/ */
public function getPropertiesFromTable($model) public function getPropertiesFromTable($model)
{ {
$database = $model->getConnection()->getDatabaseName();
$table = $model->getConnection()->getTablePrefix() . $model->getTable(); $table = $model->getConnection()->getTablePrefix() . $model->getTable();
$schema = $model->getConnection()->getDoctrineSchemaManager(); $schema = $model->getConnection()->getDoctrineSchemaManager();
$databasePlatform = $schema->getDatabasePlatform(); $databasePlatform = $schema->getDatabasePlatform();
@@ -482,11 +487,6 @@ class ModelsCommand extends Command
$databasePlatform->registerDoctrineTypeMapping($yourTypeName, $doctrineTypeName); $databasePlatform->registerDoctrineTypeMapping($yourTypeName, $doctrineTypeName);
} }
$database = null;
if (strpos($table, '.')) {
[$database, $table] = explode('.', $table);
}
$columns = $schema->listTableColumns($table, $database); $columns = $schema->listTableColumns($table, $database);
if (!$columns) { if (!$columns) {
@@ -702,7 +702,10 @@ class ModelsCommand extends Command
get_class($relationObj->getRelated()) get_class($relationObj->getRelated())
); );
if (strpos(get_class($relationObj), 'Many') !== false) { if (
strpos(get_class($relationObj), 'Many') !== false ||
($this->getRelationReturnTypes()[$relation] ?? '') === 'many'
) {
//Collection or array of models (because Collection is Arrayable) //Collection or array of models (because Collection is Arrayable)
$relatedClass = '\\' . get_class($relationObj->getRelated()); $relatedClass = '\\' . get_class($relationObj->getRelated());
$collectionClass = $this->getCollectionClass($relatedClass); $collectionClass = $this->getCollectionClass($relatedClass);
@@ -710,9 +713,10 @@ class ModelsCommand extends Command
$model, $model,
$collectionClass $collectionClass
); );
$collectionTypeHint = $this->getCollectionTypeHint($collectionClassNameInModel, $relatedModel);
$this->setProperty( $this->setProperty(
$method, $method,
$collectionClassNameInModel . '|' . $relatedModel . '[]', $collectionTypeHint,
true, true,
null, null,
$comment $comment
@@ -726,7 +730,10 @@ class ModelsCommand extends Command
// What kind of comments should be added to the relation count here? // What kind of comments should be added to the relation count here?
); );
} }
} elseif ($relation === 'morphTo') { } elseif (
$relation === 'morphTo' ||
($this->getRelationReturnTypes()[$relation] ?? '') === 'morphTo'
) {
// Model isn't specified because relation is polymorphic // Model isn't specified because relation is polymorphic
$this->setProperty( $this->setProperty(
$method, $method,
@@ -924,10 +931,19 @@ class ModelsCommand extends Command
$phpdoc->appendTag($tag); $phpdoc->appendTag($tag);
} }
if ($this->write && !$phpdoc->getTagsByName('mixin')) { if ($this->write) {
$eloquentClassNameInModel = $this->getClassNameInDestinationFile($reflection, 'Eloquent'); $eloquentClassNameInModel = $this->getClassNameInDestinationFile($reflection, 'Eloquent');
// remove the already existing tag to prevent duplicates
foreach ($phpdoc->getTagsByName('mixin') as $tag) {
if ($tag->getContent() === $eloquentClassNameInModel) {
$phpdoc->deleteTag($tag);
}
}
$phpdoc->appendTag(Tag::createInstance('@mixin ' . $eloquentClassNameInModel, $phpdoc)); $phpdoc->appendTag(Tag::createInstance('@mixin ' . $eloquentClassNameInModel, $phpdoc));
} }
if ($this->phpstorm_noinspections) { if ($this->phpstorm_noinspections) {
/** /**
* Facades, Eloquent API * Facades, Eloquent API
@@ -1065,6 +1081,23 @@ class ModelsCommand extends Command
return '\\' . get_class($model->newCollection()); return '\\' . get_class($model->newCollection());
} }
/**
* Determine a model classes' collection type hint.
*
* @param string $collectionClassNameInModel
* @param string $relatedModel
* @return string
*/
protected function getCollectionTypeHint(string $collectionClassNameInModel, string $relatedModel): string
{
$useGenericsSyntax = $this->laravel['config']->get('ide-helper.use_generics_annotations', true);
if ($useGenericsSyntax) {
return $collectionClassNameInModel . '<int, ' . $relatedModel . '>';
} else {
return $collectionClassNameInModel . '|' . $relatedModel . '[]';
}
}
/** /**
* Returns the available relation types * Returns the available relation types
*/ */
@@ -1074,6 +1107,14 @@ class ModelsCommand extends Command
return array_merge(self::RELATION_TYPES, $configuredRelations); return array_merge(self::RELATION_TYPES, $configuredRelations);
} }
/**
* Returns the return types of relations
*/
protected function getRelationReturnTypes(): array
{
return $this->laravel['config']->get('ide-helper.additional_relation_return_types', []);
}
/** /**
* @return bool * @return bool
*/ */
@@ -1198,7 +1239,7 @@ class ModelsCommand extends Command
$traits = class_uses_recursive($model); $traits = class_uses_recursive($model);
if (in_array('Illuminate\\Database\\Eloquent\\SoftDeletes', $traits)) { if (in_array('Illuminate\\Database\\Eloquent\\SoftDeletes', $traits)) {
$modelName = $this->getClassNameInDestinationFile($model, get_class($model)); $modelName = $this->getClassNameInDestinationFile($model, get_class($model));
$builder = $this->getClassNameInDestinationFile($model, \Illuminate\Database\Query\Builder::class); $builder = $this->getClassNameInDestinationFile($model, \Illuminate\Database\Eloquent\Builder::class);
$this->setMethod('withTrashed', $builder . '|' . $modelName, []); $this->setMethod('withTrashed', $builder . '|' . $modelName, []);
$this->setMethod('withoutTrashed', $builder . '|' . $modelName, []); $this->setMethod('withoutTrashed', $builder . '|' . $modelName, []);
$this->setMethod('onlyTrashed', $builder . '|' . $modelName, []); $this->setMethod('onlyTrashed', $builder . '|' . $modelName, []);
@@ -1236,7 +1277,11 @@ class ModelsCommand extends Command
return; return;
} }
$this->setMethod('factory', $factory, ['...$parameters']); if (version_compare($this->laravel->version(), '9', '>=')) {
$this->setMethod('factory', $factory, ['$count = null, $state = []']);
} else {
$this->setMethod('factory', $factory, ['...$parameters']);
}
} }
/** /**
@@ -1250,8 +1295,9 @@ class ModelsCommand extends Command
if ($collectionClass !== '\\' . \Illuminate\Database\Eloquent\Collection::class) { if ($collectionClass !== '\\' . \Illuminate\Database\Eloquent\Collection::class) {
$collectionClassInModel = $this->getClassNameInDestinationFile($model, $collectionClass); $collectionClassInModel = $this->getClassNameInDestinationFile($model, $collectionClass);
$this->setMethod('get', $collectionClassInModel . '|static[]', ['$columns = [\'*\']']); $collectionTypeHint = $this->getCollectionTypeHint($collectionClassInModel, 'static');
$this->setMethod('all', $collectionClassInModel . '|static[]', ['$columns = [\'*\']']); $this->setMethod('get', $collectionTypeHint, ['$columns = [\'*\']']);
$this->setMethod('all', $collectionTypeHint, ['$columns = [\'*\']']);
} }
} }
@@ -1272,6 +1318,11 @@ class ModelsCommand extends Command
return $keyword; return $keyword;
} }
protected function isInboundCast(string $type): bool
{
return class_exists($type) && is_subclass_of($type, CastsInboundAttributes::class);
}
protected function checkForCastableCasts(string $type, array $params = []): string protected function checkForCastableCasts(string $type, array $params = []): string
{ {
if (!class_exists($type) || !interface_exists(Castable::class)) { if (!class_exists($type) || !interface_exists(Castable::class)) {
@@ -1296,7 +1347,7 @@ class ModelsCommand extends Command
return $this->getReturnTypeFromReflection($methodReflection) ?? return $this->getReturnTypeFromReflection($methodReflection) ??
$this->getReturnTypeFromDocBlock($methodReflection, $reflection) ?? $this->getReturnTypeFromDocBlock($methodReflection, $reflection) ??
'mixed'; $type;
} }
/** /**
@@ -21,7 +21,7 @@ use Illuminate\Database\Eloquent\Relations\MorphTo;
* This is second line, success too. * This is second line, success too.
* @property-read string $many_format_comment There is format comment, success. * @property-read string $many_format_comment There is format comment, success.
* @property-read string $not_comment * @property-read string $not_comment
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $relationHasMany HasMany relations. * @property-read \Illuminate\Database\Eloquent\Collection<int, Simple> $relationHasMany HasMany relations.
* @property-read int|null $relation_has_many_count * @property-read int|null $relation_has_many_count
* @property-read Simple|null $relationHasOne Others relations. * @property-read Simple|null $relationHasOne Others relations.
* @property-read Model|\Eloquent $relationMorphTo MorphTo relations. * @property-read Model|\Eloquent $relationMorphTo MorphTo relations.
@@ -12,10 +12,10 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\CustomCollection\Models\Simple * Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\CustomCollection\Models\Simple
* *
* @property integer $id * @property integer $id
* @property-read SimpleCollection|Simple[] $relationHasMany * @property-read SimpleCollection<int, Simple> $relationHasMany
* @property-read int|null $relation_has_many_count * @property-read int|null $relation_has_many_count
* @method static SimpleCollection|static[] all($columns = ['*']) * @method static SimpleCollection<int, static> all($columns = ['*'])
* @method static SimpleCollection|static[] get($columns = ['*']) * @method static SimpleCollection<int, static> get($columns = ['*'])
* @method static \Illuminate\Database\Eloquent\Builder|Simple newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|Simple newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Simple newQuery() * @method static \Illuminate\Database\Eloquent\Builder|Simple newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Simple query() * @method static \Illuminate\Database\Eloquent\Builder|Simple query()
@@ -12,7 +12,7 @@ use Illuminate\Database\Eloquent\Relations\HasOne;
/** /**
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\DynamicRelations\Models\Dynamic * Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\DynamicRelations\Models\Dynamic
* *
* @property-read \Illuminate\Database\Eloquent\Collection|Dynamic[] $regularHasMany * @property-read \Illuminate\Database\Eloquent\Collection<int, Dynamic> $regularHasMany
* @property-read int|null $regular_has_many_count * @property-read int|null $regular_has_many_count
* @method static \Illuminate\Database\Eloquent\Builder|Dynamic newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|Dynamic newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Dynamic newQuery() * @method static \Illuminate\Database\Eloquent\Builder|Dynamic newQuery()
+25 -3
View File
@@ -13,11 +13,33 @@ use Illuminate\Support\Str;
class Test extends AbstractModelsCommand class Test extends AbstractModelsCommand
{ {
public function test(): void public function test_8(): void
{ {
if (!version_compare(Application::VERSION, '8.2', '>=')) { if (!version_compare(Application::VERSION, '8.2', '>=') || !version_compare(Application::VERSION, '9', '<')) {
$this->markTestSkipped( $this->markTestSkipped(
'This test only works in Laravel >= 8.2' 'This test only works in Laravel >= 8.2 and < 9'
);
}
Factory::guessFactoryNamesUsing(static::getFactoryNameResolver());
$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->assertStringNotContainsString('not found', $tester->getDisplay());
$this->assertMatchesMockedSnapshot();
}
public function test_9(): void
{
if (!version_compare(Application::VERSION, '9', '>=')) {
$this->markTestSkipped(
'This test only works in Laravel >= 9'
); );
} }
@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Models;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\CustomSpace\ModelWithCustomNamespaceFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
/**
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Models\ModelWithCustomNamespace
*
* @method static \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\CustomSpace\ModelWithCustomNamespaceFactory factory($count = null, $state = [])
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithCustomNamespace newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithCustomNamespace newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithCustomNamespace query()
* @mixin \Eloquent
*/
class ModelWithCustomNamespace extends Model
{
use HasFactory;
/**
* Create a new factory instance for the model.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
protected static function newFactory()
{
return ModelWithCustomNamespaceFactory::new();
}
}
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
/**
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Models\ModelWithFactory
*
* @method static \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Factories\ModelWithFactoryFactory factory($count = null, $state = [])
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithFactory newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithFactory newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithFactory query()
* @mixin \Eloquent
*/
class ModelWithFactory extends Model
{
use HasFactory;
}
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Models;
/**
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Models\ModelWithNestedFactory
*
* @method static \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Factories\ModelWithNestedFactoryFactory factory($count = null, $state = [])
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithNestedFactory newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithNestedFactory newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithNestedFactory query()
* @mixin \Eloquent
*/
class ModelWithNestedFactory extends ModelWithFactory
{
}
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
/**
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Factories\Models\ModelWithoutFactory
*
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithoutFactory newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithoutFactory newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|ModelWithoutFactory query()
* @mixin \Eloquent
*/
class ModelWithoutFactory extends Model
{
use HasFactory;
}
@@ -84,12 +84,12 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property string $macaddress_not_nullable * @property string $macaddress_not_nullable
* @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post[] $posts * @property-read \Illuminate\Database\Eloquent\Collection<int, \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post> $posts
* @property-read int|null $posts_count * @property-read int|null $posts_count
* @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post newQuery() * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post null(string $unusedParam) * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post null(string $unusedParam)
* @method static \Illuminate\Database\Query\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post onlyTrashed() * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post query() * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post query()
* @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereBigIntegerNotNullable($value) * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereBigIntegerNotNullable($value)
* @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereBigIntegerNullable($value) * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereBigIntegerNullable($value)
@@ -164,8 +164,8 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereUuidNullable($value) * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereUuidNullable($value)
* @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereYearNotNullable($value) * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereYearNotNullable($value)
* @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereYearNullable($value) * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post whereYearNullable($value)
* @method static \Illuminate\Database\Query\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post withTrashed() * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post withTrashed()
* @method static \Illuminate\Database\Query\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post withoutTrashed() * @method static \Illuminate\Database\Eloquent\Builder|\Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GeneratePhpdocWithForcedFqn\Models\Post withoutTrashed()
* @mixin \Eloquent * @mixin \Eloquent
*/ */
class Post extends Model class Post extends Model
@@ -90,12 +90,12 @@ use Illuminate\Support\Carbon;
* @property string $macaddress_not_nullable * @property string $macaddress_not_nullable
* @property Carbon|null $created_at * @property Carbon|null $created_at
* @property Carbon|null $updated_at * @property Carbon|null $updated_at
* @property-read Collection|Post[] $posts * @property-read Collection<int, Post> $posts
* @property-read int|null $posts_count * @property-read int|null $posts_count
* @method static EloquentBuilder|Post newModelQuery() * @method static EloquentBuilder|Post newModelQuery()
* @method static EloquentBuilder|Post newQuery() * @method static EloquentBuilder|Post newQuery()
* @method static EloquentBuilder|Post null(string $unusedParam) * @method static EloquentBuilder|Post null(string $unusedParam)
* @method static QueryBuilder|Post onlyTrashed() * @method static EloquentBuilder|Post onlyTrashed()
* @method static EloquentBuilder|Post query() * @method static EloquentBuilder|Post query()
* @method static EloquentBuilder|Post whereBigIntegerNotNullable($value) * @method static EloquentBuilder|Post whereBigIntegerNotNullable($value)
* @method static EloquentBuilder|Post whereBigIntegerNullable($value) * @method static EloquentBuilder|Post whereBigIntegerNullable($value)
@@ -170,8 +170,8 @@ use Illuminate\Support\Carbon;
* @method static EloquentBuilder|Post whereUuidNullable($value) * @method static EloquentBuilder|Post whereUuidNullable($value)
* @method static EloquentBuilder|Post whereYearNotNullable($value) * @method static EloquentBuilder|Post whereYearNotNullable($value)
* @method static EloquentBuilder|Post whereYearNullable($value) * @method static EloquentBuilder|Post whereYearNullable($value)
* @method static QueryBuilder|Post withTrashed() * @method static EloquentBuilder|Post withTrashed()
* @method static QueryBuilder|Post withoutTrashed() * @method static EloquentBuilder|Post withoutTrashed()
* @mixin Eloquent * @mixin Eloquent
*/ */
class Post extends Model class Post extends Model
@@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\Model;
/** /**
* @property $someProp * @property $someProp
* @method someMethod(string $method) * @method someMethod(string $method)
* @mixin IdeHelperPost
*/ */
class Post extends Model class Post extends Model
{ {
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GenericsSyntaxDisabled\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Simple extends Model
{
// Regular relations
public function regularHasMany(): HasMany
{
return $this->hasMany(Simple::class);
}
public function regularBelongsToMany(): BelongsToMany
{
return $this->belongsToMany(Simple::class);
}
}
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GenericsSyntaxDisabled;
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.use_generics_annotations', 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();
}
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GenericsSyntaxDisabled\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\GenericsSyntaxDisabled\Models\Simple
*
* @property integer $id
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $regularBelongsToMany
* @property-read int|null $regular_belongs_to_many_count
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $regularHasMany
* @property-read int|null $regular_has_many_count
* @method static \Illuminate\Database\Eloquent\Builder|Simple newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Simple newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Simple query()
* @method static \Illuminate\Database\Eloquent\Builder|Simple whereId($value)
* @mixin \Eloquent
*/
class Simple extends Model
{
// Regular relations
public function regularHasMany(): HasMany
{
return $this->hasMany(Simple::class);
}
public function regularBelongsToMany(): BelongsToMany
{
return $this->belongsToMany(Simple::class);
}
}
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsInboundAttributes;
class InboundAttributeCaster implements CastsInboundAttributes
{
public function set($model, string $key, $value, array $attributes)
{
// TODO: Implement set() method.
}
}
@@ -17,6 +17,7 @@ use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Cas
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CustomCasterWithReturnType; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CustomCasterWithReturnType;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\ExtendedSelfCastingCasterWithStaticDocblockReturn; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\ExtendedSelfCastingCasterWithStaticDocblockReturn;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\ExtendedSelfCastingCasterWithThisDocblockReturn; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\ExtendedSelfCastingCasterWithThisDocblockReturn;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\InboundAttributeCaster;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\SelfCastingCasterWithStaticDocblockReturn; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\SelfCastingCasterWithStaticDocblockReturn;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\SelfCastingCasterWithThisDocblockReturn; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\SelfCastingCasterWithThisDocblockReturn;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@@ -41,5 +42,6 @@ class CustomCast extends Model
'extended_casted_property_with_this_return_docblock' => ExtendedSelfCastingCasterWithThisDocblockReturn::class, 'extended_casted_property_with_this_return_docblock' => ExtendedSelfCastingCasterWithThisDocblockReturn::class,
'casted_property_with_static_return_docblock_and_param' => SelfCastingCasterWithStaticDocblockReturn::class . ':param', 'casted_property_with_static_return_docblock_and_param' => SelfCastingCasterWithStaticDocblockReturn::class . ':param',
'cast_without_property' => CustomCasterWithReturnType::class, 'cast_without_property' => CustomCasterWithReturnType::class,
'cast_inbound_attribute' => InboundAttributeCaster::class,
]; ];
} }
@@ -17,6 +17,7 @@ use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Cas
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CustomCasterWithReturnType; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CustomCasterWithReturnType;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\ExtendedSelfCastingCasterWithStaticDocblockReturn; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\ExtendedSelfCastingCasterWithStaticDocblockReturn;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\ExtendedSelfCastingCasterWithThisDocblockReturn; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\ExtendedSelfCastingCasterWithThisDocblockReturn;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\InboundAttributeCaster;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\SelfCastingCasterWithStaticDocblockReturn; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\SelfCastingCasterWithStaticDocblockReturn;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\SelfCastingCasterWithThisDocblockReturn; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\SelfCastingCasterWithThisDocblockReturn;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
@@ -39,8 +40,9 @@ use Illuminate\Database\Eloquent\Model;
* @property SelfCastingCasterWithStaticDocblockReturn $casted_property_with_static_return_docblock_and_param * @property SelfCastingCasterWithStaticDocblockReturn $casted_property_with_static_return_docblock_and_param
* @property \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CastedProperty $casted_property_with_castable * @property \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CastedProperty $casted_property_with_castable
* @property \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CastedProperty $casted_property_with_anonymous_cast * @property \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CastedProperty $casted_property_with_anonymous_cast
* @property mixed $casted_property_without_return_type * @property CastableWithoutReturnType $casted_property_without_return_type
* @property \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CastedProperty $cast_without_property * @property \Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\LaravelCustomCasts\Casts\CastedProperty $cast_without_property
* @property mixed $cast_inbound_attribute
* @method static \Illuminate\Database\Eloquent\Builder|CustomCast newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|CustomCast newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|CustomCast newQuery() * @method static \Illuminate\Database\Eloquent\Builder|CustomCast newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|CustomCast query() * @method static \Illuminate\Database\Eloquent\Builder|CustomCast query()
@@ -79,5 +81,6 @@ class CustomCast extends Model
'extended_casted_property_with_this_return_docblock' => ExtendedSelfCastingCasterWithThisDocblockReturn::class, 'extended_casted_property_with_this_return_docblock' => ExtendedSelfCastingCasterWithThisDocblockReturn::class,
'casted_property_with_static_return_docblock_and_param' => SelfCastingCasterWithStaticDocblockReturn::class . ':param', 'casted_property_with_static_return_docblock_and_param' => SelfCastingCasterWithStaticDocblockReturn::class . ':param',
'cast_without_property' => CustomCasterWithReturnType::class, 'cast_without_property' => CustomCasterWithReturnType::class,
'cast_inbound_attribute' => InboundAttributeCaster::class,
]; ];
} }
@@ -83,7 +83,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
* @property string $macaddress_not_nullable * @property string $macaddress_not_nullable
* @property \Illuminate\Support\Carbon|null $created_at * @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at * @property \Illuminate\Support\Carbon|null $updated_at
* @property-read \Illuminate\Database\Eloquent\Collection|Post[] $relationHasMany * @property-read \Illuminate\Database\Eloquent\Collection<int, Post> $relationHasMany
* @method static \Illuminate\Database\Eloquent\Builder|Post newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|Post newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Post newQuery() * @method static \Illuminate\Database\Eloquent\Builder|Post newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Post query() * @method static \Illuminate\Database\Eloquent\Builder|Post query()
@@ -97,4 +97,14 @@ class Simple extends Model
{ {
return $this->testToManyRelation(Simple::class); return $this->testToManyRelation(Simple::class);
} }
public function relationSampleToAnyRelationType()
{
return $this->testToAnyRelation(Simple::class);
}
public function relationSampleToAnyMorphedRelationType()
{
return $this->testToAnyMorphedRelation(Simple::class);
}
} }
@@ -6,6 +6,7 @@ namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations;
use Barryvdh\LaravelIdeHelper\Console\ModelsCommand; use Barryvdh\LaravelIdeHelper\Console\ModelsCommand;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\AbstractModelsCommand;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToAnyRelationType;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToManyRelationType; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToManyRelationType;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToOneRelationType; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToOneRelationType;
use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Config;
@@ -19,6 +20,13 @@ class Test extends AbstractModelsCommand
Config::set('ide-helper.additional_relation_types', [ Config::set('ide-helper.additional_relation_types', [
'testToOneRelation' => SampleToOneRelationType::class, 'testToOneRelation' => SampleToOneRelationType::class,
'testToManyRelation' => SampleToManyRelationType::class, 'testToManyRelation' => SampleToManyRelationType::class,
'testToAnyRelation' => SampleToAnyRelationType::class,
'testToAnyMorphedRelation' => SampleToAnyMorphedRelationType::class,
]);
Config::set('ide-helper.additional_relation_return_types', [
'testToAnyRelation' => 'many',
'testToAnyMorphedRelation' => 'morphTo',
]); ]);
} }
@@ -4,6 +4,8 @@ declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Traits; namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Traits;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToAnyMorphedRelationType;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToAnyRelationType;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToManyRelationType; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToManyRelationType;
use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToOneRelationType; use Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types\SampleToOneRelationType;
@@ -20,4 +22,16 @@ trait HasTestRelations
$instance = $this->newRelatedInstance($related); $instance = $this->newRelatedInstance($related);
return new SampleToManyRelationType($instance->newQuery(), $this); return new SampleToManyRelationType($instance->newQuery(), $this);
} }
public function testToAnyRelation($related)
{
$instance = $this->newRelatedInstance($related);
return new SampleToAnyRelationType($instance->newQuery(), $this);
}
public function testToAnyMorphedRelation($related)
{
$instance = $this->newRelatedInstance($related);
return new SampleToAnyMorphedRelationType($instance->newQuery(), $this);
}
} }
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\Relation;
class SampleToAnyMorphedRelationType extends Relation
{
public function addConstraints()
{
// Fake
}
public function addEagerConstraints(array $models)
{
// Fake
}
public function initRelation(array $models, $relation)
{
// Fake
}
public function match(array $models, Collection $results, $relation)
{
// Fake
}
public function getResults()
{
// Fake
}
}
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\Relations\Types;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\Relation;
class SampleToAnyRelationType extends Relation
{
public function addConstraints()
{
// Fake
}
public function addEagerConstraints(array $models)
{
// Fake
}
public function initRelation(array $models, $relation)
{
// Fake
}
public function match(array $models, Collection $results, $relation)
{
// Fake
}
public function getResults()
{
// Fake
}
}
@@ -75,25 +75,28 @@ use Illuminate\Database\Eloquent\Relations\MorphToMany;
* @property integer $id * @property integer $id
* @property-read Simple|null $relationBelongsTo * @property-read Simple|null $relationBelongsTo
* @property-read AnotherModel|null $relationBelongsToInAnotherNamespace * @property-read AnotherModel|null $relationBelongsToInAnotherNamespace
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $relationBelongsToMany * @property-read \Illuminate\Database\Eloquent\Collection<int, Simple> $relationBelongsToMany
* @property-read int|null $relation_belongs_to_many_count * @property-read int|null $relation_belongs_to_many_count
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $relationBelongsToManyWithSub * @property-read \Illuminate\Database\Eloquent\Collection<int, Simple> $relationBelongsToManyWithSub
* @property-read int|null $relation_belongs_to_many_with_sub_count * @property-read int|null $relation_belongs_to_many_with_sub_count
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $relationBelongsToManyWithSubAnother * @property-read \Illuminate\Database\Eloquent\Collection<int, Simple> $relationBelongsToManyWithSubAnother
* @property-read int|null $relation_belongs_to_many_with_sub_another_count * @property-read int|null $relation_belongs_to_many_with_sub_another_count
* @property-read AnotherModel|null $relationBelongsToSameNameAsColumn * @property-read AnotherModel|null $relationBelongsToSameNameAsColumn
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $relationHasMany * @property-read \Illuminate\Database\Eloquent\Collection<int, Simple> $relationHasMany
* @property-read int|null $relation_has_many_count * @property-read int|null $relation_has_many_count
* @property-read Simple|null $relationHasOne * @property-read Simple|null $relationHasOne
* @property-read Simple $relationHasOneWithDefault * @property-read Simple $relationHasOneWithDefault
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $relationMorphMany * @property-read \Illuminate\Database\Eloquent\Collection<int, Simple> $relationMorphMany
* @property-read int|null $relation_morph_many_count * @property-read int|null $relation_morph_many_count
* @property-read Simple|null $relationMorphOne * @property-read Simple|null $relationMorphOne
* @property-read Model|\Eloquent $relationMorphTo * @property-read Model|\Eloquent $relationMorphTo
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $relationMorphedByMany * @property-read \Illuminate\Database\Eloquent\Collection<int, Simple> $relationMorphedByMany
* @property-read int|null $relation_morphed_by_many_count * @property-read int|null $relation_morphed_by_many_count
* @property-read \Illuminate\Database\Eloquent\Collection|Simple[] $relationSampleRelationType * @property-read \Illuminate\Database\Eloquent\Collection<int, Simple> $relationSampleRelationType
* @property-read int|null $relation_sample_relation_type_count * @property-read int|null $relation_sample_relation_type_count
* @property-read Model|\Eloquent $relationSampleToAnyMorphedRelationType
* @property-read \Illuminate\Database\Eloquent\Collection<int, Simple> $relationSampleToAnyRelationType
* @property-read int|null $relation_sample_to_any_relation_type_count
* @property-read Simple $relationSampleToManyRelationType * @property-read Simple $relationSampleToManyRelationType
* @method static \Illuminate\Database\Eloquent\Builder|Simple newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|Simple newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Simple newQuery() * @method static \Illuminate\Database\Eloquent\Builder|Simple newQuery()
@@ -182,4 +185,14 @@ class Simple extends Model
{ {
return $this->testToManyRelation(Simple::class); return $this->testToManyRelation(Simple::class);
} }
public function relationSampleToAnyRelationType()
{
return $this->testToAnyRelation(Simple::class);
}
public function relationSampleToAnyMorphedRelationType()
{
return $this->testToAnyMorphedRelation(Simple::class);
}
} }
@@ -13,11 +13,11 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property integer $id * @property integer $id
* @method static \Illuminate\Database\Eloquent\Builder|Simple newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|Simple newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|Simple newQuery() * @method static \Illuminate\Database\Eloquent\Builder|Simple newQuery()
* @method static \Illuminate\Database\Query\Builder|Simple onlyTrashed() * @method static \Illuminate\Database\Eloquent\Builder|Simple onlyTrashed()
* @method static \Illuminate\Database\Eloquent\Builder|Simple query() * @method static \Illuminate\Database\Eloquent\Builder|Simple query()
* @method static \Illuminate\Database\Eloquent\Builder|Simple whereId($value) * @method static \Illuminate\Database\Eloquent\Builder|Simple whereId($value)
* @method static \Illuminate\Database\Query\Builder|Simple withTrashed() * @method static \Illuminate\Database\Eloquent\Builder|Simple withTrashed()
* @method static \Illuminate\Database\Query\Builder|Simple withoutTrashed() * @method static \Illuminate\Database\Eloquent\Builder|Simple withoutTrashed()
* @mixin \Eloquent * @mixin \Eloquent
*/ */
class Simple extends Model class Simple extends Model
@@ -12,7 +12,7 @@ use Illuminate\Database\Query\Builder;
* Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\UnionTypes\Models\UnionTypeModel * Barryvdh\LaravelIdeHelper\Tests\Console\ModelsCommand\UnionTypes\Models\UnionTypeModel
* *
* @property-read string|int|null $foo * @property-read string|int|null $foo
* @property-read \Illuminate\Database\Eloquent\Collection|UnionTypeModel[] $withUnionTypeReturn * @property-read \Illuminate\Database\Eloquent\Collection<int, UnionTypeModel> $withUnionTypeReturn
* @property-read int|null $with_union_type_return_count * @property-read int|null $with_union_type_return_count
* @method static \Illuminate\Database\Eloquent\Builder|UnionTypeModel newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|UnionTypeModel newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|UnionTypeModel newQuery() * @method static \Illuminate\Database\Eloquent\Builder|UnionTypeModel newQuery()