mateffy/laravel-introspect

Analyze Laravel codebases and find structured information about models, routes and other Laravel-specific things.

1.0.2 2025-05-18 16:10 UTC

This package is auto-updated.

Last update: 2025-05-20 16:39:34 UTC


README

Development Tests Status Latest Version GitHub Release Date

Introspect for Laravel

A utility package to analyze Laravel codebases, querying views, models, routes, classes and more directly from your codebase using a type-safe fluent API.


  • ๐Ÿ” Query views, routes, classes and models with a fluent API
  • ๐Ÿ” Use wildcards (*) to match multiple views, routes, classes and models
  • ๐Ÿช„ Parse properties, relationships + their types and more directly from Eloquent model code
  • ๐Ÿค– (De-)serialize queries to/from JSON (perfect for LLM tool calling)

Query Available Filters
Views name, path, used by view, uses view, extends
Routes name, URI, controller + fn, methods, middleware
Classes name / namespace, extends parent, implements interfaces, uses traits
โคท Models ... relationships, properties, casts, fillable, hidden, read/writeable
โคท Commands ... signature, description (coming soon)

Name and a few other queries even support wildcard queries (e.g. components.*.paragraph)


Who is this for?

Are you working on a complex refactoring job and need to find all the places where a specific view is used? Are you building devtools or other things which need information about the codebase? Do you need structured schema information of your Eloquent data model?

These are all use cases where you need to introspect your codebase and find out where things are used, how they are used and what they are. This package does exactly that.


Installation

Install the package via composer:

composer require mateffy/laravel-introspect  

Note

Depending on your use case, it might make sense to install the package as a dev dependency by adding the --dev flag to the command.


Usage

use Mateffy\Introspect\Facades\Introspect;  

$views = Introspect::views()
    ->whereNameEquals('components.*.button')
    ->whereUsedBy('pages.admin.*')
    ->get();  
    
$routes = Introspect::routes()
    ->whereUsesController(MyController::class)
    ->whereUsesMiddleware('auth')
    ->whereUsesMethod('POST')
    ->get();  

$classes = Introspect::classes()
    ->whereImplements(MyInterface::class)
    ->whereUses(MyTrait::class)
    ->get();  
    
$models = Introspect::models()
    ->whereHasProperties(['name', 'email'])
    ->whereHasFillable('password')
    ->get();  

// Access Eloquent properties, relationships, casts, etc. directly
$detail = Introspect::model(User::class);

// Model to JSON schema
$schema = $detail->schema();

Views

You can query all of the views you have in your codebase, including those that are provided by other packages and are namespaced with a prefix::. View queries return a Collection<string> of view names.

All queries support wildcards, e.g. components.*.button or *.button

Query views by view path

$views = Introspect::views()  
    // Supports wildcards 
    ->whereNameEquals('*components.*item')
    ->get();
// -> ['components.item', 'filament::components.dropdown.list.item', ...]
    
$views = Introspect::views()  
    ->whereNameStartsWith('filament::')
    ->get();  

$views = Introspect::views()  
    ->whereNameEndsWith('button')
    ->get();  

$views = Introspect::views()  
    ->whereNameContains('button')
    ->get();

Query all views that are used by specific views

$routes = Introspect::views()  
    ->whereUsedBy('pages.welcome')
    ->get();
// -> ['components.button', 'filament::components.button', ...]
    
$routes = Introspect::views()  
    ->whereUsedBy('pages.*')
    ->get();
    
$routes = Introspect::views()  
    ->whereNotUsedBy('pages.*')
    ->get();

Query all views that use a specific view

$routes = Introspect::views()  
    ->whereUses('components.button')   
    ->get();
    
$routes = Introspect::views()  
    ->whereUses('*.button')   
    ->get();
    
$routes = Introspect::views()  
    ->whereDoesntUse('*.button')   
    ->get();

Query all views that extend a specific view

$routes = Introspect::views()  
    ->whereExtends('layouts.app')   
    ->get();
    
$routes = Introspect::views()  
    ->whereExtends('layouts.*')   
    ->get();
    
$routes = Introspect::views()  
    ->whereDoesntExtend('layouts.*')   
    ->get();

Routes

Query through all the routes registered in your application (think like artisan route:list output), including those registered by packages. The routes are returned as a Collection<\Illuminate\Routing\Route>.

Query all routes that use a controller

$routes = Introspect::routes()  
    ->whereUsesController(MyController::class)  
    ->get();
// -> [\Illuminate\Routing\Route, \Illuminate\Routing\Route, ...]

$routes = Introspect::routes()  
    ->whereUsesController(MyController::class, 'index')
    ->get();
    
$routes = Introspect::routes()  
    ->whereUsesController(SingleActionController::class, 'index')
    ->get();

Query all routes that use a specific middleware

$routes = Introspect::routes()  
    ->whereUsesMiddleware(MyMiddleware::class)  
    ->get();

$routes = Introspect::routes()  
    ->whereUsesMiddlewares(['tenant', 'auth'])  
    ->get();
    
$routes = Introspect::routes()  
    // Match any of the middlewares
    ->whereUsesMiddlewares(['tenant', 'auth'], all: false)
    ->get();
    
$routes = Introspect::routes()  
    ->whereDoesntUseMiddleware('api')  
    ->get();

Query routes by name

"Name equals/contains" queries support wildcards, e.g. api.products.* or *.products.*

$routes = Introspect::routes()  
    ->whereNameEquals('api.products.*')
    ->get();
    
$routes = Introspect::routes()  
    ->whereNameStartsWith('api.products.')
    ->get();

$routes = Introspect::routes()  
    ->whereNameEndsWith('api.products.')
    ->get();
    
$routes = Introspect::routes()  
    ->whereNameDoesntEqual('api.products.*')
    ->get();

Query routes by path

"Path equals/contains" queries support wildcards, e.g. api/products/* or */products/*

$routes = Introspect::routes()  
    ->wherePathStartsWith('api/products')
    ->get();

$routes = Introspect::routes()
    ->wherePathEndsWith('products')
    ->get();

$routes = Introspect::routes()
    ->wherePathContains('products')
    ->get();

$routes = Introspect::routes()
    ->wherePathEquals('api/products*')
    ->get();

Generic Classes

Query by namespace

$services = Introspect::classes()  
    ->whereName('\App\Services')
    ->get();

Query by parent

$blocks = Introspect::classes()  
    ->whereExtends(CMS\Block::class)
    ->get();

Query by interface

$blocks = Introspect::classes()  
    ->whereImplements(CMS\Block::class)
    ->get();

Query by trait

$blocks = Introspect::classes()  
    ->whereUses(MyTrait::class)
    ->get();

Models

Query Eloquent models based on their properties, attributes (fillable, hidden, appended, readable, writable), and relationship existence. Model queries return a Collection of model class strings (e.g., App\Models\User::class).

Query by Property Existence

Filter models based on whether they possess specific properties.

$models = Introspect::models()
    ->whereHasProperty('created_at')
    ->get();

// Also available: whereDoesntHaveProperty, whereHasProperties, whereDoesntHaveProperties
// Example with multiple properties (any):
$models = Introspect::models()
    ->whereHasProperties(['first_name', 'last_name'], all: false)
    ->get();

Query by Fillable Properties

Filter models based on their $fillable attributes.

$models = Introspect::models()
    ->whereHasFillable('title')
    ->get();

// Also available: whereDoesntHaveFillable, whereHasFillableProperties, etc.
$models = Introspect::models()
    ->whereHasFillableProperties(['name', 'description']) // all: true by default
    ->get();

Query by Hidden Properties

Filter models based on their $hidden attributes.

$models = Introspect::models()
    ->whereHasHidden('password')
    ->get();

// Also available: whereDoesntHaveHidden, whereHasHiddenProperties, etc.
$models = Introspect::models()
    ->whereDoesntHaveHiddenProperties(['name', 'email'], all: false) // neither name nor email are hidden
    ->get();

Query by Appended Properties

Filter models based on their $appends attributes (accessors).

$models = Introspect::models()
    ->whereHasAppended('full_name')
    ->get();

// Also available: whereDoesntHaveAppended, whereHasAppendedProperties, etc.
$models = Introspect::models()
    ->whereHasAppendedProperties(['is_active', 'resource_type'])
    ->get();

Query by Readable Properties

Filter models based on "readable" properties (public getters, public properties, or attributes).

$models = Introspect::models()
    ->whereHasReadable('name')
    ->get();

// Also available: whereDoesntHaveReadable, whereHasReadableProperties, etc.
$models = Introspect::models()
    ->whereHasReadableProperties(['id', 'email'])
    ->get();

Query by Writable Properties

Filter models based on "writable" properties (public setters or public properties).

$models = Introspect::models()
    ->whereHasWritable('status')
    ->get();

// Also available: whereDoesntHaveWritable, whereHasWritableProperties, etc.
$models = Introspect::models()
    ->whereHasWritableProperties(['name', 'settings'])
    ->get();

Query by Relationship Existence

Filter models based on the existence of specific relationship methods. Note: This currently checks for method presence, not relationship type or related model details.

$models = Introspect::models()
    ->whereHasRelationship('user')
    ->get();

$models = Introspect::models()
    ->whereDoesntHaveRelationship('logs')
    ->get();

Chaining queries with OR and AND

By default, any queries are combined with AND logic. However, you can craft more complex queries by chaining together queries with OR logic, too. This works for all queries, including models, routes, views and classes.

use \Mateffy\Introspect\Query\Contracts\RouteQueryInterface;

$routes = Introspect::routes()  
    ->whereNameEquals('api.*')
    ->whereMethod('POST')
    ->or(fn (RouteQueryInterface $query) => $query
        ->whereHasParameter('product') //
        ->whereHasParameter('category')
    )
    ->get();

Some methods support multiple parameters, e.g. whereUsesMiddlewares([...]) or whereUsesProperties([...]). These methods have an all parameter that defaults to true. If set to false, the values are checked with OR logic too, matching on any of the values.

$routes = Introspect::routes()  
    ->whereUsesMiddlewares(['tenant', 'auth'], all: false)  
    ->get();

Limit the results and paginate just like using Eloquent queries

Actual Laravel pagination (->paginate(...)) is not yet supported, but you can use limit and offset to get the results you want.

$models = Introspect::models()  
    ->limit(10)
    ->offset(20)
    ->get();

Build Queries with JSON instead of code

All the type-safe queries above can also be expressed in JSON format.
This is to make it easier for LLMs to be able to more flexibly query the codebase.

$query = <<<JSON
{
    "type": "models",
    "query": {
        "filters": [
            {
                "type": "whereTrait",
                "value": "MyTrait::class"
            }
        ],
        "limit": 10,
        "offset": 20
    }
}
JSON;

$models = Introspect::query($query)->get();

DTO Examples

Get all model properties

$model = Introspect::model(User::class);
$properties = $models->properties();
$casts = $models->casts();
$casts = $models->casts();

Get Model as JSON schema

$schema = Introspect::model(User::class)->schema();
// -> ['type' => 'object',...]

License

The MIT License (MIT). Please see License File for more information.