PHPackages                             tahamiskini/crudify - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. tahamiskini/crudify

ActiveLibrary[Framework](/categories/framework)

tahamiskini/crudify
===================

Generic CRUD controller for Laravel.

v0.1.0(1mo ago)12MITPHPPHP ^8.2

Since Jul 8Pushed 4w agoCompare

[ Source](https://github.com/tahamiskini/Crudify)[ Packagist](https://packagist.org/packages/tahamiskini/crudify)[ RSS](/packages/tahamiskini-crudify/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (2)Versions (6)Used By (0)

Laravel Crudify — Generic CRUD Controller for Laravel
=====================================================

[](#laravel-crudify--generic-crud-controller-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/7d5ded6a8bfe85c44032246c9b333b3c7325baddf8de620122901eccb87c30ae/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f746168616d69736b696e692f637275646966792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/tahamiskini/crudify)[![Total Downloads](https://camo.githubusercontent.com/972135b01131551970b2d1c837bb42c15c134cdd469c073ebc82d6eb375d2b1a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f746168616d69736b696e692f637275646966792e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/tahamiskini/crudify)[![License](https://camo.githubusercontent.com/d9999c789f5e090e50c5772039fdeb9d5bf3e540eb45b86236584adef6ef7dfb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f746168616d69736b696e692f637275646966793f7374796c653d666c61742d737175617265)](https://github.com/tahamiskini/crudify/blob/main/LICENSE.md)

Crudify eliminates repetitive boilerplate by providing a single, convention-based CRUD controller for all your Eloquent models. One `Route::crud()` call gives you a full RESTful API — including mass operations, relation management, query filtering, and event hooks.

**When to use it:** CRUD-heavy, convention-driven codebases — admin panels, REST APIs, back-office dashboards where most models follow a predictable create/read/update/delete pattern.

**When to skip it:** Heavily event-driven/CQRS architectures, endpoints with unique business rules per operation, read-only or calculation-heavy apps, or cases where every response needs a completely custom format.

- [Installation](#installation)
- [Usage](#usage)
    - [Quick Start](#quick-start)
    - [Route Macro](#route-macro)
    - [Convention &amp; Auto-Discovery](#convention--auto-discovery)
    - [Naming Conventions &amp; Customization](#naming-conventions--customization)
- [API Endpoints](#api-endpoints)
    - [Single-Resource CRUD](#single-resource-crud)
    - [Mass Operations](#mass-operations)
    - [Relation Management](#relation-management)
- [Form Requests (Validation)](#form-requests-validation)
- [Policies (Authorization)](#policies-authorization)
- [Query Filtering &amp; Sorting](#query-filtering--sorting)
    - [Built-in Filter Operators](#built-in-filter-operators)
    - [Custom Filter Operators](#custom-filter-operators)
    - [Includes (Eager Loading)](#includes-eager-loading)
    - [Sorting](#sorting)
- [API Resources (Response Transformation)](#api-resources-response-transformation)
- [Events](#events)
- [Configuration](#configuration)
- [Auto-Generate Routes](#auto-generate-routes)
- [Extending the Controller](#extending-the-controller)
- [Testing](#testing)
- [Changelog](#changelog)
- [Contributing](#contributing)
- [License](#license)

Installation
------------

[](#installation)

```
composer require tahamiskini/crudify
```

Publish the config file:

```
php artisan vendor:publish --tag="crudify-config"
```

Usage
-----

[](#usage)

### Quick Start

[](#quick-start)

Create a model, policy, and form request following the naming conventions, then register the routes:

```
// routes/api.php
use App\Models\Post;
use Illuminate\Support\Facades\Route;

Route::crud('posts', Post::class);
```

That's it. You now have a full CRUD API at `/api/posts`.

### Route Macro

[](#route-macro)

The `Route::crud()` macro registers **13 endpoints** for a given resource:

```
Route::crud('posts', Post::class);
```

**Signature:**

```
Route::crud(
    string $resource,        // URI segment, e.g. 'posts'
    string $model,           // Model class, e.g. Post::class
    array $options = []      // Optional: ['namespace' => 'App']
);
```

Options:

- `namespace` — Override the root namespace (default: `App`)

### Convention &amp; Auto-Discovery

[](#convention--auto-discovery)

Crudify resolves models, form requests, and policies by convention:

ComponentConventionExample**Model**`{namespace}\Models\{ModelName}``App\Models\Post`**Form Request**`{namespace}\Http\Requests\{ModelName}Request``App\Http\Requests\PostRequest`**Policy**`{namespace}\Policies\{ModelName}Policy``App\Policies\PostPolicy`**Fallback Policy**`Taha\Crudify\Policies\CrudifyPolicy` (permissive)—If a form request class does not exist, the controller falls back to `CrudifyRequest` (no validation). If a policy class does not exist, it falls back to `CrudifyPolicy` (all operations allowed).

### Naming Conventions &amp; Customization

[](#naming-conventions--customization)

For a model named `Post`, the following files are auto-discovered:

```
app/
├── Models/
│   └── Post.php
├── Http/
│   └── Requests/
│       └── PostRequest.php
└── Policies/
    └── PostPolicy.php

```

The `studly()` method handles kebab-case and snake-case conversion:

- `blog-post` → `BlogPost`
- `blog_post` → `BlogPost`

API Endpoints
-------------

[](#api-endpoints)

All endpoints are registered under the configured prefix (default: `api`).

### Single-Resource CRUD

[](#single-resource-crud)

MethodURIController MethodDescription`GET``/api/posts``readMore`Paginated list (supports `?trashed=only|with`)`GET``/api/posts/{id}``readOne`Single resource (supports `?trashed=with`)`POST``/api/posts``create`Create resource`PUT`/`PATCH``/api/posts/{id}``update`Update resource`DELETE``/api/posts/{id}``delete`Delete resource (returns 204)`POST``/api/posts/restore/{id}``restore`Restore a soft-deleted resource`DELETE``/api/posts/force-delete/{id}``forceDelete`Permanently delete a resource**Response format** (single resource):

```
{
  "data": {
    "id": 1,
    "title": "Hello World",
    "body": "My first post",
    "published": true,
    "created_at": "2026-01-01T00:00:00.000000Z",
    "updated_at": "2026-01-01T00:00:00.000000Z"
  }
}
```

**Response format** (paginated list):

```
{
  "data": [
    { "id": 1, "title": "Hello World", ... }
  ],
  "links": { ... },
  "meta": { "current_page": 1, "last_page": 1, "per_page": 20, "total": 3 }
}
```

### Mass Operations

[](#mass-operations)

MethodURIController MethodDescription`POST``/api/posts/mass-create``massCreate`Create multiple records`PUT`/`PATCH``/api/posts/mass-update``massUpdate`Update multiple records`DELETE``/api/posts/mass-delete``massDelete`Delete multiple records`POST``/api/posts/mass-create-or-update``massCreateOrUpdate`Upsert records**Mass create request:**

```
{
  "items": [
    { "title": "Post 1", "body": "Content 1" },
    { "title": "Post 2", "body": "Content 2" }
  ]
}
```

**Mass update request:**

```
{
  "items": [
    { "id": 1, "title": "Updated Title" },
    { "id": 2, "title": "Another Update" }
  ]
}
```

**Mass delete request:**

```
{
  "items": [
    { "id": 1 },
    { "id": 2 }
  ]
}
```

**Mass create-or-update request:**

```
{
  "items": [
    { "id": 1, "title": "Update existing" },
    { "title": "Create new" }
  ]
}
```

### Relation Management

[](#relation-management)

Crudify supports managing Eloquent relationships through dedicated endpoints.

MethodURIDescription`POST``/api/posts/{id}/add-relation/{relationField}`Add a related model (create child for HasMany / attach pivot for BelongsToMany without detaching)`DELETE``/api/posts/{id}/remove-relation/{relationField}/{relationId?}`Remove a related model (delete child / detach pivot)`POST``/api/posts/{id}/attach-relation/{relationField}/{relationId}`Attach an existing model to the relation (reassign HasMany / sync-without-detach for BelongsToMany)`DELETE``/api/posts/{id}/detach-relation/{relationField}/{relationId}`Detach a related model (remove pivot / nullify FK)**Example — add a tag to a post (BelongsToMany):**

```
curl -X POST /api/posts/1/add-relation/tags \
  -H 'Content-Type: application/json' \
  -d '{"name": "New Tag"}'
```

**Example — attach existing tag (BelongsToMany):**

```
curl -X POST /api/posts/1/attach-relation/tags/5
```

**Example — remove (detach) a tag:**

```
curl -X DELETE /api/posts/1/detach-relation/tags/5
```

**Example — add a comment to a post (HasMany):**

```
curl -X POST /api/posts/1/add-relation/comments \
  -H 'Content-Type: application/json' \
  -d '{"body": "Great post!"}'
```

**Supported relation types:**

Relation Typeaddremoveattachdetach`BelongsToMany` / `MorphToMany`Creates related model + syncs without detachDetaches pivotSyncs without detachDetaches pivot`HasMany` / `MorphMany`Creates childDeletes childReassigns child FKNullifies child FK`BelongsTo`————`HasOne`————`MorphTo`————Form Requests (Validation)
--------------------------

[](#form-requests-validation)

Create a form request following the naming convention to define validation rules:

```
