In this series of articles, we will guide you through the process of building a Customer Relationship Management (CRM) system using Laravel 11 and a SQL database. Laravel is a powerful PHP framework that makes it easy to build robust web applications quickly. This CRM will manage customer information, product catalogs, orders, and activities.
Module 1: Installation and Setup
Step 1: Prerequisites
Before we start, ensure you have the following software installed on your machine:
- PHP: Version 8.1 or higher
- Composer: Dependency manager for PHP
- MySQL: Or any other SQL database
- Git: Version control system
- Node.js & npm: For handling JavaScript dependencies
- Laravel Installer: Optional, but recommended for ease of use
Step 2: Installing Laravel
Create a new Laravel project: If you have the Laravel installer:
laravel new crm-backend
If you don’t have the Laravel installer, use Composer:
composer create-project --prefer-dist laravel/laravel crm-backend
Navigate to the project directory:
cd crm-backend
Install JavaScript dependencies:
npm install
Create a .env
file: Copy the example environment configuration:
cp .env.example .env
Generate an application key:
php artisan key:generate
Step 3: Setting Up the Database
Configure your database: Open the
.env
file and set the database connection details:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=crm_backend
DB_USERNAME=root
DB_PASSWORD=
Create the database: Use your preferred method to create a new database named
crm_backend
.
Step 4: Setting Up Git and GitHub
Initialize Git:
git init
2. Create a .gitignore
file: Laravel already includes a .gitignore
file in the project. Ensure it includes vendor/
and .env
.
3. Push to GitHub:
- Create a new repository on GitHub.
- Link your local repository to GitHub
git remote add origin https://github.com/yourusername/crm-backend.git
git add .
git commit -m "Initial commit"
git push -u origin main
Step 5: Project Structure and Documentation
Here’s a proposed project structure:
crm-backend/
│
├── app/
│ ├── Console/
│ ├── Exceptions/
│ ├── Http/
│ │ ├── Controllers/
│ │ ├── Middleware/
│ │ └── Requests/
│ ├── Models/
│ ├── Policies/
│ └── Providers/
│
├── bootstrap/
├── config/
├── database/
│ ├── factories/
│ ├── migrations/
│ └── seeders/
│
├── public/
├── resources/
├── routes/
│ └── api.php
├── storage/
├── tests/
├── .env
├── .env.example
├── .gitignore
├── composer.json
├── package.json
├── webpack.mix.js
└── README.md
Step 6: Creating the App Schema/Diagram
To visualize the application, we’ll create an Entity-Relationship Diagram (ERD). The CRM system will have entities such as Customer, Product, Order, OrderDetail, Employee, and Activity.
Entities:
Customer:
id
(Primary Key)name
email
phone
address
created_at
updated_at
Product:
id
(Primary Key)name
description
price
category
brand
quantity_in_stock
created_at
updated_at
Order:
id
(Primary Key)customer_id
(Foreign Key)order_date
total_amount
status
payment_method
shipping_address
created_at
updated_at
OrderDetail:
id
(Primary Key)order_id
(Foreign Key)product_id
(Foreign Key)quantity
unit_price
subtotal
discount
created_at
updated_at
Employee:
id
(Primary Key)name
email
phone
position
department
hire_date
created_at
updated_at
Activity:
id
(Primary Key)employee_id
(Foreign Key)type
description
date
time
location
duration
created_at
updated_at
Step 7: Connecting to GitHub via Visual Studio Code
- Open your project in Visual Studio Code.
- Install GitHub extension (if not already installed).
- Clone the repository:
- Use the command palette (
Ctrl+Shift+P
orCmd+Shift+P
) and typeGit: Clone
. - Enter your repository URL.
- Use the command palette (
- Commit and push changes:
- Use the source control panel to commit and push changes directly from VS Code.
In this module, we set up the Laravel 11 project, configured the database, initialized Git and GitHub, and structured the project. We also created an ERD to visualize the application’s entities and relationships. In the next module, we will focus on designing our database schema and creating migrations. Stay tuned!
Module 2: Database Design and Migrations
In this module, we will design our database schema and create the necessary migrations for our CRM system using Laravel 11 and MySQL. Migrations are a type of version control for your database, allowing your team to define and share the application’s database schema definition.
Step 1: Designing the Database Schema
We have six main entities in our CRM system:
- Customer
- Product
- Order
- OrderDetail
- Employee
- Activity
Step 2: Creating Migrations
We’ll create migrations for each of these entities. Laravel’s Artisan command-line tool makes this process straightforward.
1. Customer Migration
First, create a migration for the customers
table.
php artisan make:migration create_customers_table
Then, define the schema in the migration file:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCustomersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('phone');
$table->text('address');
$table->timestamps(); // This adds 'created_at' and 'updated_at'
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('customers');
}
}
2. Product Migration
Create a migration for the products
table.
php artisan make:migration create_products_table
Define the schema:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateProductsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description');
$table->decimal('price', 8, 2);
$table->string('category');
$table->string('brand');
$table->integer('quantity_in_stock');
$table->timestamps(); // This adds 'created_at' and 'updated_at'
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('products');
}
}
3. Order Migration
Create a migration for the orders
table.
php artisan make:migration create_orders_table
Define the schema:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateOrdersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('orders', function (Blueprint $table) {
$table->id();
$table->foreignId('customer_id')->constrained()->onDelete('cascade');
$table->date('order_date');
$table->decimal('total_amount', 10, 2);
$table->string('status');
$table->string('payment_method');
$table->text('shipping_address');
$table->timestamps(); // This adds 'created_at' and 'updated_at'
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('orders');
}
}
4. OrderDetail Migration
Create a migration for the order_details
table.
php artisan make:migration create_order_details_table
Define the schema:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateOrderDetailsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('order_details', function (Blueprint $table) {
$table->id();
$table->foreignId('order_id')->constrained()->onDelete('cascade');
$table->foreignId('product_id')->constrained()->onDelete('cascade');
$table->integer('quantity');
$table->decimal('unit_price', 8, 2);
$table->decimal('subtotal', 10, 2);
$table->decimal('discount', 8, 2)->default(0);
$table->timestamps(); // This adds 'created_at' and 'updated_at'
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('order_details');
}
}
5. Employee Migration
Create a migration for the employees
table.
php artisan make:migration create_employees_table
Define the schema:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateEmployeesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('employees', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('phone');
$table->string('position');
$table->string('department');
$table->date('hire_date');
$table->timestamps(); // This adds 'created_at' and 'updated_at'
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('employees');
}
}
6. Activity Migration
Create a migration for the activities
table.
php artisan make:migration create_activities_table
Define the schema:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateActivitiesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('activities', function (Blueprint $table) {
$table->id();
$table->foreignId('employee_id')->constrained()->onDelete('cascade');
$table->string('type');
$table->text('description');
$table->date('date');
$table->time('time');
$table->string('location');
$table->integer('duration'); // Duration in minutes
$table->timestamps(); // This adds 'created_at' and 'updated_at'
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('activities');
}
}
Step 3: Running Migrations
After defining all the migrations, run the following command to create the tables in the database:
php artisan migrate
This command will execute all the migrations and create the tables according to the schema definitions provided.
In this module, we have designed the database schema for our CRM system and created migrations for each entity. The migrations define the structure of the tables and their relationships. Running the migrations sets up the database schema in MySQL. In the next module, we will focus on creating models and setting up relationships between them.
Module 3: User Authentication and Authorization
In this module, we will set up user authentication and authorization. We’ll ensure that customers cannot access other customers’ data, employees cannot access customers managed by other employees, and admins have full access to all data. Laravel provides built-in support for authentication, making it straightforward to implement these features.
Step 1: Setting Up Authentication
Laravel makes it easy to implement authentication through the laravel/ui
package.
1. Install Laravel UI Package
composer require laravel/ui
2. Generate Authentication Scaffolding
php artisan ui:auth
This command generates the necessary controllers, views, and routes for user authentication.
3. Migrate the Database
php artisan migrate
This command will create the necessary tables in the database, including the users
table.
Step 2: Customizing User Model
We need to customize the User model to include roles (admin, employee, customer).
1. Update User Model
Open the User.php
model located in app/Models
and add a role
field:
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password', 'role',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
}
2. Update User Migration
We need to add a role
column to the users
table. Open the xxxx_xx_xx_create_users_table.php
migration file and add the role
column:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->string('role')->default('customer'); // Default role is customer
$table->rememberToken();
$table->timestamps();
});
}
Run the migration to update the users
table:
php artisan migrate
Step 3: Middleware for Authorization
We need middleware to restrict access based on roles. Create middleware to check the user’s role.
1. Create Role Middleware
Generate middleware using Artisan:
php artisan make:middleware RoleMiddleware
Open the newly created RoleMiddleware.php
file located in app/Http/Middleware
and define the middleware:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RoleMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $role
* @return mixed
*/
public function handle($request, Closure $next, $role)
{
if (!Auth::check() || Auth::user()->role != $role) {
return redirect('/home')->with('error', 'You do not have access to this page.');
}
return $next($request);
}
}
2. Register Middleware
Register the middleware in app/Http/Kernel.php
:
protected $routeMiddleware = [
// ...
'role' => \App\Http\Middleware\RoleMiddleware::class,
];
Step 4: Protecting Routes
Use the middleware to protect routes based on roles.
1. Define Routes
Open routes/web.php
and define routes with role-based access control:
use App\Http\Controllers\HomeController;
use App\Http\Controllers\CustomerController;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\OrderController;
use App\Http\Controllers\EmployeeController;
use App\Http\Controllers\ActivityController;
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', [HomeController::class, 'index'])->name('home');
// Admin Routes
Route::middleware(['auth', 'role:admin'])->group(function () {
Route::resource('customers', CustomerController::class);
Route::resource('products', ProductController::class);
Route::resource('orders', OrderController::class);
Route::resource('employees', EmployeeController::class);
Route::resource('activities', ActivityController::class);
});
// Employee Routes
Route::middleware(['auth', 'role:employee'])->group(function () {
Route::get('/customers', [CustomerController::class, 'index'])->name('customers.index');
Route::get('/customers/{id}', [CustomerController::class, 'show'])->name('customers.show');
Route::post('/customers', [CustomerController::class, 'store'])->name('customers.store');
Route::put('/customers/{id}', [CustomerController::class, 'update'])->name('customers.update');
Route::delete('/customers/{id}', [CustomerController::class, 'destroy'])->name('customers.destroy');
});
// Customer Routes
Route::middleware(['auth', 'role:customer'])->group(function () {
Route::get('/my-orders', [OrderController::class, 'myOrders'])->name('orders.myOrders');
});
Step 5: Creating Controllers
Generate controllers for the main entities using Artisan:
php artisan make:controller CustomerController --resource
php artisan make:controller ProductController --resource
php artisan make:controller OrderController --resource
php artisan make:controller EmployeeController --resource
php artisan make:controller ActivityController --resource
Step 6: Implementing CRUD Operations
Implement CRUD operations in each controller. Here’s an example for CustomerController
.
1. CustomerController Example
Open CustomerController.php
and implement the CRUD operations:
namespace App\Http\Controllers;
use App\Models\Customer;
use Illuminate\Http\Request;
class CustomerController extends Controller
{
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$customers = Customer::all();
return view('customers.index', compact('customers'));
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
return view('customers.create');
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$request->validate([
'name' => 'required',
'email' => 'required|email|unique:customers',
'phone' => 'required',
'address' => 'required',
]);
Customer::create($request->all());
return redirect()->route('customers.index')
->with('success', 'Customer created successfully.');
}
/**
* Display the specified resource.
*
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\Response
*/
public function show(Customer $customer)
{
return view('customers.show', compact('customer'));
}
/**
* Show the form for editing the specified resource.
*
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\Response
*/
public function edit(Customer $customer)
{
return view('customers.edit', compact('customer'));
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Customer $customer)
{
$request->validate([
'name' => 'required',
'email' => 'required|email|unique:customers,email,' . $customer->id,
'phone' => 'required',
'address' => 'required',
]);
$customer->update($request->all());
return redirect()->route('customers.index')
->with('success', 'Customer updated successfully.');
}
/**
* Remove the specified resource from storage.
*
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\Response
*/
public function destroy(Customer $customer)
{
$customer->delete();
return redirect()->route('customers.index')
->with('success', 'Customer deleted successfully.');
}
}
Step 7: Creating Views
Create views for each CRUD operation. For example, create the following view files for customers:
resources/views/customers/index.blade.php
resources/views/customers/create.blade.php
resources/views/customers/edit.blade.php
resources/views/customers/show.blade.php
Example: index.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row">
<div class="col-lg-12 margin-tb">
<div class="pull-left">
<h2>Customers</h2>
</div>
<div class="pull-right">
<a class="btn btn-success" href="{{ route('customers.create') }}"> Create New Customer</a>
</div>
</div>
</div>
@if ($message = Session::get('success'))
<div class="alert alert-success">
<p>{{ $message }}</p>
</div>
@endif
<table class="table table-bordered">
<tr>
<th>No</th>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Address</th>
<th width="280px">Action</th>
</tr>
@foreach ($customers as $customer)
<tr>
<td>{{ ++$i }}</td>
<td>{{ $customer->name }}</td>
<td>{{ $customer->email }}</td>
<td>{{ $customer->phone }}</td>
<td>{{ $customer->address }}</td>
<td>
<form action="{{ route('customers.destroy',$customer->id) }}" method="POST">
<a class="btn btn-info" href="{{ route('customers.show',$customer->id) }}">Show</a>
<a class="btn btn-primary" href="{{ route('customers.edit',$customer->id) }}">Edit</a>
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</td>
</tr>
@endforeach
</table>
</div>
@endsection
In this module, we set up user authentication and authorization using Laravel’s built-in features. We customized the User model to include roles and created middleware to restrict access based on roles. We also created controllers and views to handle CRUD operations for customers. In the next module, we will create models and set up relationships between them.
Module 4: Creating Models and Setting Up Relationships
In this module, we will create the models for our CRM system and set up the relationships between them. Laravel’s Eloquent ORM makes it easy to work with database relationships.
Step 1: Creating Models
We will create models for the six main entities: Customer, Product, Order, OrderDetail, Employee, and Activity. Each model will define the relationships with other models.
1. Customer Model
Create the Customer model:
php artisan make:model Customer
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
use HasFactory;
protected $fillable = [
'name', 'email', 'phone', 'address',
];
public function orders()
{
return $this->hasMany(Order::class);
}
}
2. Product Model
Create the Product model:
php artisan make:model Product
Define the relationships in the Product.php
model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
protected $fillable = [
'name', 'description', 'price', 'category', 'brand', 'quantity_in_stock',
];
public function orderDetails()
{
return $this->hasMany(OrderDetail::class);
}
}
3. Order Model
Create the Order model:
php artisan make:model Order
Define the relationships in the Order.php
model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Order extends Model
{
use HasFactory;
protected $fillable = [
'customer_id', 'order_date', 'total_amount', 'status', 'payment_method', 'shipping_address',
];
public function customer()
{
return $this->belongsTo(Customer::class);
}
public function orderDetails()
{
return $this->hasMany(OrderDetail::class);
}
}
4. OrderDetail Model
Create the OrderDetail model:
php artisan make:model OrderDetail
Define the relationships in the OrderDetail.php
model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class OrderDetail extends Model
{
use HasFactory;
protected $fillable = [
'order_id', 'product_id', 'quantity', 'unit_price', 'subtotal', 'discount',
];
public function order()
{
return $this->belongsTo(Order::class);
}
public function product()
{
return $this->belongsTo(Product::class);
}
}
5. Employee Model
Create the Employee model:
php artisan make:model Employee
Define the relationships in the Employee.php
model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Employee extends Model
{
use HasFactory;
protected $fillable = [
'name', 'email', 'phone', 'position', 'department', 'hire_date',
];
public function activities()
{
return $this->hasMany(Activity::class);
}
}
6. Activity Model
Create the Activity model:
php artisan make:model Activity
Define the relationships in the Activity.php
model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Activity extends Model
{
use HasFactory;
protected $fillable = [
'employee_id', 'type', 'description', 'date', 'time', 'location', 'duration',
];
public function employee()
{
return $this->belongsTo(Employee::class);
}
}
Step 2: Setting Up Relationships
The relationships are defined using Eloquent’s relationship methods. Here’s a quick recap of the relationships:
- Customer has many Orders.
- Order belongs to a Customer.
- Order has many OrderDetails.
- OrderDetail belongs to an Order.
- OrderDetail belongs to a Product.
- Product has many OrderDetails.
- Employee has many Activities.
- Activity belongs to an Employee.
Step 3: Seeding the Database
To test our relationships and data flow, we will create some seed data.
1. Create Seeders
Generate seeders for each model:
php artisan make:seeder CustomerSeeder
php artisan make:seeder ProductSeeder
php artisan make:seeder OrderSeeder
php artisan make:seeder OrderDetailSeeder
php artisan make:seeder EmployeeSeeder
php artisan make:seeder ActivitySeeder
2. Define Seeder Data
Here’s an example of how to define data in a seeder. We will do this for the CustomerSeeder
:
database/seeders/CustomerSeeder.php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\Models\Customer;
class CustomerSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
Customer::factory()->count(10)->create();
}
}
3. Run Seeders
Add the seeders to DatabaseSeeder.php
:
database/seeders/DatabaseSeeder.php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call([
CustomerSeeder::class,
ProductSeeder::class,
OrderSeeder::class,
OrderDetailSeeder::class,
EmployeeSeeder::class,
ActivitySeeder::class,
]);
}
}
Run the seeders:
php artisan db:seed
In this module, we created the models for our CRM system and set up relationships between them. We also created seeders to populate the database with test data. In the next module, we will focus on implementing controllers and routes to handle CRUD operations and business logic.
Module 5: Implementing Controllers and Routes
In this module, we will implement the controllers and routes for our CRM system. The controllers will handle CRUD operations and business logic, while the routes will define the API endpoints.
Step 1: Creating Controllers
We have already generated controllers for our main entities in Module 3. Now, we will implement the methods for these controllers.
1. CustomerController
Open CustomerController.php
and implement the CRUD operations:
app/Http/Controllers/CustomerController.php
namespace App\Http\Controllers;
use App\Models\Customer;
use Illuminate\Http\Request;
class CustomerController extends Controller
{
/**
* Display a listing of the customers.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$customers = Customer::all();
return response()->json($customers);
}
/**
* Store a newly created customer in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'name' => 'required',
'email' => 'required|email|unique:customers',
'phone' => 'required',
'address' => 'required',
]);
$customer = Customer::create($validatedData);
return response()->json($customer, 201);
}
/**
* Display the specified customer.
*
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\Response
*/
public function show(Customer $customer)
{
return response()->json($customer);
}
/**
* Update the specified customer in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Customer $customer)
{
$validatedData = $request->validate([
'name' => 'required',
'email' => 'required|email|unique:customers,email,' . $customer->id,
'phone' => 'required',
'address' => 'required',
]);
$customer->update($validatedData);
return response()->json($customer);
}
/**
* Remove the specified customer from storage.
*
* @param \App\Models\Customer $customer
* @return \Illuminate\Http\Response
*/
public function destroy(Customer $customer)
{
$customer->delete();
return response()->json(null, 204);
}
}
2. ProductController
Open ProductController.php
and implement the CRUD operations:
app/Http/Controllers/ProductController.php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
/**
* Display a listing of the products.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$products = Product::all();
return response()->json($products);
}
/**
* Store a newly created product in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'name' => 'required',
'description' => 'required',
'price' => 'required|numeric',
'category' => 'required',
'brand' => 'required',
'quantity_in_stock' => 'required|integer',
]);
$product = Product::create($validatedData);
return response()->json($product, 201);
}
/**
* Display the specified product.
*
* @param \App\Models\Product $product
* @return \Illuminate\Http\Response
*/
public function show(Product $product)
{
return response()->json($product);
}
/**
* Update the specified product in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Product $product
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Product $product)
{
$validatedData = $request->validate([
'name' => 'required',
'description' => 'required',
'price' => 'required|numeric',
'category' => 'required',
'brand' => 'required',
'quantity_in_stock' => 'required|integer',
]);
$product->update($validatedData);
return response()->json($product);
}
/**
* Remove the specified product from storage.
*
* @param \App\Models\Product $product
* @return \Illuminate\Http\Response
*/
public function destroy(Product $product)
{
$product->delete();
return response()->json(null, 204);
}
}
3. OrderController
Open OrderController.php
and implement the CRUD operations:
app/Http/Controllers/OrderController.php
namespace App\Http\Controllers;
use App\Models\Order;
use Illuminate\Http\Request;
class OrderController extends Controller
{
/**
* Display a listing of the orders.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$orders = Order::with('customer', 'orderDetails.product')->get();
return response()->json($orders);
}
/**
* Store a newly created order in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'customer_id' => 'required|exists:customers,id',
'order_date' => 'required|date',
'total_amount' => 'required|numeric',
'status' => 'required',
'payment_method' => 'required',
'shipping_address' => 'required',
'order_details' => 'required|array',
'order_details.*.product_id' => 'required|exists:products,id',
'order_details.*.quantity' => 'required|integer',
'order_details.*.unit_price' => 'required|numeric',
'order_details.*.subtotal' => 'required|numeric',
'order_details.*.discount' => 'required|numeric',
]);
$order = Order::create($validatedData);
foreach ($validatedData['order_details'] as $detail) {
$order->orderDetails()->create($detail);
}
return response()->json($order->load('customer', 'orderDetails.product'), 201);
}
/**
* Display the specified order.
*
* @param \App\Models\Order $order
* @return \Illuminate\Http\Response
*/
public function show(Order $order)
{
return response()->json($order->load('customer', 'orderDetails.product'));
}
/**
* Update the specified order in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Order $order
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Order $order)
{
$validatedData = $request->validate([
'customer_id' => 'required|exists:customers,id',
'order_date' => 'required|date',
'total_amount' => 'required|numeric',
'status' => 'required',
'payment_method' => 'required',
'shipping_address' => 'required',
'order_details' => 'sometimes|array',
'order_details.*.product_id' => 'required|exists:products,id',
'order_details.*.quantity' => 'required|integer',
'order_details.*.unit_price' => 'required|numeric',
'order_details.*.subtotal' => 'required|numeric',
'order_details.*.discount' => 'required|numeric',
]);
$order->update($validatedData);
if (isset($validatedData['order_details'])) {
$order->orderDetails()->delete();
foreach ($validatedData['order_details'] as $detail) {
$order->orderDetails()->create($detail);
}
}
return response()->json($order->load('customer', 'orderDetails.product'));
}
/**
* Remove the specified order from storage.
*
* @param \App\Models\Order $order
* @return \Illuminate\Http\Response
*/
public function destroy(Order $order)
{
$order->delete();
return response()->json(null, 204);
}
}
4. EmployeeController
Open EmployeeController.php
and implement the CRUD operations:
app/Http/Controllers/EmployeeController.php
namespace App\Http\Controllers;
use App\Models\Employee;
use Illuminate\Http\Request;
class EmployeeController extends Controller
{
/**
* Display a listing of the employees.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$employees = Employee::all();
return response()->json($employees);
}
/**
* Store a newly created employee in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'name' => 'required',
'email' => 'required|email|unique:employees',
'phone' => 'required',
'position' => 'required',
'department' => 'required',
'hire_date' => 'required|date',
]);
$employee = Employee::create($validatedData);
return response()->json($employee, 201);
}
/**
* Display the specified employee.
*
* @param \App\Models\Employee $employee
* @return \Illuminate\Http\Response
*/
public function show(Employee $employee)
{
return response()->json($employee);
}
/**
* Update the specified employee in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Employee $employee
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Employee $employee)
{
$validatedData = $request->validate([
'name' => 'required',
'email' => 'required|email|unique:employees,email,' . $employee->id,
'phone' => 'required',
'position' => 'required',
'department' => 'required',
'hire_date' => 'required|date',
]);
$employee->update($validatedData);
return response()->json($employee);
}
/**
* Remove the specified employee from storage.
*
* @param \App\Models\Employee $employee
* @return \Illuminate\Http\Response
*/
public function destroy(Employee $employee)
{
$employee->delete();
return response()->json(null, 204);
}
}
5. ActivityController
Open ActivityController.php
and implement the CRUD operations:
app/Http/Controllers/ActivityController.php
namespace App\Http\Controllers;
use App\Models\Activity;
use Illuminate\Http\Request;
class ActivityController extends Controller
{
/**
* Display a listing of the activities.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$activities = Activity::with('employee')->get();
return response()->json($activities);
}
/**
* Store a newly created activity in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$validatedData = $request->validate([
'employee_id' => 'required|exists:employees,id',
'type' => 'required',
'description' => 'required',
'date' => 'required|date',
'time' => 'required|date_format:H:i',
'location' => 'required',
'duration' => 'required|integer',
]);
$activity = Activity::create($validatedData);
return response()->json($activity->load('employee'), 201);
}
/**
* Display the specified activity.
*
* @param \App\Models\Activity $activity
* @return \Illuminate\Http\Response
*/
public function show(Activity $activity)
{
return response()->json($activity->load('employee'));
}
/**
* Update the specified activity in storage.
*
* @param \Illuminate\Http\Request $request
* @param \App\Models\Activity $activity
* @return \Illuminate\Http\Response
*/
public function update(Request $request, Activity $activity)
{
$validatedData = $request->validate([
'employee_id' => 'required|exists:employees,id',
'type' => 'required',
'description' => 'required',
'date' => 'required|date',
'time' => 'required|date_format:H:i',
'location' => 'required',
'duration' => 'required|integer',
]);
$activity->update($validatedData);
return response()->json($activity->load('employee'));
}
/**
* Remove the specified activity from storage.
*
* @param \App\Models\Activity $activity
* @return \Illuminate\Http\Response
*/
public function destroy(Activity $activity)
{
$activity->delete();
return response()->json(null, 204);
}
}
Step 2: Defining Routes
Define the API routes for the controllers in routes/api.php
:
routes/api.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\CustomerController;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\OrderController;
use App\Http\Controllers\EmployeeController;
use App\Http\Controllers\ActivityController;
Route::middleware('auth:sanctum')->group(function () {
// Customer Routes
Route::apiResource('customers', CustomerController::class);
// Product Routes
Route::apiResource('products', ProductController::class);
// Order Routes
Route::apiResource('orders', OrderController::class);
// Employee Routes
Route::apiResource('employees', EmployeeController::class);
// Activity Routes
Route::apiResource('activities', ActivityController::class);
});
Step 3: Authentication Using Sanctum
To handle API authentication, we’ll use Laravel Sanctum.
1. Install Laravel Sanctum
composer require laravel/sanctum
2. Publish Sanctum Configuration
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
3. Run Sanctum Migrations
php artisan migrate
4. Configure Sanctum
Add Sanctum’s middleware to api
middleware group within your app/Http/Kernel.php
file:
app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
// ...
],
'api' => [
// ...
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
5. Protecting Routes with Sanctum
Update your routes/api.php
to use Sanctum’s authentication:
routes/api.php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\CustomerController;
use App\Http\Controllers\ProductController;
use App\Http\Controllers\OrderController;
use App\Http\Controllers\EmployeeController;
use App\Http\Controllers\ActivityController;
Route::middleware('auth:sanctum')->group(function () {
// Customer Routes
Route::apiResource('customers', CustomerController::class);
// Product Routes
Route::apiResource('products', ProductController::class);
// Order Routes
Route::apiResource('orders', OrderController::class);
// Employee Routes
Route::apiResource('employees', EmployeeController::class);
// Activity Routes
Route::apiResource('activities', ActivityController::class);
});
6. Creating Login and Register Routes
Add routes for user registration and login in routes/api.php
:
use App\Http\Controllers\AuthController;
Route::post('register', [AuthController::class, 'register']);
Route::post('login', [AuthController::class, 'login']);
7. AuthController
Create an AuthController
to handle user registration and login:
php artisan make:controller AuthController
Implement the methods in AuthController.php
:
app/Http/Controllers/AuthController.php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
/**
* Register a new user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$validatedData = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:8|confirmed',
'role' => 'required|string|in:admin,employee,customer',
]);
$user = User::create([
'name' => $validatedData['name'],
'email' => $validatedData['email'],
'password' => Hash::make($validatedData['password']),
'role' => $validatedData['role'],
]);
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer',
]);
}
/**
* Login a user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function login(Request $request)
{
$validatedData = $request->validate([
'email' => 'required|string|email',
'password' => 'required|string',
]);
$user = User::where('email', $validatedData['email'])->first();
if (!$user || !Hash::check($validatedData['password'], $user->password)) {
return response()->json(['message' => 'Invalid credentials'], 401);
}
$token = $user->createToken('auth_token')->plainTextToken;
return response()->json([
'access_token' => $token,
'token_type' => 'Bearer',
]);
}
}
In this module, we implemented controllers and routes to handle CRUD operations and business logic for our CRM system. We used Laravel Sanctum for API authentication, ensuring secure access to our endpoints. In the next module, we will implement advanced features such as pagination, filtering, and search functionalitie
Module 6: Advanced Pagination, Filtering, and Search
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.
In this module, we will implement advanced features such as pagination, filtering, and search functionalities. These features will allow users to retrieve data more efficiently and perform specific queries on the data.
Step 1: Pagination
Pagination helps in managing large sets of data by breaking them into smaller chunks. Laravel provides a convenient way to handle pagination using the paginate
method.
1. Implementing Pagination in Controllers
We will update our controllers to use pagination. Let’s start with the CustomerController
.
app/Http/Controllers/CustomerController.php
namespace App\Http\Controllers;
use App\Models\Customer;
use Illuminate\Http\Request;
class CustomerController extends Controller
{
/**
* Display a listing of the customers.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$customers = Customer::paginate($perPage);
return response()->json($customers);
}
// Other methods...
}
Similarly, update the other controllers:
app/Http/Controllers/ProductController.php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
/**
* Display a listing of the products.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$products = Product::paginate($perPage);
return response()->json($products);
}
// Other methods...
}
app/Http/Controllers/OrderController.php
namespace App\Http\Controllers;
use App\Models\Order;
use Illuminate\Http\Request;
class OrderController extends Controller
{
/**
* Display a listing of the orders.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$orders = Order::with('customer', 'orderDetails.product')->paginate($perPage);
return response()->json($orders);
}
// Other methods...
}
app/Http/Controllers/EmployeeController.php
namespace App\Http\Controllers;
use App\Models\Employee;
use Illuminate\Http\Request;
class EmployeeController extends Controller
{
/**
* Display a listing of the employees.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$employees = Employee::paginate($perPage);
return response()->json($employees);
}
// Other methods...
}
app/Http/Controllers/ActivityController.php
namespace App\Http\Controllers;
use App\Models\Activity;
use Illuminate\Http\Request;
class ActivityController extends Controller
{
/**
* Display a listing of the activities.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$activities = Activity::with('employee')->paginate($perPage);
return response()->json($activities);
}
// Other methods...
}
Step 2: Filtering and Search
Filtering and search allow users to retrieve specific subsets of data based on certain criteria.
1. Implementing Filtering and Search in Controllers
We will update our controllers to handle filtering and search. Let’s start with the CustomerController
.
app/Http/Controllers/CustomerController.php
namespace App\Http\Controllers;
use App\Models\Customer;
use Illuminate\Http\Request;
class CustomerController extends Controller
{
/**
* Display a listing of the customers.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$query = Customer::query();
if ($request->has('search')) {
$search = $request->get('search');
$query->where('name', 'LIKE', "%{$search}%")
->orWhere('email', 'LIKE', "%{$search}%")
->orWhere('phone', 'LIKE', "%{$search}%");
}
if ($request->has('address')) {
$address = $request->get('address');
$query->where('address', 'LIKE', "%{$address}%");
}
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$customers = $query->paginate($perPage);
return response()->json($customers);
}
// Other methods...
}
Similarly, update the other controllers:
app/Http/Controllers/ProductController.php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
/**
* Display a listing of the products.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$query = Product::query();
if ($request->has('search')) {
$search = $request->get('search');
$query->where('name', 'LIKE', "%{$search}%")
->orWhere('description', 'LIKE', "%{$search}%")
->orWhere('category', 'LIKE', "%{$search}%")
->orWhere('brand', 'LIKE', "%{$search}%");
}
if ($request->has('price_min')) {
$priceMin = $request->get('price_min');
$query->where('price', '>=', $priceMin);
}
if ($request->has('price_max')) {
$priceMax = $request->get('price_max');
$query->where('price', '<=', $priceMax);
}
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$products = $query->paginate($perPage);
return response()->json($products);
}
// Other methods...
}
app/Http/Controllers/OrderController.php
namespace App\Http\Controllers;
use App\Models\Order;
use Illuminate\Http\Request;
class OrderController extends Controller
{
/**
* Display a listing of the orders.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$query = Order::with('customer', 'orderDetails.product');
if ($request->has('search')) {
$search = $request->get('search');
$query->where('status', 'LIKE', "%{$search}%")
->orWhere('payment_method', 'LIKE', "%{$search}%");
}
if ($request->has('order_date')) {
$orderDate = $request->get('order_date');
$query->whereDate('order_date', $orderDate);
}
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$orders = $query->paginate($perPage);
return response()->json($orders);
}
// Other methods...
}
app/Http/Controllers/EmployeeController.php
namespace App\Http\Controllers;
use App\Models\Employee;
use Illuminate\Http\Request;
class EmployeeController extends Controller
{
/**
* Display a listing of the employees.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$query = Employee::query();
if ($request->has('search')) {
$search = $request->get('search');
$query->where('name', 'LIKE', "%{$search}%")
->orWhere('email', 'LIKE', "%{$search}%")
->orWhere('phone', 'LIKE', "%{$search}%")
->orWhere('position', 'LIKE', "%{$search}%")
->orWhere('department', 'LIKE', "%{$search}%");
}
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$employees = $query->paginate($perPage);
return response()->json($employees);
}
// Other methods...
}
app/Http/Controllers/ActivityController.php
namespace App\Http\Controllers;
use App\Models\Activity;
use Illuminate\Http\Request;
class ActivityController extends Controller
{
/**
* Display a listing of the activities.
*
* @return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$query = Activity::with('employee');
if ($request->has('search')) {
$search = $request->get('search');
$query->where('type', 'LIKE', "%{$search}%")
->orWhere('description', 'LIKE', "%{$search}%")
->orWhere('location', 'LIKE', "%{$search}%");
}
if ($request->has('date')) {
$date = $request->get('date');
$query->whereDate('date', $date);
}
$perPage = $request->get('per_page', 10); // Default is 10 items per page
$activities = $query->paginate($perPage);
return response()->json($activities);
}
// Other methods...
}
Step 3: Testing the Endpoints
To ensure our implementation works correctly, we will test the endpoints using Postman or any other API testing tool.
- Pagination: Test by passing the
per_page
parameter in the request URL, e.g.,GET /api/customers?per_page=5
. - Filtering: Test by passing the filtering parameters, e.g.,
GET /api/products?price_min=50&price_max=200
. - Search: Test by passing the search parameter, e.g.,
GET /api/customers?search=John
.
In this module, we implemented advanced features such as pagination, filtering, and search functionalities in our CRM system. These enhancements allow users to retrieve data more efficiently and perform specific queries. In the next module, we will focus on testing and deploying the application.
Module 7: Testing and Deployment
In this final module, we will cover how to test and deploy our CRM backend application. Testing ensures the reliability and correctness of our application, while deployment allows us to make our application accessible to users.
Step 1: Testing
We’ll use PHPUnit for testing our application. PHPUnit is a testing framework for PHP that allows us to write unit and feature tests.
1. Setting Up PHPUnit
Laravel comes with PHPUnit pre-configured. To get started, ensure you have the testing environment configured in your .env
file.
.env.testing
APP_ENV=testing
APP_DEBUG=true
DB_CONNECTION=sqlite
DB_DATABASE=:memory:
This configuration uses an in-memory SQLite database for testing purposes.
2. Writing Tests
We will write tests for our controllers to ensure that the CRUD operations and other functionalities work correctly.
Example: Testing Customer Controller
tests/Feature/CustomerTest.php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use App\Models\User;
use App\Models\Customer;
class CustomerTest extends TestCase
{
use RefreshDatabase;
/**
* Test retrieving a list of customers.
*
* @return void
*/
public function testCanRetrieveCustomers()
{
$user = User::factory()->create(['role' => 'admin']);
Customer::factory()->count(5)->create();
$response = $this->actingAs($user, 'sanctum')
->getJson('/api/customers');
$response->assertStatus(200)
->assertJsonCount(5, 'data');
}
/**
* Test creating a new customer.
*
* @return void
*/
public function testCanCreateCustomer()
{
$user = User::factory()->create(['role' => 'admin']);
$customerData = [
'name' => 'Test Customer',
'email' => 'testcustomer@example.com',
'phone' => '1234567890',
'address' => '123 Test Street',
];
$response = $this->actingAs($user, 'sanctum')
->postJson('/api/customers', $customerData);
$response->assertStatus(201)
->assertJsonFragment($customerData);
}
/**
* Test updating an existing customer.
*
* @return void
*/
public function testCanUpdateCustomer()
{
$user = User::factory()->create(['role' => 'admin']);
$customer = Customer::factory()->create();
$updatedData = [
'name' => 'Updated Name',
'email' => 'updatedemail@example.com',
'phone' => '0987654321',
'address' => '456 Updated Street',
];
$response = $this->actingAs($user, 'sanctum')
->putJson("/api/customers/{$customer->id}", $updatedData);
$response->assertStatus(200)
->assertJsonFragment($updatedData);
}
/**
* Test deleting a customer.
*
* @return void
*/
public function testCanDeleteCustomer()
{
$user = User::factory()->create(['role' => 'admin']);
$customer = Customer::factory()->create();
$response = $this->actingAs($user, 'sanctum')
->deleteJson("/api/customers/{$customer->id}");
$response->assertStatus(204);
$this->assertDatabaseMissing('customers', ['id' => $customer->id]);
}
}
3. Running Tests
Run your tests using the following command:
php artisan test
This command will execute all your tests and show the results in the console.
Step 2: Deployment
We will deploy our application to Heroku, a cloud platform that supports PHP applications.
1. Setting Up Heroku
Install Heroku CLI: Follow the instructions to install the Heroku CLI from the Heroku Dev Center.
Log in to Heroku:
heroku login
Create a Heroku Application:
heroku create my-crm-backend
Add a Database Add-on: Add ClearDB MySQL add-on to your Heroku application (replace my-crm-backend
with your app name):
heroku addons:create cleardb:ignite --app my-crm-backend
2. Configuring the Database
Retrieve the database URL provided by ClearDB:
heroku config:get CLEARDB_DATABASE_URL --app my-crm-backend
Update your .env
file with the following settings:
.env
DB_CONNECTION=mysql
DB_HOST=your-database-host
DB_PORT=3306
DB_DATABASE=your-database-name
DB_USERNAME=your-database-username
DB_PASSWORD=your-database-password
3. Preparing the Application for Deployment
Create a Procfile
in the root directory of your project to tell Heroku how to run your application:
Procfile
web: vendor/bin/heroku-php-apache2 public/
4. Deploying to Heroku
Initialize a Git repository (if not already done) and push your code to Heroku
git init
heroku git:remote -a my-crm-backend
git add .
git commit -m "Initial commit"
git push heroku master
5. Running Migrations on Heroku
Run the migrations on your Heroku app to set up the database schema:
heroku run php artisan migrate --app my-crm-backend
Step 3: Verifying the Deployment
Open your application:
heroku open
Verify the application:
- Test the endpoints using Postman or any other API testing tool.
- Ensure that the authentication, CRUD operations, pagination, filtering, and search functionalities work as expected.

Welcome to DevTechTutor.com, your ultimate resource for mastering web development and technology! Whether you're a beginner eager to dive into coding or an experienced developer looking to sharpen your skills, DevTechTutor.com is here to guide you every step of the way. Our mission is to make learning web development accessible, engaging, and effective.