PHPStan configuration for FuelPHP - php

I am having a lot of trouble getting PHPStan to see the FuelPHP core classes. It would appear this sort of thing causes it grief:
namespace Fuel\Core;
/**
* Template Controller class
*
* A base controller for easily creating templated output.
*
* #package Fuel
* #category Core
* #author Fuel Development Team
*/
abstract class Controller_Template extends \Controller
{
/**
* #var string page template
*/
public $template = 'template';
Where Controller is also in the Fuel\Core namespace:
namespace Fuel\Core;
abstract class Controller
{
/**
* #var Request The current Request object
*/
public $request;
It looks like PHPStan can's find Controller because it is looking in the root namespace. FuelPHP gets around this (magic? autoloading? aliasing?). Is there a way to get PHPStan to jump on the same bandwagon, or do I need to stub out all the core classes I'm using?

Did you try to follow this guide? PHPStan: Discovering symbols
I helped set up FuelCMS analysis in the past. What worked for that user was this phpstan.neon:
parameters:
scanDirectories:
- core/classes
bootstrapFiles:
- core/classes/autoloader.php
There's an example repository that works: https://github.com/ondrejmirtes/phpstan_problem/tree/fix
For some reason the phpstan.neon is buried in app/classes/controller while it should definitely be in the root directory. But otherwise it works.

Related

Undefined step reference in PhpStorm when using Codeception and Gherkin

I'd like to be able to use PhpStorm's "Go To Declaration" feature (Command + B on a Mac) in Gherkin feature files when using Codeception. However, PhpStorm doesn't seem to figure out where the steps are defined, and outputs this warning:
Undefined step reference: […]
When I'm using Behat, PhpStorm understands where the steps are defined.
Steps to reproduce
mkdir codeception
cd codeception
composer require "codeception/codeception" --dev
./vendor/bin/codecept bootstrap
./vendor/bin/codecept generate:feature acceptance first
Open the project directory in PhpStorm.
Make sure that PhpStorm knows that Codeception is installed:
Make sure that the PhpStorm plugins Gherkin and Codeception Framework are installed.
Add a step to tests/acceptance/first.feature.
./vendor/bin/codecept gherkin:snippets acceptance
This results in the following code. (Not everything is included – let me know if I need to add anything.)
tests/acceptance/first.feature:
Feature: first
In order to ...
As a ...
I need to ...
Scenario: try first
When I visit "/"
tests/_support/AcceptanceTester.php:
<?php
/**
* Inherited Methods
* #method void wantToTest($text)
* #method void wantTo($text)
* #method void execute($callable)
* #method void expectTo($prediction)
* #method void expect($prediction)
* #method void amGoingTo($argumentation)
* #method void am($role)
* #method void lookForwardTo($achieveValue)
* #method void comment($description)
* #method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* #SuppressWarnings(PHPMD)
*/
class AcceptanceTester extends \Codeception\Actor
{
use _generated\AcceptanceTesterActions;
/**
* Define custom actions here
*/
/**
* #When I visit :arg1
*/
public function iVisit($arg1)
{
throw new \Codeception\Exception\Incomplete("Step `I visit :arg1` is not defined");
}
}
However, PhpStorm doesn't know where iVisit() is. How can I fix this?
Currently PhpStorm seems to use the Behat Context interface to determine which classes define implementations for the Gherkin steps in .feature files, so a workaround to have PhpStorm find the steps in the codeception tester is to add the Behat\Behat\Context\Context interface somewhere in your source tree
/* Context.php */
namespace Behat\Behat\Context;
interface Context { }
and then have the AcceptanceTester implement that interface (which is an empty marker interface)
class AcceptanceTester extends \Codeception\Actor implements Context ...
Not supported yet, please vote:
https://youtrack.jetbrains.com/issue/WI-34963
Building off Roverwolf's answer.
Add this to the top of the AcceptanceTester file.
namespace Behat\Behat\Context {
interface Context { }
}
Then have AcceptanceTester implement that. Wrapping namespaces like this is a common trick in PHP testing to fake methods that exist in other namespaces.
namespace {
class AcceptanceTester extends \Codeception\Actor implements \Behat\Behat\Context\Context
}
}
I have another step definition file, and I use Behat's Context. Then implements Context in the class declaration.
use Behat\Behat\Context;
class myClassSteps implements Context\Context
{
step definitions
}
It works for me.

Eloquent ORM Code Hinting in PhpStorm

So I'm just starting off with Laravel (using v5) and Eloquent. I'm working on getting some basic APIs up and running and noticing that a lot of working methods don't show up in PhpStorm's code hinting
So I have this model:
namespace Project\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model
implements AuthenticatableContract, CanResetPasswordContract {
}
And in one of my controllers I try to do
User::query()->orderBy('id', 'desc');
User::query() creates a Eloquent Builder object and orderBy() behave properly and without error. However, PhpStorm does not show orderBy() (or take(), skip(), and I'm sure others) when I type User::query()-> and gives warnings when I actually do use it.
I am using Laravel IDE Helper which has helped immensely with bringing code hints to the Facades, but not to the models/builders it would seem.
Does anyone have a solution to this?
For future Googlers, and perhaps OP as well if you are still sticking to Laravel.
The laravel-ide-helper package solves this issue for you quite elegantly, with what I believe is a relatively new feature; generated model PHPDocs.
You can generate a separate file for all PHPDocs with this command:
php artisan ide-helper:models
The generated metadata will look something like this for each class:
namespace App {
/**
* App\Post
*
* #property integer $id
* #property integer $author_id
* #property string $title
* #property string $text
* #property \Carbon\Carbon $created_at
* #property \Carbon\Carbon $updated_at
* #property-read \User $author
* #property-read \Illuminate\Database\Eloquent\Collection|\Comment[] $comments
*/
class Post {}
}
This caused issues for me in PHPStorm however, where the software was complaining about multiple class definitions. Luckily an option is readily available for writing directly to the model files:
php artisan ide-helper:models -W
There are a few more options and settings available if you need to tweak the behavior, but this is the gist of it.
Add in model PHPDoc#mixin
/**
* Class News
* #property int $id
* #property string $created_at
* #property string $updated_at
* #mixin \Eloquent
* #package App
*/
class News extends Model
{
}
In PHPStorm works
You can try Laravel plug-in for PhpStorm and you need to specifically activate it in your project settings.
If you're using BarryVHD's Laravel IDE Helper package, run:
php artisan ide-helper:eloquent
This will write /** #mixin \Eloquent */ into the vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php file.
A little late but I recently had the same problem so I thought I would put a note down:
This is because Database\Eloquent\Model.php has a query() function which returns \Illuminate\Database\Eloquent\Builder and the Eloquent\Builder has a line:
use Illuminate\Database\Query\Builder as QueryBuilder;
Then it uses 'magic' __call methods to call to functions in Query\Builder. (look for __call method in Eloquent\Builder)
See:
http://php.net/manual/en/language.oop5.overloading.php#object.call
__call() is triggered when invoking inaccessible methods in an object context.
So, indeed the method you are calling is inaccessible :) There is not much that the IDE can do.
There are workarounds like using #method tags but it is unmaintainable. An alternative is to use #mixin (but this is not standards based).
See: https://github.com/laravel/framework/issues/7558
I think this all be resolved when they get rid of all the magic calls in the Laravel code and use PHP 'traits' instead. See last message here. :)
Just import Eloquent Builder in your Model class and add mixin:
use Illuminate\Database\Eloquent\Builder;
/** #mixin Builder */
To cover all the models at once — add the mixin to the src/Illuminate/Database/Eloquent/Model.php)
I wanted to have some kind of explicit "casting" when interacting with the query builder. Example...
$user = User::query()->findOrFail($id);
$user->myUserSpecialMethod(); // <-- IDE syntax error
Since all my models are extending my custom base Model which in turn extends Eloquent, I've ended up creating this method in my custom base model:
/**
* Explicit type-hinting
*
* #return static
*/
static public function hint(BaseModel $model)
{
return $model;
}
This way, it solves the IDE invalid error and helps me:
$user = User::hint(User::query()->findOrFail($id));
$user->myUserSpecialMethod(); // <-- all OK !
Please note that this is not OOP type casting. It is only a hint to help the IDE. In my example, the returned Model was already a User. If I woud use this method on a derived class like SuperUser, only the IDE will be fooled...
An nice alternative also is to put meta information directly over the assignment statement:
/** #var User $user */
$user = User::query()->findOrFail($id);
$user->myUserSpecialMethod(); // <-- all OK !
Or next to it...
$user = User::query()->findOrFail($id); /** #var User $user */
$user->myUserSpecialMethod(); // <-- all OK !
Verified on Laravel 8, just added #mixin Builder to Illuminate\Database\Eloquent\Model.php annotation solved it.
// Illuminate\Database\Eloquent\Model.php
/**
* #mixin Builder
*/
abstract class Model

In the Eclipse PDT, is it possible to configure content assist to look for alternative tags to suggest PHP types?

I'm working on a project that uses the Lithium (http://li3.me/) framework and they document their classes like this:
class Controller extends \lithium\core\Object {
/**
* Contains an instance of the `Request` object with all the details of the HTTP request that
* was dispatched to the controller object. Any parameters captured in routing, such as
* controller or action name are accessible as properties of this object, i.e.
* `$this->request->controller` or `$this->request->action`.
*
* #see lithium\action\Request
* #var object
*/
public $request = null;
I've always used fully qualified class names in the #var and Eclipse seems to do a good job with that for generating content assist. However they seem to document class names using #see tags instead, and content assist is not available. Is there a way to configure PDT to use the information in the #see tag as a class name for the purposes of content assist?
It's not possible without own plugin. #see tag should be used for links only.

How do I get Swagger to follow extends?

I'm using Swagger PHP for ZF2 to generate API docs.
However, Some of my Controllers extends another Controller, and I can't get Swagger to include annotations from the parent class.
Consider this:
/**
* ProjectController Class
* #SWG\Resource(
* basePath="projects",
* description="Actions for Projects"
* )
* #see AbstractItemController
*/
class ProjectController extends AbstractItemController
{
...
}
Any Swagger annotations in the ProjectController works just fine, however I can't get any annotations in AbstractItemController to be included in the documentation for ProjectController.
Any ideas?
Thanks!

phpdoc keeps telling me my page-level docblock is not present

PHPDocumenter keeps telling me that my page-level docblock is not present in my file, i read several pages of documentation online to make this work but still doesn't work, anyone know whats wrong?
<?php
namespace Activis\Catalog\Model;
/**
* This file represents the factory for the domain object Product for the Activis catalog.
*
* For now, this factory is simple and abstract but will slowly change into a non-static set of factory functions
* The domain model for this object is \Activis\Catalog\Model\Product
*
* #category Domain model factory
* #package Activis.Catalog.Model
* #author Mathieu Dumoulin
* #license LGPL v3
* #link http://activis.ca/
* #todo Change the methods in the factory to not be abstract and require an instance of this class
*/
/**
* Declares the catalog's product's domain model factory
*
* #abstract
* #static
*/
abstract class ProductFactory
{
}
Page-level docblock should be placed on top of file, before namespace declarations

Categories