/biblio-backend

API for an online library project

Primary LanguagePHP

image



Work  - In Progress

Introduction

Biblio is a web app for managing the work flow of a library, coming with an API that you can consume in the frontend.

Links:

Frontend
Backend
Postman API collection

Installation:

Backend:

Clone the repo first:

$ git clone https://github.com/hbakouane/biblio-backend && cd biblio-backend 

Install composer dependecies:

composer i

Create .env file

cp .env.example .env

Generate a key:

php artisan key:generate

Go to your .env and add your database credentials then run the migration

php artisan migrate

Are you on Mac? and using Valet? make sure you run this command so you can access the app via: biblio-backend.test

valet park

So far the project is good to go.

Project architecture:

The whole project is located at the Modules folder, you can find there models, controllers, factories & seeders, migrations, observers, mails and ...
Each module has a folder, let's take the Book module for example:

| Modules
    | Book
        | Config
        | Console
        | Database
            | factories
            | Migrations
            | Seeders
        | Entities
            Book.php
        | Http
            | Controllers
            | Middlewares
            | Requests
            | Traits
        | Providers
        | Resources
            | views
        | Routes
            books.php
        | Tests
        | Transformers
            BookResource
        composer.json
        module.json
        package.json
        vite.config.js
    | Order
    | Category
    | User
    | Profile
    ...

General information are located in the Core.php file, it has information like:

class Core
{
    /**
     * Items to return per page in a pagination
     */
    const ITEMS_PER_PAGE = 10;

    /**
     * Allowed image extensions
     *
     * @var array|string[]
     */
    public static array $allowedImageExtension = ['png', 'jpg', 'jpeg', 'svg'];

    /**
     * All media collections
     */
    const COLLECTION_PROFILE_IMAGES = 'profile_images';
}

Mechanism:

We are gonna be using the command with the namespace module all over the application in order to create any Model, controller or whatever.

Create a new Module:

php artisan module:make Customer

This creates our module folder which will hold all the files inside the Modules folder.

Create a new Model

php artisan module:make-model Customer Customer

This will create a file in: Modules/Customer/Entities/Customer.php
the created model looks like this:

<?php

namespace Modules\Customer\Entities;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use App\Traits\Uuids;

class Customer extends Model
{
    use HasFactory, Uuids;

    /**
     * Mass-assignable attributes
     *
     * @var array[]
    */
    protected $fillable = [];

    protected static function newFactory()
    {
        return \Modules\Customer\Database\factories\CustomerFactory::new();
    }
}

To follow the convention of how the project was built, you have to create some files for each new created model, let's take the Book model for example:

use HasFactory, Uuids, BookMethods, BookRelationships, Updatable;

Let's go through the unusual ones one by one:

BookMethods:

This trait includes every method that is related to the book model, for example: createBook()

You will notice that the BookMethods has a method called createBook(), well, that's the case with every other module, we have one method which responsible for creating a new record of that model so that we can do modifications easily and just in one place when we want.

BookRelationships:

This trait includes every relationship of the book model, for example: publisher() or category()

Updatable:

This is a global trait which can be used for all the models, it includes methods that related to updating a model, like: updateUsingRequest()

The goal from those traits is mainly leaving the Models just for properties, besides, any developer who is new to the project, they can directly access a method/relationship because they know exactly where it might be located.

Create a new controller:

Note: All the controllers are a single action controller

php artisan module:make-controller FetchAllCustomers Customer

Migration:

Go to Modules/Customer/migrations/create_customers_table.php and put your code there

File Upload:

We have one method that handles file uploading all over the project, it's located in the Modules\Core\Http\Controllers\CoreController class and it's called uploadMedia, you basically feed it 2 required arguments and 3 optional ones.

/**
 * Uploads the given media to a collection
 *
 * @param User|Model $model
 * @param $media
 * @param string $collection
 * @param string|null $name
 * @param string|null $fileName
 * @return void
 * @throws FileDoesNotExist
 * @throws FileIsTooBig
 */
public function uploadMedia(
    User|Model $model,
    $media,
    string $collection,
    string $name = null,
    string $fileName = null
)
{
    $media = $model->addMedia($media);

    if ($name) $media->usingName($name);

    if ($fileName) $media->usingFileName($fileName);

    return $media->toMediaCollection($collection);
}

Mail:

We already have an email template that's looking like this, however, to write content for a mail blade, you can extend the mail layout and put your content inside the content holder, the blade file for your email would look something like this:

@extends('core::layouts.mail')

@section('body')
    {!! __('a title here') !!}

    <div class="text-center mt-3">
        <!-- Content go here -->
    
        @include('core::_partials.mails.cta', [
            'text' => __('app.mail.discover_books'),
            'url' => config('app.url')
        ])
    </div>
@endsection

The output will be something like this:

Capture d’écran 2023-07-08 à 01 57 13-modified (1)