Skip to content

Autocomplete Eloquent model attributes and accessors #189

@igorsantos07

Description

@igorsantos07

Tinker Version

none

Laravel Version

none

PHP Version

none

Database Driver & Version

No response

Description

I'm using Eloquent as a standalone lib on my project, and while integrating PsySH onto it, I ended up writing an autocompleter for Eloquent props.

As I'm not using Laravel on its entirety, I can't really write/test a fully fledged PR to integrate this suggestion onto Tinker. However, I thought about posting the code anyway as some maintainer could be interested in bringing this feature into Laravel.

Using .psysh.php config file, you'd add the following to its returned array:

'matchers' => [
	//autocompletes with Eloquent model attributes and accessors.
	new class extends \Psy\TabCompletion\Matcher\ObjectAttributesMatcher {
		public function getMatches(array $tokens, array $info = []): array { //adapted from the parent class
			$input = $this->getInput($tokens);

			$firstToken = array_pop($tokens);
			if (self::tokenIs($firstToken, self::T_STRING)) {
				array_pop($tokens); // second token is the object operator
			}
			$objectToken = array_pop($tokens);
			if (!is_array($objectToken)) {
				return [];
			}
			$objectName = str_replace('$', '', $objectToken[1]);

			try {
				$object = $this->getVariable($objectName);
			} catch (InvalidArgumentException $e) {
				return [];
			}

			if (!($object instanceof \Illuminate\Database\Eloquent\Model)) {
				return [];
			}

			return array_merge(
				array_filter(
					array_keys($object->getAttributes()),
					fn($attr) => str_starts_with($attr, $input)
				),

				//cannot autocomplete with what doesn't start with $input, so we turn accessors into magic props
				array_map(
					fn($accessor) => Str::snake(preg_replace(['/^get/', '/Attribute$/'], '', $accessor)),
					array_filter(
						get_class_methods($object),
						fn($method) => str_starts_with($method, 'get'.ucfirst($input))
					)
				)
			);
		}
	},
]

The first half of that method was copied from ObjectAttributesMatcher, and obviously this anonymous class would be implemented as a real one. However, Tinker configures PsySH differently as well, so it would probably be added with Psy\Shell::addMatchers().

I hope this is useful! For us it will definitely be :)

Steps To Reproduce

Try to autocomplete your favorite model with that forgettable attribute name :)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions