Multi table inheritance in Laravel - laravel

I want just a simple example on how to have multi tables in database using Eloquent, for example :
I have a Model "Person", and there is 2 classes extending from this Model : Student and Teacher, and in database I don't want to have one table (persons), I want to have 2 tables (students and teachers).
How this is possible in Laravel (Eloquent), give me just the code of the three classes (Person, Student and Teacher).
Thanks a lot :)

Not tested but should work:
Docs
Person.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Person extends Model {
// ...
}
Student.php
<?php
namespace App;
class Student extends Person {
$table = 'students';
// ...
}
Teacher.php
<?php
namespace App;
class Teacher extends Person {
$table = 'teachers';
// ...
}
Migrations
You can create the desired migrations as usual with php artisan make:migration create_students_table --create=students. Then migrate with php artisan migrate
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateStudentsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('students', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
// ...
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('students');
}
}
EDIT
I don't know the background but maybe a trait is the better alternative.

Related

How to reflect the data into server database?

I am using laravel framework and firebase-database,i am using laravel-firebase-sync package which is responsible for syncing the data to firebase and it's allows to use Eloquent queries upto this part is working fine,i created two migrations and models (User.php and Books.php).
when i hit user registration api the data is being stored in the firebase database ,when i create book(one to many relationships to the users table) the data is being stored in my local-DB(mysql) and it's not reflecting into the firebase,can you suggest how to sync the relations data into firebase
createBooksTable
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateBooksTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('books');
}
}
Books.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Mpociot\Firebase\SyncsWithFirebase;
class Books extends Model
{
//
use SyncsWithFirebase;
public function users(){
return $this->hasMany(User::class);
}
}
controller
public function createBook(Request $request){
Books::insert(['name' => $request->name,
'user_id' => $request->user_id
]);
return response()->json(['done']);
}

why foreign key not get setted in laravel migrations

I made an exam-question relationship, every exam has less than 200 questions, but when I run migrations, I go to the PHPMyAdmin and I don't find the foreign key set, it's only a bigint(20) unsigned column and not linked to the exams table.
exam model
<?php
namespace App\Models;
use App\Models\Question;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Exam extends Model
{
use HasFactory;
protected $fillable = [
//
];
public function questions(){
return $this->hasMany(Question::class);
}
}
question model
<?php
namespace App\Models;
use App\Models\Exam;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Question extends Model
{
use HasFactory;
function exam(){
return $this->belongsTo(Exam::class);
}
}
exam migration
<?php
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateExamsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('exams', function (Blueprint $table) {
$table->id();
$table->string('examHash')->unique();
//..
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('exams');
}
}
questions migrations
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateQuestionsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('questions', function (Blueprint $table) {
$table->id();
$table->foreignId('exam_id')->constrained();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('questions');
}
}
I've tried to:
Use this
$table->foreign('exam_id')->references('id')->on('exams');
but
Key column 'exam_id' doesn't exist in table
EDIT:
it can be caused because my engine is not InnoDB, regularly I change the engine to InnoDB to create foreign keys
The method foreignId will only create an UNSIGNED BIGINT and not a foreign key constraint. To also create a constraint you need to call constrained() afterward.
Try this:
Schema::create('questions', function (Blueprint $table) {
$table->id();
$table->foreignId('exam_id')->constrained();
$table->timestamps();
});
You can also find more information in the documentation.
Try to add the constrained method when you define the foreign key in question's migration, change:
$table->foreignId('exam_id');
to:
$table->foreignId('exam_id')->constrained();
the problem as I've mentioned in the question is in the engine. so I wrote
$table->engine = 'InnoDB';
in both of question and exam tables...

My one to many relation does not work, It bringing up the error '' Trying to get property 'senders_name' '' when I try to call it up in view

I want to be able to pass the value of my related table to my views, I am making use of a One to Many relation. also I am trying to do the connection without using a foreign key, well I have been informed that using it for mysql database is not efficient and it would probably brings up error or not do anything.
I actually tested it, I mean the foreign key, it did not work.
Post model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
//Post model
protected $table = 'posts';
public function staff()
{
return $this->belongsTo('App\Models\Staff');
}
}
Staff model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Staff extends Model
{
protected $table = 'staff';
public function posts()
{
return $this->hasMany('App\Models\Post');
}
}
Create posts table migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePostsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{ //my post table
Schema::create('posts', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('name');
$table->string('phone_number');
$table->mediumText('fault_explained');
$table->string('repair_type');
$table->string('repair_part');
$table->integer('repair_total');
$table->mediumtext('justify');
$table->string('vendor_name');
$table->string('vendor_number');
$table->string('status_option');
$table->integer('status_value');
$table->string('vehicle_name');
$table->string('vehicle_number');
$table->integer('staff_id')->nullable()->unsigned();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('posts');
}
}
Create staff table migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateStaffTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{ //Staff table
Schema::create('staff', function (Blueprint $table) {
$table->increments('id');
$table->string('senders_name');
$table->string('senders_number');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('staff');
}
}
View:
<div class="content-wrapper">
<main class="st_viewport">
<div class="border bg-warning">
<div style="margin-left:14px; margin-top:5px;">
<span class="h2 wrapper " > <em><b>SUBJECT:</b> {{ $posts->title }}</span></em>
</div>
<div class="" style="margin-left:14px; margin-bottom:5px;">
<em><b>Sent on</b> {{ $posts->created_at }}</em> {{ $posts->staff->senders_name}}
</div>
In the Post model you should use -
public function staff()
{
return $this->belongsTo(Staff::class);
}
In the Staff model you should use -
public function posts()
{
return $this->hasMany(Post::class);
}
In CreatePostsTable migration you need to add one more line -
$table->foreign('staff_id')->references('id')->on('staff');
You must replace App\Models\Staff with Staff::class in your code.
...
return $this->belongsTo(Staff::class);
...

Get attribute in model - laravel eloquent

In laravel i can getFirstNameAttribute in my products model and change the value but I'm create this column "priceArray" and i can not get attributes because The first letter in the second word is capital letters and model can not found this column.
public function getPriceArrayAttribute($value)
{
return 'test';
}
Its not work and can not get "priceArray" column
This is my migration
<?php
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('title')->nullable();
$table->string('price')->nullable();
$table->string('priceArray')->nullable();
$table->text('items')->nullable();
$table->enum('status',['active','inactive','unavailable'])->default('inactive');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('products');
}
}
This is my product model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
/**
* Class Products
* #package App\Models
* #property Variants Variants
*/
class Products extends Model
{
use HasFactory;
protected $guarded=[];
protected $changePrice=0;
public function Insert($data)
{
return self::create($data);
}
public function getPriceArrayAttribute($value)
{
return 'test';
}
public function getPriceAttribute($value)
{
return ceil($value);
}
}
The getPriceAttribute is worked but getPriceArrayAttribute does not worked
I think you are trying to modify the priceArray value after it is retrieved from the database, the way you did with ceil() on the price attribute. The only way this works is if you change the column name to price_array. This is by far the simplest fix.
Migration
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('title')->nullable();
$table->string('price')->nullable();
$table->string('price_array')->nullable();
$table->text('items')->nullable();
$table->enum('status',['active','inactive','unavailable'])->default('inactive');
$table->timestamps();
});
Model
public function getPriceArrayAttribute($value)
{
return 'test';
}
You must follow Eloquent's rules: you use snake case for the attributes. The getPriceArrayAttribute accessor will automatically be called by Eloquent when you retrieve the value of the price_array attribute.
$table->string('price_array')->nullable();

Laravel API: How to get data from foreign key from different table

I currently want to make an API that will get all the lessons by its module_id. These are currently my codes:
Module Migration Table:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateModulesTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up() {
Schema::create('modules', function (Blueprint $table) {
$table->id();
$table->string('module_name');
$table->bigInteger('created_by')->unsigned()->nullable();
$table->bigInteger('updated_by')->unsigned()->nullable();
$table->timestamps();
});
Schema::table('modules', function(Blueprint $table) {
$table->foreign('created_by')->references('id')->on('admins');
$table->foreign('updated_by')->references('id')->on('admins');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down() {
Schema::dropIfExists('modules');
}
}
Lesson Migration Table:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateLessonTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up() {
Schema::create('lesson', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->bigInteger('module_id')->unsigned();
$table->longText('content');
$table->bigInteger('created_by')->unsigned()->nullable();
$table->bigInteger('updated_by')->unsigned()->nullable();
$table->string('enabled')->nullable();
$table->string('position')->nullable();
$table->timestamps();
});
Schema::table('lesson', function(Blueprint $table) {
$table->foreign('module_id')->references('id')->on('modules');
$table->foreign('created_by')->references('id')->on('admins');
$table->foreign('updated_by')->references('id')->on('admins');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down() {
Schema::dropIfExists('lesson');
}
}
And this is the GetLessonByModule controller of that API I want to make (getting all the lessons by its module_id):
<?php
namespace App\Http\Controllers;
use App\Models\Lesson;
use App\Models\Modules;
use Illuminate\Http\Request;
class GetLessonByModuleController extends Controller {
public function index() {
$lessons = Lesson::all();
return response($lessons,200);
}
}
The module_id and the ID in the modules table are currently connected as seen in the migration tables. I just don't know how to compose it in my Controller. I also don't know if I should make a new model. Any kind of help/suggestion is deeply appreciated. Thanks in advance.
You can do
<?php
namespace App\Http\Controllers;
use App\Models\Lesson;
use App\Models\Modules;
use Illuminate\Http\Request;
class GetLessonByModuleController extends Controller {
public function index(int $module_id) {
$lessons = Lesson::where('module_id', '=', $module_id)->get();
return response($lessons,200);
}
}
In your api.php there should be definition of the route:
Route::get('lessons-by-module/{module_id}', [\App\Http\Controllers::class, 'index']);
If it works for you and want to do it better, you can go fancy with Laravel routing explicit binding: https://laravel.com/docs/8.x/routing#explicit-binding

Resources