Skip to main content

Resources

A resource is the Qore definition for one Eloquent model.

Resources extend QoreResource<TModel> and describe how that model appears in Qore: CRUD pages, fields, permissions, actions, relation tables, global search, logbook entries and URLs.

Use a resource when a model needs the standard application surface. A working resource normally has five app pieces:

  • the resource class;
  • registration in AppServiceProvider;
  • seeded permissions;
  • a model policy;
  • a menu item.

Create A Resource Class

Create the resource in app/Resources. This example assumes an App\Models\Product model with name and price columns.

<?php

namespace App\Resources;

use App\Models\Product;
use Illuminate\Database\Eloquent\Model;
use Qore\Next\System\Field\Field;
use Qore\Next\System\Fields\CreatedAtField;
use Qore\Next\System\Fields\NumberField;
use Qore\Next\System\Fields\TextField;
use Qore\Next\System\Fields\UpdatedAtField;
use Qore\Next\System\Resource\QoreResource;

/**
* @extends QoreResource<Product>
*/
class ProductResource extends QoreResource
{
/**
* @return class-string<Product>
*/
public function modelClass(): string
{
return Product::class;
}

public function labelSingular(): string
{
return __('common.products.singular');
}

public function labelPlural(): string
{
return __('common.products.plural');
}

/**
* @param Product $model
*/
public function modelTitle(Model $model): string
{
return $model->name;
}

public function icon(): string
{
return 'package';
}

/**
* @return Field[]
*/
public function fields(): array
{
return [
TextField::make('name', __('common.name'))
->setRules(fn () => ['required', 'string', 'max:255']),

NumberField::make('price', __('common.price'))
->setRules(fn () => ['required', 'numeric', 'min:0'])
->setPrecision(2),

CreatedAtField::make(),
UpdatedAtField::make(),
];
}
}

ProductResource becomes the resource name products. Qore uses that name for default URLs and permission names, such as view any products.

At minimum a resource defines:

  • modelClass()
  • labelSingular()
  • labelPlural()
  • icon()
  • fields()

Register The Resource

Register resources in AppServiceProvider::register() so Qore can expose their routes, globals, relation options and menu metadata.

use App\Resources\ProductResource;

use function Qore\Next\System\Helpers\qore;

public function register(): void
{
qore()
->registerResource(new UserResource)
->registerResource(new ProductResource);
}

Registering the resource does not grant access by itself. Permissions and policies still decide what the user may do.

Seed Permissions

Add CRUDA permissions for the resource in database/seeders/PermissionSeeder.php.

use Illuminate\Database\Seeder;
use Qore\Next\System\Models\Permission;

use function Qore\Next\System\Helpers\admin_role;
use function Qore\Next\System\Helpers\qore;

class PermissionSeeder extends Seeder
{
public function run(): void
{
qore()->permissions()->cruda('products');

admin_role()->givePermissions(Permission::query()->select('id')->get());
}
}

cruda('products') creates the default resource permissions:

  • view any products
  • view products
  • create products
  • update products
  • delete products

Use the same resource name everywhere unless the resource overrides its permission methods. See Permissions for custom permission names.

Create The Policy

Create a policy for the model in app/Policies/ProductPolicy.php.

namespace App\Policies;

use App\Models\Product;
use App\Models\User;

class ProductPolicy
{
public function viewAny(User $user): bool
{
return $user->hasPermissionToViewAny('products');
}

public function view(User $user, Product $model): bool
{
return $user->hasPermissionToView('products', $model);
}

public function create(User $user): bool
{
return $user->hasPermissionToCreate('products');
}

public function update(User $user, Product $model): bool
{
return $user->hasPermissionToUpdate('products', $model);
}

public function delete(User $user, Product $model): bool
{
return $user->hasPermissionToDelete('products', $model);
}
}

Laravel auto-discovers policies that follow the normal App\Models\Product and App\Policies\ProductPolicy naming convention. Register the policy manually only when the class lives outside that convention:

Gate::policy(Product::class, ProductPolicy::class);

Add It To The Menu

Add the resource to the application menu, usually in app/Menu/AppMenu.php.

use function Qore\Next\System\Helpers\qore;

$this->addResourceMenuItem(resource: qore()->getResourceOrFail('products'));

addResourceMenuItem() uses the resource label, icon, index URL and getViewAnyPermissions() automatically. If the user cannot viewAny, the frontend hides the menu item from the globals payload.

Resource Checklist

When a resource does not show up, check these in order:

  1. The resource is registered in AppServiceProvider::register().
  2. The resource name used in permissions matches ProductResource -> products.
  3. The permission seeder has run and the current role has the permissions.
  4. The policy returns true for the action you are testing.
  5. The menu includes the resource or a custom menu item that points to it.

Common Overrides

Most resources start with the required methods and override only what changes the user experience:

  • modelTitle(Model $model): string for readable titles.
  • indexQuery(): Builder for default scoping and eager loading.
  • indexTabs(): TableTab[] for index table tabs.
  • indexLayout(): Node, createLayout(): Node, detailLayout(Model $model): Node and editLayout(Model $model): Node for custom page layouts.
  • actions(): ResourceAction[] for bulk and detail actions.
  • alerts(): ResourceAlert[] for detail-page warnings or notices.
  • getGlobalSearchFields(): Field[] and globalSearchNode(Model $model): Node for search behaviour.

See the focused pages for the details: