Made using Laravel and Sanctum.
Keep track of the books you've read. Set a reading goal and complete it. Add books to bookshelves.
php 7.4.9, composer 2.6.1 with Laravel 8.83.27
- id (PK, auto-increment)
- email (unique)
- pwd
- id (PK, auto-increment)
- user id (foreign key referencing Users(user_id) )
- username (varchar)
- avg_rating (float)
- total_read (integer)
- reading_goal (integer)
- id (PK)
- user_id (FK referencing PK of Users table)
- title (varchar)
- author (varchar)
- start_date (date)
- end_date (date, >start_date)
- rating (integer, <=5)
- book_id (FK referencing PK of Book table)
- shelf_id (FK referencing PK of Shelves table)
- id (PK)
- name (varchar)
- One User only had one User Profile. And, a user profile only belongs to one user
- One User may have one or more books. But, one book only belongs to one user.
- One book may have multiple shelves (through shelf junction). And, one shelf may have multiple books.
- composer create-project laravel/laravel Book-Tracker
- made necessary changes in .env
- git init
- git add .
- git commit -m "first commit"
- git remote add origin https://github.com/yusha-g/Book-Tracker.git
- git push -u origin master
-
Creating
- User model already exists. Will make changes to it if and when required.
php artisan make:model UserProfile -m
php artisan make:model Book -m
php artisan make:model Shelves -m
php artisan make:model ShelfJunction -m
php artisan make:migration insert_default_shelves
[will insert the default shelves: read, reading and tbr]- In each model, add corresponding fillable and specify relationships with other tables. [example with Book Model]
protected $fillable = [ 'user_id', 'title', 'author', 'start_date', 'end_date', 'personal_rating' ]; public function user(){ return $this->belongsTo(User::class); } public function shelves(){ /*intermediate table, foreign keys in the intemediary table (book belongs to many shelves via shelf junction) */ return $this->belongsToMany(Shelves::class, 'shelf_junction','book_id','shelf_id'); }
-
Editing Migrations (example with user_profoiles_table)
- Define table structure like so:
Schema::create('user_profiles', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('user_id')->notNullable(); $table->string('username')->notNullabe(); $table->float('avg_rating',2,1)->nullable()->default('0'); $table->bigInteger('total_read')->nullable()->default('0'); $table->bigInteger('reading_goal')->nullable()->default('0'); $table->timestamps(); });
-
Define Relationship with other tables:
Schema::table('user_profiles', function($table){ $table->foreign('user_id')->reference('id')->on('users'); });
-
Because Eloquent does not support sql checks, write them separately:
ALTERNATELY / ADDITIONALLY: We can add these checks during validation
DB::statement(' ALTER TABLE user_profiles ADD CONSTRAINT anv_rating_check CHECK (avg_rating >= 0 AND avg_rating <= 5) ');
-
Using Composite Primary Key
$table->primary(['book_id', 'shelf_id']);
In doing so, you just specify the primary key in the model as well:
protected $primaryKey = ['book_id', 'shelf_id'];
-
Inserting Default Shelves [read, reading, tbr]
public function up() { DB::table('shelves')->insert([ ['name'=>'read'], ['name'=>'reading'], ['name'=>'tbr'] ]); } public function down() { DB::table('shelves')->whereIn('name',['read','reading','tbr'])->delete(); }
- Define table structure like so:
php artisan make:controller BookController
- routes.php > api.php
- Import BookController
use App\Http\Controllers\BookController;
- group book related routes together:
2.1.
Route::middleware([])->prefix('book')->group(function(){}
2.2. will add middleware later - Inside the function, add the routes as follows:
3.1.
Route::post('/',[BookController::class, 'create']);
3.2. add similar routes for get, put and delete
- Import BookController
- Implement the necessary functions in BookController
Laravel 8 provide sanctum by default
-
In App\Http\Kernel.php uncomment \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, under the api seciton
-
Create the login and register routes with post method.
Route::post('/login',[AuthController::class,'login']); Route::post('/register',[AuthController::class,'register']); Route::post('/logout',[AuthController::class,'logout']);
-
php artisan make:controller AuthController
-
Corresponding to the above routes, create functions for register, login and logout.
-
IMPLEMENTING REGISTER
-
Validate request
$validateUser = Validator::make($req->all(),[ 'name'=>'required', 'email'=>'required', 'password'=>'required', 'confirm_password'=>'required|same:password', ]); if($validateUser -> fails()){ $res = [ 'success'=>false, 'message'=> $validateUser -> errors() ]; }
-
Once validated, create new user and issue token
-
-
IMPLEMENT LOGIN
- Similar to Registration, validate the user.
- Once validated, attempt authentication.
- If Authentication succeeds issue a token