Creating a wallet system in Laravel can be a fantastic way to manage user balances, handle transactions, and build a robust financial feature into your application. Whether you're building an e-commerce platform, a gaming app, or a fintech solution, a well-implemented wallet system is crucial. In this step-by-step guide, we'll walk you through the process of creating a basic wallet system in Laravel, covering everything from setting up your database to implementing the core functionalities. So, let's dive in and get those wallets rolling!
Setting Up Your Laravel Project
First things first, you need to have a Laravel project up and running. If you don't already have one, creating a new Laravel project is super easy. Open your terminal and run the following command:
composer create-project --prefer-dist laravel/laravel walletapp
cd walletapp
This command creates a new Laravel project named walletapp. Feel free to change the name to whatever suits your needs. Once the project is created, navigate into the project directory using the cd walletapp command. Next, you'll want to set up your database. Open your .env file and configure your database connection details. You'll need to provide the database name, username, and password. Here’s an example:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=walletapp
DB_USERNAME=your_username
DB_PASSWORD=your_password
Make sure to replace your_username and your_password with your actual database credentials. Once your database is configured, run the migrations to set up the initial database schema. Run the following command in your terminal:
php artisan migrate
This will create the default tables needed for your Laravel application. With your project and database set up, you're ready to start building the wallet system.
Creating the Wallet Model and Migration
Now, let's create the Wallet model and migration. Models in Laravel represent your database tables, and migrations are used to create and modify those tables. Run the following command to create both the model and the migration:
php artisan make:model Wallet -m
This command generates two files: app/Models/Wallet.php and database/migrations/xxxx_xx_xx_create_wallets_table.php (where xxxx_xx_xx is the timestamp). Open the migration file and add the necessary columns for your wallets table. You'll need columns for the user ID, balance, and any other relevant information. Here’s an example migration:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateWalletsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('wallets', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->decimal('balance', 15, 2)->default(0.00);
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('wallets');
}
}
In this migration, we're creating a wallets table with an id, user_id, and balance column. The user_id column is a foreign key that references the users table, ensuring that each wallet is associated with a user. The balance column is a decimal with a precision of 15 and 2 decimal places, which is suitable for storing monetary values. After modifying the migration file, run the migrations again to create the wallets table in your database:
php artisan migrate
Next, open the app/Models/Wallet.php file and define the model. You’ll want to specify which attributes are fillable to allow mass assignment. Here’s an example:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Wallet extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'balance',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
In this model, we're specifying that the user_id and balance attributes can be mass assigned. We're also defining a user relationship, indicating that each wallet belongs to a user.
Implementing Wallet Functionality
With the model and migration in place, it's time to implement the core wallet functionalities. This includes creating wallets, depositing funds, withdrawing funds, and checking balances. Let's start by creating a service class to handle these operations.
Create a new directory app/Services if it doesn't already exist, and then create a new file app/Services/WalletService.php. Here’s an example of what the service class might look like:
namespace App\Services;
use App\Models\Wallet;
use Illuminate\Support\Facades\DB;
use Exception;
class WalletService
{
/**
* Create a new wallet for a user.
*
* @param int $userId
* @return Wallet
*/
public function createWallet(int $userId): Wallet
{
return Wallet::create(['user_id' => $userId]);
}
/**
* Deposit funds into a wallet.
*
* @param Wallet $wallet
* @param float $amount
* @return Wallet
* @throws Exception
*/
public function deposit(Wallet $wallet, float $amount): Wallet
{
if ($amount <= 0) {
throw new Exception('Amount must be positive.');
}
$wallet->balance += $amount;
$wallet->save();
return $wallet;
}
/**
* Withdraw funds from a wallet.
*
* @param Wallet $wallet
* @param float $amount
* @return Wallet
* @throws Exception
*/
public function withdraw(Wallet $wallet, float $amount): Wallet
{
if ($amount <= 0) {
throw new Exception('Amount must be positive.');
}
if ($wallet->balance < $amount) {
throw new Exception('Insufficient balance.');
}
$wallet->balance -= $amount;
$wallet->save();
return $wallet;
}
/**
* Get the balance of a wallet.
*
* @param Wallet $wallet
* @return float
*/
public function getBalance(Wallet $wallet): float
{
return $wallet->balance;
}
}
In this service class, we have methods for creating a wallet, depositing funds, withdrawing funds, and checking the balance. Each method performs necessary validations and updates the wallet balance accordingly. The deposit and withdraw methods throw exceptions if the amount is invalid or if there are insufficient funds. These exceptions can be caught and handled in your controllers or other parts of your application.
Implementing Controllers and Routes
Next, you'll need to create controllers and routes to expose the wallet functionality to your application. Let's create a WalletController to handle wallet-related requests.
Run the following command to create a new controller:
php artisan make:controller WalletController
Open the app/Http/Controllers/WalletController.php file and add the necessary methods. Here’s an example:
namespace App\Http\Controllers;
use App\Models\User;
use App\Models\Wallet;
use App\Services\WalletService;
use Illuminate\Http\Request;
use Exception;
class WalletController extends Controller
{
protected $walletService;
public function __construct(WalletService $walletService)
{
$this->walletService = $walletService;
}
/**
* Create a new wallet for a user.
*
* @param Request $request
* @param int $userId
* @return \Illuminate\Http\JsonResponse
*/
public function createWallet(Request $request, int $userId)
{
try {
$wallet = $this->walletService->createWallet($userId);
return response()->json(['message' => 'Wallet created successfully', 'wallet' => $wallet], 201);
} catch (Exception $e) {
return response()->json(['message' => 'Failed to create wallet', 'error' => $e->getMessage()], 500);
}
}
/**
* Deposit funds into a wallet.
*
* @param Request $request
* @param int $walletId
* @return \Illuminate\Http\JsonResponse
*/
public function deposit(Request $request, int $walletId)
{
$request->validate(['amount' => 'required|numeric|min:0.01']);
try {
$wallet = Wallet::findOrFail($walletId);
$amount = $request->input('amount');
$wallet = $this->walletService->deposit($wallet, $amount);
return response()->json(['message' => 'Funds deposited successfully', 'wallet' => $wallet], 200);
} catch (Exception $e) {
return response()->json(['message' => 'Failed to deposit funds', 'error' => $e->getMessage()], 500);
}
}
/**
* Withdraw funds from a wallet.
*
* @param Request $request
* @param int $walletId
* @return \Illuminate\Http\JsonResponse
*/
public function withdraw(Request $request, int $walletId)
{
$request->validate(['amount' => 'required|numeric|min:0.01']);
try {
$wallet = Wallet::findOrFail($walletId);
$amount = $request->input('amount');
$wallet = $this->walletService->withdraw($wallet, $amount);
return response()->json(['message' => 'Funds withdrawn successfully', 'wallet' => $wallet], 200);
} catch (Exception $e) {
return response()->json(['message' => 'Failed to withdraw funds', 'error' => $e->getMessage()], 500);
}
}
/**
* Get the balance of a wallet.
*
* @param int $walletId
* @return \Illuminate\Http\JsonResponse
*/
public function getBalance(int $walletId)
{
try {
$wallet = Wallet::findOrFail($walletId);
$balance = $this->walletService->getBalance($wallet);
return response()->json(['balance' => $balance], 200);
} catch (Exception $e) {
return response()->json(['message' => 'Failed to get balance', 'error' => $e->getMessage()], 500);
}
}
}
In this controller, we're injecting the WalletService to handle the wallet logic. We have methods for creating a wallet, depositing funds, withdrawing funds, and getting the balance. Each method validates the input, calls the corresponding service method, and returns a JSON response. Now, let's define the routes for these controller methods. Open the routes/api.php file and add the following routes:
use App\Http\Controllers\WalletController;
use Illuminate\Support\Facades\Route;
Route::post('/users/{userId}/wallets', [WalletController::class, 'createWallet']);
Route::post('/wallets/{walletId}/deposit', [WalletController::class, 'deposit']);
Route::post('/wallets/{walletId}/withdraw', [WalletController::class, 'withdraw']);
Route::get('/wallets/{walletId}/balance', [WalletController::class, 'getBalance']);
These routes define the API endpoints for creating wallets, depositing funds, withdrawing funds, and getting the balance. You can access these endpoints using HTTP requests, such as POST and GET. You can test this functionality using tools like Postman or Insomnia.
Testing Your Wallet System
Testing is a crucial part of building any application. Let's write some tests to ensure that our wallet system is working correctly. Create a new test file tests/Feature/WalletTest.php and add the following tests:
namespace Tests\Feature;
use App\Models\User;
use App\Models\Wallet;
use App\Services\WalletService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class WalletTest extends TestCase
{
use RefreshDatabase;
/**
* Test creating a wallet for a user.
*
* @return void
*/
public function testCreateWallet()
{
$user = User::factory()->create();
$walletService = new WalletService();
$wallet = $walletService->createWallet($user->id);
$this->assertInstanceOf(Wallet::class, $wallet);
$this->assertEquals($user->id, $wallet->user_id);
$this->assertEquals(0, $wallet->balance);
}
/**
* Test depositing funds into a wallet.
*
* @return void
*/
public function testDeposit()
{
$user = User::factory()->create();
$wallet = Wallet::factory()->create(['user_id' => $user->id, 'balance' => 100]);
$walletService = new WalletService();
$wallet = $walletService->deposit($wallet, 50);
$this->assertEquals(150, $wallet->balance);
}
/**
* Test withdrawing funds from a wallet.
*
* @return void
*/
public function testWithdraw()
{
$user = User::factory()->create();
$wallet = Wallet::factory()->create(['user_id' => $user->id, 'balance' => 100]);
$walletService = new WalletService();
$wallet = $walletService->withdraw($wallet, 50);
$this->assertEquals(50, $wallet->balance);
}
/**
* Test withdrawing funds from a wallet with insufficient balance.
*
* @return void
*/
public function testWithdrawInsufficientBalance()
{
$this->expectException(\Exception::class);
$user = User::factory()->create();
$wallet = Wallet::factory()->create(['user_id' => $user->id, 'balance' => 100]);
$walletService = new WalletService();
$walletService->withdraw($wallet, 150);
}
}
These tests cover the core functionalities of the wallet system, including creating wallets, depositing funds, withdrawing funds, and handling insufficient balances. Run the tests using the following command:
php artisan test
This will execute the tests and verify that your wallet system is working correctly. Make sure all tests pass before deploying your application.
Conclusion
Creating a wallet system in Laravel involves setting up your project, creating models and migrations, implementing core functionalities, and testing your code. This step-by-step guide provides a solid foundation for building a robust wallet system in your Laravel application. Remember to handle exceptions, validate inputs, and write tests to ensure the reliability of your system. With these steps, you'll be well on your way to managing user balances and handling transactions effectively. Happy coding, and may your wallets always be full!
Lastest News
-
-
Related News
Oscoscarssc, Scnewportsc, And The News: A Vet's Perspective
Alex Braham - Nov 12, 2025 59 Views -
Related News
Reset Your Mi Band 6 Using Your Phone
Alex Braham - Nov 13, 2025 37 Views -
Related News
5500mAh Battery Life: How Many Hours Can You Expect?
Alex Braham - Nov 14, 2025 52 Views -
Related News
Apple Valley News: Your Local Newspaper Guide
Alex Braham - Nov 17, 2025 45 Views -
Related News
Josh Turner: His Best Full Albums - Ranked!
Alex Braham - Nov 9, 2025 43 Views