Download the PHP package inlayphp/resources without Composer

On this page you can find all versions of the php package inlayphp/resources. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package resources

Inlay Resources

Packagist PHP

Fluent Laravel resource orchestration for Inlay forms, tables, infolists, and panels

Inlay Resources is the PHP-first CRUD layer for Laravel and Inertia. One resource owns its Eloquent query, table, form, validation class, authorization, pages, persistence hooks, and navigation metadata; React or Vue only renders the serialized form/table contracts.

Install

Resources depends on the PHP form, table, validation, authorization, and panel contracts. Install the matching React or Vue renderers for the schemas used by your pages. For a complete administration foundation, composer require inlayphp/inlay installs the clean panel package set; permission management, media, Spatie adapters, and imports remain opt-in.

Install the relation-manager renderer used by your Inertia frontend:

Generate a resource

This creates UserResource, list/create/edit page classes, and UserRules. Existing files are never replaced unless --force is supplied.

Options decide the resource's shape:

--simple and --view are refused together: a modal-only resource has no page to view a record on.

--generate reads the model's table and writes the form, table, and validation rules from it:

Booleans become Toggles, date columns become DatePickers, and datetime columns become DateTimePickers with the right value shape. Numeric columns become numeric TextInputs, and long text becomes a Textarea that is left out of the table. The first string column is made searchable, nullability decides required() and the generated rule, and framework-owned columns — keys, timestamps, deleted_at, remember_token — are skipped. The Validation class is derived from the same reading. It is a starting point: the output is ordinary PHP to edit, read once at generation time rather than re-derived at runtime.

Generate an owner-scoped relationship manager separately:

This creates PostsRelationManager and a centralized UserPostRules validation class. The generated authorization stub is intentionally fail-closed.

Define the resource

Page classes choose the Inertia component while the resource stays frontend-neutral:

Navigation groups and badges

Resources can describe their own place in a panel's navigation. The panel registrar uses this metadata when it registers the resource, so a team can add or reorder a module without maintaining a second navigation list:

Declare the matching NavigationGroup labels and order once in the panel provider. The browser receives the group, item order, icon, and badge as part of the normal inlay.panels.v1 contract; it does not infer or duplicate resource navigation.

Global search

Declare what a resource contributes to search:

Each resource is searched through its own scoped query and its own authorization, so a match can never surface a record the visitor could not open directly, and a tenant-scoped resource stays inside its tenant without extra configuration. A resource that declares no attributes stays out of search entirely. Terms shorter than two characters are refused rather than scanning the table, and every result links to the page the visitor would have opened anyway. Results are named by the resource's record title, below.

Record titles and breadcrumbs

Name a record once, and every place that mentions it agrees:

Without a declared attribute, recordTitle() tries name, title, then label, and falls back to the resource label with the key (User #17) so a record is never named blank. globalSearchTitle() reads the same title, and recordTitle() may be overridden outright when a title is composed from several columns.

Every resource page publishes a breadcrumbs prop — the resource's list page, the record, then the current page — which both renderers draw:

For a complete custom page shell, both official renderers also expose ResourcePage. It composes the heading, breadcrumbs, record sub-navigation, and named-view tabs around host content while keeping forms, tables, infolists, and relation managers as ordinary child components. This is the recommended escape hatch for pages that need custom layout without losing the resource contract.

A step links only where a page exists to open: the list step is dropped from the trail's links when the resource has no index page, the record step links only when there is an edit or view page, and the current page is always plain text carrying aria-current="page". Nested resources keep their parent segment, so /admin/users/1/notes is a URL that exists. Override breadcrumbLabel() on a page to rename its own step.

Record sub-navigation

Name the pages one record moves between:

Names are keys of getPages(), and every one of them must accept a record — an unknown name, a duplicate, or the list page is refused when the page renders rather than drawn wrong. Each entry is checked against the resource's own authorization for that page's operation, so a visitor is only offered pages they could open; the check runs through authorize(), so navigation and enforcement cannot drift apart. A page may override subNavigation() to narrow the list, or return [] to hide it on itself.

Pages publish the result as a subNavigation prop, which both renderers draw:

The active page carries aria-current="page" and is not a link back to itself, and the component renders nothing when PHP offered no pages.

Resource::allows($operation, $record, $user) is available on its own for the same question elsewhere — it reports what authorize() would decide without throwing.

List page tabs

Declare named views of a list page's records:

The page narrows its own query before the table sees it, so the browser only sends a tab name and the server decides what that name means. A requested tab the page never declared falls back to the default rather than running an unknown query. The props carry tabs.active and tabs.items; @inlayphp/resources-react and @inlayphp/resources-vue export a ResourceTabs control with a proper tablist and arrow-key navigation. A page without tabs publishes nothing extra.

A page per relation

A record with many relations does not have to show them all at once:

The page renders the same relation manager the record page would have, with the same authorization; it only narrows which managers are built. A page naming a relation the resource does not declare is refused rather than rendered.

Page header actions

An action without its own URL is pointed at the resource's action endpoint under a page scope, resolved from the page rather than the table since it belongs to neither a row nor a selection. It still runs through the resource's authorized query, so a record page's action cannot reach a record the visitor could not open. An action that declares a URL is left exactly as written, duplicate names are refused, and a page without header actions publishes nothing extra. Lifecycle actions are fail-closed: add authorizeUsing() (or a policy-backed callback) before they can execute. The _inlay_page query marker used by the generated URL is internal transport metadata and is removed before action data is validated.

Page widgets

Declare widgets a resource shows above every page, and add page-specific ones:

Widgets resolve through the same WidgetResolver a dashboard uses, so instances, provider objects, and provider class names all work, and a page widget behaves exactly like a dashboard widget. Pages publish them as headerWidgets and footerWidgets, which the existing React and Vue widget renderers display. A resource with no widgets publishes neither prop.

Register all routes

For a users resource this registers named GET index/create/edit pages plus POST /users, PATCH /users/{record}, and DELETE /users/{record}. Page-specific middleware declared on PageRoute is also applied.

Inside an Inlay panel, prefer registering the same resource classes through Panel::resources(). The panel supplies its prefix, route-name namespace, middleware, navigation, authorization ability registry, and Inertia panel defaults automatically:

One validation class everywhere

The same validation class can be consumed by Resources, Forms, Form Requests, Imports, APIs, and Actions. ValidationContext supplies the operation (create or edit), source, current record, authenticated user, prepared input, and options. The mutation controller authorizes before validation, and only validated keys reach persistence.

Remote Select options

Remote searchable Select fields work unchanged in resource create and edit forms:

The resource page answers option searches on its existing authorized GET route. On create and update, the same configured Form automatically verifies submitted values with the selected-label resolver before persistence. This prevents a client from submitting a value that the field provider does not recognize. Multiple selects use getOptionLabelsUsing().

Resources also bind their Eloquent model automatically, so a BelongsTo field only needs its relationship name and label column:

Use the optional modifyQueryUsing callback to apply tenant, visibility, or soft-delete constraints. The same scoped query is used for search, initial labels, and server-side valid-option checks.

BelongsToMany is also automatic:

Inlay makes this a multiple Select, hydrates current related keys on edit, validates every submitted key against the scoped relationship query, excludes roles from User::fill(), and calls sync() after the owner exists. The owner write and relationship sync share the Resource transaction. Omitting roles preserves existing assignments on a partial update; sending roles: [] detaches visible assignments. Existing relationships excluded by modifyQueryUsing are neither exposed nor detached. Static arrays passed to pivotData() apply to every pivot row, while callbacks may calculate data for each related key.

createOptionForm() and editOptionForm() use the same resource routes and authorization boundary. Their callbacks receive only independently validated option-form data; they do not submit or persist the parent Resource. See the Forms README for the complete fluent API.

Relation managers

Relation managers place a related Table and Form on edit/view resource pages without writing React or Vue business logic:

Register it on the owner Resource:

Group related managers into accessible tabs with the same PHP-only registration style:

RelationGroup accepts an explicit id(), optional description and icon, contained(false), and either a manager class or relationship name for defaultRelation(). Manager names and group IDs must be unique. The Resource keeps one flat, owner-scoped route registry internally, so grouping never changes endpoint URLs, authorization, validation, or query isolation.

React and Vue detect the repeated group metadata in the normal relations prop. They render semantic tablist, tab, and tabpanel roles, support Arrow Left/Right and Home/End navigation, move focus with the selected tab, and render only the active manager. No frontend grouping configuration is required.

Nested resources

When a child record only makes sense inside its parent, nest the whole Resource instead of embedding a Relation Manager. Declare the parent registration and Inlay serves every page and mutation under /parent-slug/{parent}/child-slug:

relationship() names the HasOne, HasMany, MorphOne, MorphMany, BelongsToMany, or MorphToMany relationship on the parent model, and defaults to the plural camel-cased child model name. inverseRelationship() names the child's BelongsTo or MorphTo relationship. parameter() renames the {parent} route parameter. Registration is validated once, before any route exists: the parent must be a Resource, cannot be the child itself, cannot already be nested (nesting is one level deep, matching the documented contract), and its relationship must return the child's model.

The registration drives everything else:

Generate URLs with the parent record:

Edit and view page props include relations, each using the stable inlay.resources.relation-manager.v1 contract. A relation contains the same Table and Form resources used elsewhere. View pages make managers read-only automatically.

Render every registered manager in React:

Or in Vue:

Both renderers compose the standard Inlay Table and Form components, add accessible create/edit dialogs, map Laravel validation errors back to fields, resolve route templates safely, and emit a changed event after successful mutations. Pass onQueryChange/@query-change when the parent page should reload server-side search, filters, sorting, or pagination.

Relation managers inherit the Panel's semantic theme contract: dialog scrims, surface rings, breadcrumbs, forms, tables, and action buttons all consume the same --inlay-* variables. If a relation manager is mounted standalone, set the same variables on its host (or pass a local theme to its Form/Table) rather than adding palette-specific Tailwind classes.

Every related record is resolved again through the owner's Eloquent relationship. Create, edit, and delete support HasOne, HasMany, MorphOne, MorphMany, BelongsToMany, and MorphToMany where Eloquent permits the operation. Attach/detach endpoints are limited to BelongsToMany and MorphToMany. Mutation forms require a centralized validation class and writes run in transactions. Parent Resource authorization and relation-specific authorization both run before mutation.

Relation managers support the same soft-delete preset as top-level Resources. Use Laravel's SoftDeletes trait on the related model and enable it on the manager:

This adds the TrashedFilter, conditional Delete/Restore/Force delete row actions, query-wide bulk equivalents, hosted Action endpoints, and beforeRestore(), afterRestore(), beforeForceDelete(), and afterForceDelete() hooks. Trashed records remain hidden by default but can be resolved for authorized lifecycle actions through the owner's relationship; soft deletion never weakens owner or tenant scoping. Read-only managers retain the filter but omit mutation actions. Custom definitions using the preset names win.

For many-to-many managers, the React and Vue renderers automatically add an Attach button, a remote searchable Select form, and a confirmed Detach row action. The chooser excludes records already connected to the owner. Scope the candidate query for tenancy, visibility, guard, or archival rules:

That scope is enforced both while searching and while resolving a submitted identifier, so a forged out-of-scope identifier cannot be attached. canAccess(RelationOperation::Attach, null, $user) controls whether the chooser is exposed; authorization runs again with the resolved candidate before syncWithoutDetaching(). Detach always resolves through the owner's existing relationship.

Attach forms may collect pivot attributes using the same Form components and centralized validation used elsewhere:

The relationship must explicitly expose writable columns:

RoleAssignmentRules is application code and can return rules for record and assignment_note when the operation is relation.attach. Inlay merges field rules with the centralized rules, validates the remote record option against modifyAttachQuery(), removes undeclared input, and passes only withPivot() columns to Eloquent. A field not declared by withPivot() causes configuration to fail instead of silently writing arbitrary pivot state.

Use the normal relation-manager form() to edit related-model and pivot attributes together, matching the documented contract:

On create, Inlay inserts the related record and attaches it with the validated pivot state. On edit, it updates related attributes and calls updateExistingPivot() for declared pivot attributes in the same transaction. The edit dialog is available independently of create authorization, so pivot-only managers can allow RelationOperation::Edit while denying RelationOperation::Create. Pivot columns appear as root Table row attributes (assignment_note, not pivot.assignment_note) because that is how Eloquent relationship queries expose them.

For HasMany and MorphMany managers, Inlay exposes the equivalent Associate button, remote searchable Select, and confirmed Dissociate row action. Association may claim an unowned record or move a record from another owner, matching Eloquent and the documented contract semantics. Constrain that behavior explicitly:

The same scope is applied to chooser searches and submitted identifiers. canAccess(RelationOperation::Associate, $candidate, $user) runs before Eloquent reassigns the foreign key. Dissociation resolves only through the owner's current relationship, authorizes Dissociate, and transactionally nulls the foreign key (and morph type for MorphMany). The relationship columns must therefore be nullable when dissociation is enabled.

Customize persistence safely

Default create/update uses Eloquent fill() and save() inside a database transaction. Relationship-managed field state is separated before fill() and saved after the owner model. Override narrow hooks instead of replacing controllers:

Advanced resources may override handleRecordCreation() or handleRecordUpdate() for services or aggregate writes. Returned records must remain instances of the declared model; exceptions roll the transaction back.

Soft deletes

Use Laravel's SoftDeletes trait on the model and enable the resource preset:

That single flag adds:

When Laravel policies are enabled, define the matching methods:

Custom actions or a custom filter with the same preset name win; Inlay only adds missing trashed, delete, restore, and force-delete definitions.

Tenancy

A resource can belong to a tenant. Declare the relationship on the model that owns it:

Set the current tenant once per request, usually from middleware or a panel:

Every query the resource runs — list, action, and record resolution — is constrained to that tenant, so another tenant's record cannot be listed, opened, or acted on by key. A created record joins the tenant by having the key written server-side, so a forged team_id in the payload is overwritten rather than honoured. BelongsTo and BelongsToMany ownership are both supported.

A tenant-scoped resource with no current tenant refuses to read at all rather than returning every tenant's records.

Register tenant-aware routes to resolve the tenant from the URL instead:

Every URL gains the tenant segment — /{team}/admin/projects — and every route, mutation routes included, resolves the tenant before the controller runs. Membership is decided by the model, not the URL: implement TenantAccess on the tenant to refuse a visitor who is not a member.

An unknown tenant is a 404, and the resolved tenant is forgotten when the request ends. Relation managers need no extra configuration: they hang off a record the resource resolved, so another tenant's owner is already unreachable.

Security guarantees

Parent-scoped nested resource URLs, fluent Relation Groups, and accessible relation tabs are available. Resource and Relation Manager soft-delete query, filter, row/bulk action, lifecycle-hook, React, Vue, testing, and playground support is available. The core Relation Manager contract, scoped CRUD, validated pivot-aware create/attach/edit forms, secure remote attach/detach and associate/dissociate UI, generation, automatic React/Vue composition, and read-only view behavior are available now.

Testing Resources

The package autoloads a global inlay() test helper with familiar fluent APIs:

Tenant-scoped resources are driven the same way:

forTenant() applies for everything that follows, withoutTenant() clears it, and tenant() returns the current one. The DSL runs the same scoped query a request does, so parent-resource and tenant scoping are both exercised.

Forms run through the Resource's real centralized validation and persistence lifecycle:

Edit forms and editable table columns are equally direct:

Row, header, and bulk actions use the same ActionRunner as production routes. Authorization, scoped record lookup, mounted form defaults, validation, hooks, transactions, and lifecycle results are exercised rather than mocked:

Use selectAllTableRecords() for the table's authorized query-wide mode and pass excluded records when required. Invalid forms and selection counts are available through assertHasTableActionErrors(). Interrupted lifecycles use assertTableActionHalted() and assertTableActionCancelled(). Unexpected exceptions and authorization failures are deliberately not swallowed.

Every table interaction rebuilds the configured Table through getEloquentQuery(). Every mutation runs Resource authorization, centralized Laravel validation, transactions, relationship persistence, and lifecycle hooks. The helper therefore does not bypass the boundaries that production requests rely on.

The root Pest suite contains contract and lifecycle coverage; the Laravel playground verifies the complete panel route stack. HTTP feature tests remain important for middleware, routing, redirects, Precognition, uploads, and Inertia delivery.


All versions of resources with dependencies

PHP Build Version
Package Version
Requires php Version ^8.3
illuminate/console Version ^12.0 || ^13.0
illuminate/container Version ^12.0 || ^13.0
illuminate/database Version ^12.0 || ^13.0
illuminate/filesystem Version ^12.0 || ^13.0
illuminate/http Version ^12.0 || ^13.0
illuminate/routing Version ^12.0 || ^13.0
illuminate/support Version ^12.0 || ^13.0
inertiajs/inertia-laravel Version ^3.0
inlayphp/actions Version ^0.3 || dev-main
inlayphp/forms Version ^0.3 || dev-main
inlayphp/authorization Version ^0.3 || dev-main
inlayphp/infolists Version ^0.3 || dev-main
inlayphp/panels Version ^0.3 || dev-main
inlayphp/support Version ^0.3 || dev-main
inlayphp/tables Version ^0.3 || dev-main
inlayphp/validation Version ^0.3 || dev-main
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package inlayphp/resources contains the following files

Loading the files please wait ...