klesun / deep-assoc-completion

A phpstorm plugin for associative array key typing and completion
Other
267 stars 17 forks source link

Introduce syntax to autocomplete from docblock? #215

Open dereuromark opened 6 months ago

dereuromark commented 6 months ago

Refs https://github.com/dereuromark/cakephp-ide-helper/issues/346

Would be nice if we could use some kind of option keys list in the docblock to document all possible array keys for assoc arrays.

So when someone types

    $this->hasMany('ADmad/SocialAuth.SocialProfiles', [
        'f
    ]);

it would autocomplete the foreignKey option right away.

Or are there other ways of accomplishing this?

The method and its docblock currently reads as

    /**
     * The options array accept the following keys:
     *
     * - className: The class name of the target table object
     * - targetTable: An instance of a table object to be used as the target table
     * - foreignKey: The name of the field to use as foreign key, if false none
     *   will be used
     * - dependent: Set to true if you want CakePHP to cascade deletes to the
     *   associated table when an entity is removed on this table. The delete operation
     *   on the associated table will not cascade further. To get recursive cascades enable
     *   `cascadeCallbacks` as well. Set to false if you don't want CakePHP to remove
     *   associated data, or when you are using database constraints.
     * - cascadeCallbacks: Set to true if you want CakePHP to fire callbacks on
     *   cascaded deletes. If false the ORM will use deleteAll() to remove data.
     *   When true records will be loaded and then deleted.
     * - conditions: array with a list of conditions to filter the join with
     * - sort: The order in which results for this association should be returned
     * - saveStrategy: Either 'append' or 'replace'. When 'append' the current records
     *   are appended to any records in the database. When 'replace' associated records
     *   not in the current set will be removed. If the foreign key is a null able column
     *   or if `dependent` is true records will be orphaned.
     * - strategy: The strategy to be used for selecting results Either 'select'
     *   or 'subquery'. If subquery is selected the query used to return results
     *   in the source table will be used as conditions for getting rows in the
     *   target table.
     * - finder: The finder method to use when loading records from this association.
     *   Defaults to 'all'.
     *
     * This method will return the association object that was built.
     *
     * @param string $associated the alias for the target table. This is used to
     * uniquely identify the association
     * @param array<string, mixed> $options list of options to configure the association definition
     * @return \Cake\ORM\Association\HasMany
     */
    public function hasMany(string $associated, array $options = []): HasMany
    {

If sth like this list is not formal enough, maybe we can find a syntax for it that is.

klesun commented 6 months ago

If I understood the question correctly, the format from phpstan and other linters does cover the union type and the string literal type, so following should work in the plugin: (unless some breaking change in modern IDE versions broke that)

    /**
     * @param array<'className' | 'targetTable' | 'foreignKey' | 'dependent' | 'cascadeCallbacks' | 'conditions' | 'sort' | 'saveStrategy' | 'strategy' | 'finder', mixed> $options list of options to configure the association definition
     */
    public function hasMany(string $associated, array $options = []): HasMany
    {
        $options['<completion should come up here>']
dereuromark commented 6 months ago

I mean from the outside, the using function of ->hasMany() See my example.

Your code snippet does not seem to work. Only AI (tabinePro in my case) seems to sometimes guess the possible types correctly, but more like 20% of the time.

dereuromark commented 6 months ago

That said

@param array{className: string, targetTable: string, foreignKey: string, webroot: string, dependent: bool, cascadeCallbacks: bool, conditions: array, sort: array, saveStrategy: string, finder: string} $options List of options to configure the association definition

seems to work, but that makes the docblock line super loong, would be nice if there was a way outside of the param docblock line directly.

klesun commented 6 months ago

When completion works it suppossedly works both inside and outside the ->hasMany() function.

One more way, specific to the plugin, is to express the type through a dummy function:

function hasManyOptionsType()
{
    return [
        /** The class name of the target table object */
        'className' => 'example value',
        /** An instance of a table object to be used as the target table */
        'targetTable' => 'example value',
        /** The name of the field to use as foreign key, if false none will ve used */
        'foreignKey' => 'example value',
        // and so on
    ];
}

class Something()
{
    /**
     * @param $options = hasManyOptionsType()
     */
    public function hasMany(string $associated, array $options = []): HasMany
    {
        $options['<completion should come up here>']
    }
}

(new Something())->hasMany('ADmad/SocialAuth.SocialProfiles', [
    '<completion should come up here too>'
]);