rizkussef/laravel-core-crud

A clean, scalable Core CRUD architecture for Laravel with advanced filtering, eager-loading relationships, and automatic resource resolution

Maintainers

Package info

github.com/RizkUssef/laravel-core-crud

Homepage

pkg:composer/rizkussef/laravel-core-crud

Statistics

Installs: 8

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.2.0 2026-02-23 23:27 UTC

This package is auto-updated.

Last update: 2026-02-26 21:24:32 UTC


README

Latest Version on Packagist Total Downloads License

A clean, scalable Core CRUD architecture for Laravel, built around a reusable Base Service and Base Controller with automatic:

  • ✅ Model Resolution
  • ✅ Resource Resolution
  • ✅ Collection Handling
  • ✅ Pagination
  • ✅ Advanced Filtering (=, !=, >, <, >=, <=, LIKE, IN, BETWEEN, NULL checks, Date operations)
  • ✅ Eager Loading Relationships
  • ✅ API Response Formatting

Designed to eliminate repetitive CRUD logic while keeping your application clean and maintainable. Pass filters and relationships directly from your frontend to dynamically build optimized queries with full control over data retrieval.

📦 Installation

Install via Composer:

composer require rizkussef/laravel-core-crud

If needed, manually register the provider in:

config/app.php
Rizkussef\LaravelCoreCrud\CoreCrudServiceProvider::class,

⚙️ Publish Configuration

php artisan vendor:publish --provider="Rizkussef\LaravelCoreCrud\CoreCrudServiceProvider" --tag=config

This will publish:

config/core-crud.php

Example:

return [
    'paginate' => 15,
];

🏗 Architecture

App
 ├── Models
 │     └── User.php
 ├── Services
 │     └── UserService.php
 ├── Http
 │     ├── Controllers
 │     │      └── UserController.php
 │     └── Resources
 │            └── UserResource.php

🚀 Quick Start

1️⃣ Create a Service

namespace App\Services;

use Rizkussef\LaravelCoreCrud\Services\CoreCrudService;

class UserService extends CoreCrudService
{
    // Add custom business logic here if needed
}

🔎 Automatic Model & Resource Resolution

UserService → App\Http\Resources\UserResource
UserService → App\Models\User

No need to manually define the model or resource.

2️⃣ Create a Controller

namespace App\Http\Controllers;

use App\Services\UserService;
use Rizkussef\LaravelCoreCrud\Http\Controllers\CoreCrudController;

class UserController extends CoreCrudController {
    public function __construct(UserService $service)
    {
        parent::__construct($service);
    }
}

Just Inject the specific service for this controller.

� Filters & Relationships

The package includes powerful filtering and eager-loading capabilities. Pass filters and relationships from the frontend to dynamically build queries.

Available Filter Operators

Comparison Operators

// Equal / Greater Than / Less Than
['age' => ['operator' => '=', 'value' => 25]]
['age' => ['operator' => '>', 'value' => 18]]
['age' => ['operator' => '>=', 'value' => 18]]
['age' => ['operator' => '<', 'value' => 65]]
['age' => ['operator' => '<=', 'value' => 65]]
['status' => ['operator' => '!=', 'value' => 'deleted']]

String Matching

// LIKE search (wildcard)
['name' => ['operator' => 'like', 'value' => 'John']]

// Starts with
['email' => ['operator' => 'starts_with', 'value' => 'admin']]

// Ends with
['email' => ['operator' => 'ends_with', 'value' => '.com']]

// Simple value (auto LIKE for strings)
['name' => 'John']  // Searches LIKE "%John%"

Array Operations

// Multiple values
['status' => ['operator' => 'in', 'value' => ['active', 'pending']]]

// Exclude values
['status' => ['operator' => 'not_in', 'value' => ['deleted', 'banned']]]

// Range
['price' => ['operator' => 'between', 'value' => [100, 500]]]
['price' => ['operator' => 'not_between', 'value' => [100, 500]]]

NULL Checks

['deleted_at' => ['operator' => 'null']]      // IS NULL
['verified_at' => ['operator' => '!null']]    // IS NOT NULL
['verified_at' => ['operator' => 'not_null']]

Date Operations

['created_at' => ['operator' => 'date', 'value' => '2024-02-23']]
['created_at' => ['operator' => 'year', 'value' => 2024]]
['created_at' => ['operator' => 'month', 'value' => 2]]
['created_at' => ['operator' => 'day', 'value' => 23]]

Frontend Examples

Axios Example

import axios from 'axios';

const fetchUsers = async () => {
  const { data } = await axios.post('/api/users/Paginate', {
    filters: {
      status: 'active',
      age: { operator: '>', value: 18 }
    },
    relationships: ['profile', 'comments'],
    perPage: 15
  });
  
  console.log(data);
};

Backend Services Examples

Another Service Calling This Service

namespace App\Services;

use App\Services\UserService;

class ReportService
{
    public function __construct(private UserService $userService) {}

    /**
     * Generate active users report
     */
    public function getActiveUsersReport()
    {
        $filters = [
            'status' => 'active',
            'created_at' => [
                'operator' => 'date',
                'value' => now()->subMonth()->format('Y-m-d')
            ]
        ];

        $relationships = ['profile', 'department'];

        return $this->userService->index($filters, $relationships);
    }

    /**
     * Get premium users with pagination
     */
    public function getPremiumUsers($page = 1)
    {
        $filters = [
            'subscription_type' => 'premium',
            'last_payment_date' => [
                'operator' => '!=null'
            ]
        ];

        $relationships = ['subscription', 'profile'];

        return $this->userService->getPaginated(
            perPage: 50,
            filters: $filters,
            relationships: $relationships
        );
    }

    /**
     * Search users by multiple criteria
     */
    public function searchUsers($name, $department, $minAge)
    {
        $filters = [
            'name' => $name,
            'department_id' => $department,
            'age' => [
                'operator' => '>=',
                'value' => $minAge
            ]
        ];

        return $this->userService->index($filters, ['profile', 'department']);
    }
}

�🔁 Built-in CRUD Methods

The BaseCrudController provides:

  • index() – List records
  • getPaginated($perPage) - Paginate list of records
  • show($id) – Show single record
  • store(Request $request) – Create record
  • update(Request $request, $id) – Update record
  • destroy($id) – Delete record

All logic is handled inside CoreCrudService.

📄 Automatic Resource Handling

Single Item

return new UserResource($user);

Collection

return UserResource::collection($users);

Automatically handled by the base service.

No Resource

// No UserResource exists
return $user; // returns full user model data

If the corresponding Resource class does not exist, the base controller will return the raw model data instead of a resource.

📊 Example JSON Response

GET /users

{
  "data": [
    {
      "id": 1,
      "name": "John Doe"
    }
  ],
  "meta": {
    "current_page": 1,
    "per_page": 15
  }
}

🧠 Best Practices

✔ Keep business logic inside Model-specific services.
✔ Keep controllers thin.
✔ Extend CoreCrudService instead of modifying it.
✔ Use Resources for API formatting.
✔ Use filters and relationships to avoid N+1 query problems.

Example 1: Simple Business Logic with Filters

namespace App\Services;

use Rizkussef\LaravelCoreCrud\Services\CoreCrudService;

class UserService extends CoreCrudService
{
    /**
     * Activate user
     */
    public function activate($id)
    {
        $user = $this->model->findOrFail($id);
        $user->update(['active' => true]);
        return $this->applyResource($user);
    }

    /**
     * Get active users in a department
     */
    public function getActiveDepartmentUsers($departmentId, $perPage = 15)
    {
        $filters = [
            'active' => true,
            'department_id' => $departmentId
        ];
        
        $relationships = ['department', 'profile'];
        
        return $this->getPaginated($perPage, $filters, $relationships);
    }
}

Example 2: Complex Filtering with Date Range

namespace App\Services;

use Rizkussef\LaravelCoreCrud\Services\CoreCrudService;

class OrderService extends CoreCrudService
{
    /**
     * Get high-value orders in date range with customer details
     */
    public function getHighValueOrders($minAmount, $startDate, $endDate, $perPage = 20)
    {
        $filters = [
            'total_amount' => [
                'operator' => '>=',
                'value' => $minAmount
            ],
            'created_at' => [
                'operator' => 'between',
                'value' => [$startDate, $endDate]
            ],
            'status' => [
                'operator' => 'in',
                'value' => ['completed', 'shipped']
            ]
        ];

        $relationships = ['customer', 'items.product', 'payment'];

        return $this->getPaginated($perPage, $filters, $relationships);
    }

    /**
     * Search orders by customer name and status
     */
    public function searchOrders($customerName, $statuses)
    {
        $filters = [
            'customer_name' => [
                'operator' => 'like',
                'value' => $customerName
            ],
            'status' => [
                'operator' => 'in',
                'value' => $statuses
            ]
        ];

        return $this->index($filters, ['customer', 'items']);
    }
}

Example 3: Filtering with NULL Checks

namespace App\Services;

use Rizkussef\LaravelCoreCrud\Services\CoreCrudService;

class ArticleService extends CoreCrudService
{
    /**
     * Get published articles with authors and comments
     */
    public function getPublishedArticles($perPage = 15)
    {
        $filters = [
            'status' => 'published',
            'published_at' => [
                'operator' => '!null'  // IS NOT NULL
            ]
        ];

        $relationships = ['author', 'comments.author', 'tags'];

        return $this->getPaginated($perPage, $filters, $relationships);
    }

    /**
     * Get articles pending review (no reviewer assigned)
     */
    public function getPendingReview()
    {
        $filters = [
            'status' => 'draft',
            'reviewer_id' => [
                'operator' => 'null'  // IS NULL
            ]
        ];

        return $this->index($filters, ['author']);
    }
}

🔌 Dependency Injection

CoreCrudService is bound in the container via the Service Provider, so it can be injected anywhere.

🔧 Extending

You can extend:

  • BaseCrudController
  • CoreCrudService
  • Pagination configuration

And you can use:

  • API Response Trait
  • Filter Query Trait
  • Relationship Query Trait

🛣 Example Routes

Route::apiResource('users', UserController::class);

👨‍💻 Author & Support

Developed by Rizk Ussef

A fullstack developer passionate about creating clean, maintainable architecture patterns and reusable solutions for building scalable applications across frontend and backend ecosystems.

Get in Touch

🤝 Contributing

Contributions are welcome! If you find bugs or have feature suggestions, please open an issue or submit a pull request.

📄 License

MIT License - see LICENSE file for details.