PHPackages                             adithwidhiantara/crud - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. adithwidhiantara/crud

ActivePackage[Utility &amp; Helpers](/categories/utility)

adithwidhiantara/crud
=====================

Generate Simple CRUD

1.3.2(3mo ago)25MITPHPPHP ^8.2CI passing

Since Dec 30Pushed 3mo agoCompare

[ Source](https://github.com/adith-widhiantara/crud)[ Packagist](https://packagist.org/packages/adithwidhiantara/crud)[ RSS](/packages/adithwidhiantara-crud/feed)WikiDiscussions v1 Synced 1mo ago

READMEChangelogDependencies (9)Versions (8)Used By (0)

Laravel Advanced CRUD Generator
===============================

[](#laravel-advanced-crud-generator)

[![codecov](https://camo.githubusercontent.com/80bc879f7c0a00e588e62f8fa1fd3aa96f24a007e1c9522f9ef49ccbf5b217fe/68747470733a2f2f636f6465636f762e696f2f6769746875622f61646974682d7769646869616e746172612f637275642f67726170682f62616467652e7376673f746f6b656e3d3353355553345a584738)](https://codecov.io/github/adith-widhiantara/crud)

**Laravel CRUD Generator** is a powerful package designed to accelerate backend development. It provides a full suite of features including **Auto-Discovery Routes**, **Dynamic Database Schema Validation**, **Bulk Operations**, and **Service-Repository Pattern** out of the box.

Stop writing repetitive boilerplate code. Just run one command and you are ready to go! 🚀

✨ Features
----------

[](#-features)

- **⚡ Rapid Generation**: Generate Model, Controller, Service, Factory, Migration, and Unit Test in one command.
- **🛣️ Auto-Discovery Routes**: No need to manually define routes in `api.php`. Routes are automatically registered based on your controller.
- **🛡️ Dynamic Validation**: Validation rules are automatically generated by inspecting your Database Schema (supports MySQL &amp; PostgreSQL).
- **📦 Bulk Operations**: Built-in support for Bulk Create, Bulk Update, and Bulk Delete in a single atomic transaction.
- **mj Service Pattern**: Clean architecture separation using Service classes with built-in Hooks (`beforeCreate`, `afterCreate`, etc).
- **🧪 Ready-to-use Tests**: Automatically generates Feature Tests that cover standard CRUD scenarios.

📦 Installation
--------------

[](#-installation)

Requires **PHP 8.2+** and **Laravel 11+**.

```
composer require adithwidhiantara/crud
```

🚀 Quick Start
-------------

[](#-quick-start)

### 1. Generate CRUD

[](#1-generate-crud)

Run the magic command to generate everything you need:

```
php artisan make:crud Product
```

This command will generate:

- `app/Models/Product.php`
- `app/Http/Controllers/ProductController.php`
- `app/Http/Services/ProductService.php`
- `database/migrations/xxxx_create_products_table.php`
- `database/factories/ProductFactory.php`
- `tests/Feature/ProductControllerTest.php`

### 2. Update Migration

[](#2-update-migration)

Open the generated migration file and define your table schema:

```
Schema::create('products', function (Blueprint $table) {
    $table->id();
    $table->string('name'); // Auto-detected as 'required|string|max:255'
    $table->text('description')->nullable(); // Auto-detected as 'nullable|string'
    $table->integer('price')->default(0); // Auto-detected as 'integer' (optional input)
    $table->timestamps();
});
```

### 3. Migrate &amp; Enjoy

[](#3-migrate--enjoy)

Run the migration and your API is ready!

```
php artisan migrate
```

You can now access your API at:

- `GET /api/products`
- `POST /api/products`
- `GET /api/products/{id}`
- `PUT /api/products/{id}`
- `DELETE /api/products/{id}`
- `POST /api/products/bulk`

---

📖 Deep Dive
-----------

[](#-deep-dive)

### 🛡️ Dynamic Validation

[](#️-dynamic-validation)

You **don't need** to write validation rules manually. The package inspects your database columns to generate rules:

- **Type**: `varchar(20)` → `string|max:20`
- **Nullable**: `nullable()` → `nullable` rule.
- **Default**: Has `default` value → Field becomes optional.
- **PostgreSQL Support**: Fully supports Postgres specific types and length constraints.

If you need custom rules, simply override the `rules()` method in your Controller's Request class (or creating a custom Request).

### 📦 Bulk Operations

[](#-bulk-operations)

The `/bulk` endpoint allows you to perform multiple operations in a **Single Database Transaction**.

**Endpoint:** `POST /api/products/bulk`

**Payload Example:**

```
{
  "create": [
    {
      "name": "Laptop",
      "price": 15000000
    },
    {
      "name": "Mouse",
      "price": 200000
    }
  ],
  "update": {
    "10": {
      "price": 14500000
    },
    "12": {
      "name": "Gaming Mouse"
    }
  },
  "delete": [
    15,
    16,
    17
  ]
}
```

*If any operation fails, the entire transaction is rolled back.*

### ⚙️ Model Configuration

[](#️-model-configuration)

Your models (extending CrudModel) have two powerful methods to control the API output and Validation behavior.

1. getShowOnListColumns() This method is mandatory. It determines which columns are returned when calling the List Endpoint (GET /api/products). This helps optimize performance by selecting only necessary fields for table views.
2. ignoredColumns() This method controls the Auto-Validation Generator. By default, the generator ignores system columns (id, created\_at, updated\_at, deleted\_at).

If you have sensitive columns (like api\_token, password\_hash, is\_admin) or calculated columns that should NOT be validated or accepted from the Request payload, override this method.

Here is the English translation for your documentation:

### 🔍 Filtering, Searching &amp; Sorting

[](#-filtering-searching--sorting)

This package provides secure and powerful query manipulation features out-of-the-box.

#### 1. Filtering

[](#1-filtering)

You can filter results based on specific columns. By default, **no columns are filterable** for security reasons. You must allow them in your Model.

**In Model (`App\Models\Product.php`):**

```
public function filterableColumns(): array
{
    return ['status', 'category_id', 'price', 'created_at'];
}
```

**API Usage:**

- **Exact Match:** `/api/products?filter[status]=active`
- *Query:* `WHERE products.status = 'active'`
- **Multiple Values (IN):** `/api/products?filter[category_id][]=1&filter[category_id][]=5`
- *Query:* `WHERE products.category_id IN (1, 5)`
- **Null Checks:** `/api/products?filter[deleted_at]=null` (or `!null`)
- *Query:* `WHERE products.deleted_at IS NULL`

##### Advanced Operators (Range Filtering)

[](#advanced-operators-range-filtering)

You can use logical operators for range filtering. Supported operators: `eq`, `gt`, `gte`, `lt`, `lte`, `like`, `between`.

- **Greater/Less Than:** `/api/products?filter[price][gte]=1000&filter[price][lte]=5000`
- *Query:* `WHERE products.price >= 1000 AND products.price  **Note:** All filter columns are automatically qualified with the table name (e.g., `products.price`) to prevent " Ambiguous Column" errors during joins.

---

#### 2. Global Search (Fuzzy)

[](#2-global-search-fuzzy)

The search feature allows text searching (`LIKE %keyword%`) across multiple columns simultaneously using `OR` logic. It supports searching within **Nested Relationships**.

**In Model:**

```
public function searchableColumns(): array
{
    return [
        'name',             // Search in current table
        'category.name',    // Search in 'category' relation
        'tags.title',       // Search in 'tags' relation
    ];
}
```

**API Usage:**

- **Search:** `/api/products?search=laptop`
- *Logic:* `AND (products.name LIKE '%laptop%' OR category.name LIKE '%laptop%' ...)`

---

#### 3. Dynamic Sorting

[](#3-dynamic-sorting)

You can sort results dynamically. Define allowed columns in `sortableColumns()`.

**In Model:**

```
public function sortableColumns(): array
{
    return ['price', 'created_at', 'name'];
}
```

**API Usage:**

- **Ascending:** `/api/products?sort=price`
- **Descending:** `/api/products?sort=-price` (Add `-` prefix)

---

#### 4. Custom Query (Hook)

[](#4-custom-query-hook)

Use `extendQuery` in your Service to add custom logic (scopes, joins, etc.) without overriding the main `getAll` method.

**In Service:**

```
protected function extendQuery(Builder $query): Builder
{
    // Example: Only show own data if not admin
    if (!auth()->user()->isAdmin()) {
        $query->where('user_id', auth()->id());
    }

    return $query;
}
```

The video below explains the common ambiguous column error in Laravel queries, which your new code now prevents.

[Resolving the ambiguous column error in your Laravel Eloquent left join query](https://www.youtube.com/watch?v=3fds4NGJIxg)

### 🏗️ Defining Columns &amp; Relations (Strict Mode)

[](#️-defining-columns--relations-strict-mode)

In `BaseCrudService`, you are required to define which columns to display by implementing the `getShowOnListColumns()`method.

**Important:** Starting from this version, **Strict Mode** is enforced. You **must** define at least one column from the main table. If you intend to select all columns, you must explicitly specify it as `['*']`. The system will throw an `InvalidArgumentException` if no local columns are defined to prevent accidental `SELECT *` queries.

#### Auto-Load Relations

[](#auto-load-relations)

You can define columns from related tables using the *dot-notation* format (`relation.column`). The service will automatically handle efficient *Eager Loading* (Partial Select).

Implementation example in your Service:

```
public function getShowOnListColumns(): array
{
    return [
        // Local Columns (At least one is required)
        'id',
        'title',
        'status',

        // Relations (Automatically loaded via Eager Loading)
        // Syntax: 'relation_name.column_name'
        'author.name',    // Will execute: with('author:id,name')
        'category.slug',  // Will execute: with('category:id,slug')
    ];
}
```

### 🪝 Service Hooks

[](#-service-hooks)

You can intervene in the CRUD process by overriding hooks in your **Service** class ( `app/Http/Services/ProductService.php`).

```
public function beforeCreateHook(array $data): array
{
    // Modify data before saving to DB
    $data['slug'] = Str::slug($data['name']);
    $data['user_id'] = auth()->id();

    return $data;
}

public function afterCreateHook(CrudModel $model): CrudModel
{
    // Trigger actions after save (e.g., Send Email)
    Mail::to(auth()->user())->send(new ProductCreated($model));

    return $model;
}
```

### 🛣️ Custom Endpoints

[](#️-custom-endpoints)

To add a custom route to your controller that is automatically discovered, use the `#[Endpoint]` attribute.

```
use Adithwidhiantara\Crud\Attributes\Endpoint;

class ProductController extends BaseCrudController
{
    #[Endpoint(method: 'POST', uri: 'publish/{id}')]
    public function publish($id)
    {
        $this->service()->publish($id);
        return response()->json(['message' => 'Published!']);
    }
}
```

Result: `POST /api/products/publish/{id}`

---

✅ Testing
---------

[](#-testing)

The package automatically generates feature tests for your CRUD. To run them:

```
php artisan test
```

🚀 Performance
-------------

[](#-performance)

This package is designed for speed. Benchmarks show **less than 1ms overhead** compared to native Eloquent queries. See full [Benchmark Results](benchmark-result.md).

Ensure you have set up your `phpunit.xml` or `.env.testing` database configuration.

---

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance79

Regular maintenance activity

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~5 days

Total

7

Last Release

110d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/a9fcb175983dc323f8c81f4204771a22e22477fba78c30a3961b252c1a41619b?d=identicon)[adith-widhiantara](/maintainers/adith-widhiantara)

---

Top Contributors

[![adith-widhiantara](https://avatars.githubusercontent.com/u/54925429?v=4)](https://github.com/adith-widhiantara "adith-widhiantara (60 commits)")

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/adithwidhiantara-crud/health.svg)

```
[![Health](https://phpackages.com/badges/adithwidhiantara-crud/health.svg)](https://phpackages.com/packages/adithwidhiantara-crud)
```

###  Alternatives

[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k25.9M107](/packages/laravel-cashier)[psalm/plugin-laravel

Psalm plugin for Laravel

3274.9M308](/packages/psalm-plugin-laravel)[watson/active

Laravel helper for recognising the current route, controller and action

3253.6M14](/packages/watson-active)[api-platform/laravel

API Platform support for Laravel

59126.4k6](/packages/api-platform-laravel)[aedart/athenaeum

Athenaeum is a mono repository; a collection of various PHP packages

245.2k](/packages/aedart-athenaeum)[dragon-code/pretty-routes

Pretty Routes for Laravel

10058.7k4](/packages/dragon-code-pretty-routes)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
