Search Documentation

Search across all documentation pages

Extending

Stubs

The generator commands that write Lathe classes, the stubs they render, and how to change them.

Lathe writes the classes and components you need from templates called stubs. Each generator is an Artisan command. It writes into app/Lathe/, in the namespace of your app, or into a plugin package. You may publish the stubs and edit them, so your team's classes start the way you want.

The generators

Command Writes Where
lathe:resource A Resource and its policy app/Lathe/Resources, app/Policies
lathe:action An action app/Lathe/Actions
lathe:filter A filter app/Lathe/Filters
lathe:lens A lens app/Lathe/Lenses
lathe:widget A widget app/Lathe/Widgets
lathe:dashboard A dashboard app/Lathe/Dashboards
lathe:field A field class app/Lathe/Fields
lathe:page A page and its React component app/Lathe/Pages
lathe:resource-plugin A resource plugin and its React component app/Lathe/Plugins
lathe:plugin A plugin package, or with --inline an in-app plugin and its React component lathe-components/, or app/Lathe/Plugins

Every generator takes the class name as its argument. The name may hold letters, digits and underscores, and each part starts with a letter. A / makes a subfolder and a sub-namespace: lathe:resource Billing/Invoice writes app/Lathe/Resources/Billing/Invoice.php in the namespace App\Lathe\Resources\Billing. These names are reserved because they would clash with Lathe's own classes: Action, Dashboard, Field, Filter, Lens, Plugin, Resource and Widget.

A generator refuses to overwrite a file. Pass --force to replace it. --force replaces the file without asking, so any change in the old file is lost.

php artisan lathe:resource Post --force

--plugin=vendor/package writes the class into a plugin package instead of the app. It works for lathe:resource, lathe:action, lathe:lens, lathe:dashboard and lathe:resource-plugin. Lathe looks for the package in lathe-components/ first and then in vendor/, and uses the namespace of its src/ folder. lathe:resource writes no policy then.

php artisan lathe:action Notify --plugin=acme/price-tracker

Commands lists every flag.

Resources

php artisan lathe:resource Post

This writes app/Lathe/Resources/Post.php, a Resource for the model App\Models\Post, and app/Policies/PostPolicy.php unless it exists. If the model does not exist yet, the command prints a warning. See Defining resources.

Actions, lenses and dashboards

php artisan lathe:action SendWelcomeEmail
php artisan lathe:lens MostValuableUsers
php artisan lathe:dashboard Analytics

Each writes a class with the methods you fill in.

Filters

php artisan lathe:filter UserType

By default this is a select filter. --type picks another: select, boolean, date or range. --custom writes a filter class and a React component instead:

php artisan lathe:filter PriceRange --custom

This writes app/Lathe/Filters/PriceRange.php and resources/js/lathe/filters/PriceRange.tsx, and adds the import to boot.ts. The component key gets a -filter suffix, here price-range-filter. The PHP class returns the same key from component().

Widgets

php artisan lathe:widget NewUsers --type=trend

--type is value (the default), trend, partition, progress, table, bar, pie, radar, radial, help or custom. Only custom also writes a React component.

Fields

php artisan lathe:field Currency

This writes app/Lathe/Fields/Currency.php, a class that extends Field. --extends names a built-in type to extend instead: field, text, textarea, number, boolean, date, datetime, code, badge, status, file or image. --custom also writes a React component and its import. See Frontend.

Pages

php artisan lathe:page Reports

This writes the page class and resources/js/lathe/pages/Reports.tsx. See Pages.

Plugins

php artisan lathe:plugin acme/price-tracker
php artisan lathe:plugin Insights --inline
php artisan lathe:resource-plugin StripeInspector

The first writes a Composer package to lathe-components/PriceTracker/. The second writes an in-app plugin and its component. The third writes a resource plugin. --skip-composer stops lathe:plugin from offering to run composer update. See Plugins.

The frontend setup

The first command that writes a React component also sets up the extension build. That means lathe:field --custom, lathe:filter --custom, lathe:widget --type=custom, lathe:page, lathe:plugin --inline and lathe:resource-plugin without --plugin. It writes resources/js/lathe/boot.ts, the folders next to it and a vite.lathe.config.ts, and adds the three @lathephp packages to your package.json. It skips this when boot.ts exists. It never edits your vite.config.ts. Frontend explains the build.

Publish the stubs

php artisan lathe:stubs

This copies the stubs to stubs/lathe/ in your app. A generator uses your copy when one exists and the package's stub otherwise. lathe:stubs leaves files that already exist alone. Pass --force to overwrite them.

To change what lathe:resource writes, edit stubs/lathe/resource.stub. Every later lathe:resource uses it. Delete a file from stubs/lathe/ to go back to the default.

The stubs

Stub Used by
resource.stub lathe:resource
policy.stub lathe:resource, for the policy
action.stub lathe:action
lens.stub lathe:lens
dashboard.stub lathe:dashboard
filter-select.stub, filter-boolean.stub, filter-date.stub, filter-range.stub lathe:filter --type=...
filter-custom.stub, filter-react.stub lathe:filter --custom: the class and the component
widget-value.stub, widget-trend.stub, widget-partition.stub, widget-progress.stub, widget-table.stub, widget-bar.stub, widget-pie.stub, widget-radar.stub, widget-radial.stub, widget-help.stub lathe:widget --type=...
widget-custom.stub, widget-react.stub lathe:widget --type=custom: the class and the component
field.stub, field-react.stub lathe:field: the class, and the component with --custom
page.stub, page-react.stub lathe:page: the class and the component
resource-plugin.stub, resource-plugin-react.stub lathe:resource-plugin: the class and the component
plugin.stub, plugin-react.stub lathe:plugin --inline: the class and the component
boot.stub, vite.lathe.config.stub The frontend setup

lathe:install writes LatheServiceProvider.stub, user-resource.stub and main-dashboard.stub from the package, and lathe:plugin copies lathe-components-readme.md from the package. Copies in stubs/lathe/ do not change them. The package scaffold of lathe:plugin vendor/package is a whole folder of templates, stubs/plugin-skeleton/. lathe:stubs does not publish it.

Placeholders

A stub holds {{ name }} style placeholders that the command fills in:

Placeholder Replaced with Example
{{ namespace }} The namespace of the class App\Lathe\Resources
{{ class }} The class name in StudlyCase UserPost
{{ name }} The class name as a headline User Post
{{ component }} The kebab-case component key (the filter key has -filter added) user-post
{{ modelNamespace }} The model class of a Resource App\Models\UserPost

policy.stub also gets {{ model }}, the model class. field.stub gets {{ baseImport }} and {{ baseClass }}, the field type to extend.

What you see

After php artisan lathe:resource Post, the file app/Lathe/Resources/Post.php exists and the panel lists Posts in the sidebar. After php artisan lathe:stubs, the stubs/lathe/ folder holds one file for each stub, and the next generator you run uses the copy you edit.