Separate table for each year in Laravel - php

How can implement tables based on year in Laravel, like Orders2020, Orders2019, Orders2018 etc. And how to switch between?

I have a model with huge datas, and every month it will generate nearly 10 million+ records, so I split its table horizon too.
The solution is like this below,
In your Order model:
use Illuminate\Support\Carbon;
class Order extends Model
{
protected $table = '';
public function __construct($year='')
{
parent::__construct();
if (empty($year)) {
$tablename = 'orders'.Carbon::now()->year;
} else {
$tablename = 'orders'.$year;
}
$this->setTable($tablename);
}
}
So you can get the table you want:
$orders2018 = new Order('2018');
$orders2018->where(...)->get();
$orders = Order::where(...)->get(); // will search from the table this year.

I think you can do scope
example:
public function scopeYear($query,$year)
{
$this->table = 'orders'.year;
return $query;
}
To get from table of orders2019 just use Order::year('2019')->get();
To create data to table of orders2019 just use Order::year('2019')->create($data);

Order::from('orders_2019')->get();

i have 3 tables with same schema
i used this structure to handle that
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class ReportValues extends Model
{
use HasFactory;
protected $fillable = [
'id',
'user_id',
'report_id',
'item_id',
'value',
];
public function scopeGenerate($query, $type, $date){
$table_name = $type."_".$date;
if (!Schema::hasTable($table_name)){
Schema::create($table_name, function (Blueprint $table) {
$table->id();
$table->integer('user_id');
$table->integer('report_id');
$table->integer('item_id');
$table->tinyText('value');
$table->unique(['report_id', 'item_id', 'user_id']);
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('item_id')->references('id')->on('report_items');
});
}
return $query;
}
public function scopeSalaries($query, $date){
$this->table = 'salaries_'.$date;
return $this;
}
public function scopeContracts($query, $date){
$this->table = 'contracts_'.$date;
return $this;
}
}
and then use this command to use them :
generate table for each month clients salary :
ReportValues::generate('salaries', '202101')
and then
ReportValues::salaries('202101')->get()
or generate contract table for each year
ReportValues::generate('contracts', '202101')
and then
ReportValues::contracts('2021')->get()
My tables was :
salaries_202101
contracts_2021

Related

How to get related records for a single record in Laravel 5.8?

I have a registration table where the situation is that I have a table for months and a table for years. The relationship between months and registration is one-to-many and same is the case with years and registration like below:
//Here is the registration migration
public function up()
{
Schema::create('registrations', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('father_name');
$table->string('contact1');
$table->string('contact2')->nullable();
$table->string('address')->nullable();
$table->integer('amount');
$table->integer('day');
$table->unsignedInteger('month_id');
$table->unsignedBigInteger('year_id');
$table->timestamps();
});
}
Below is the Registration model:
class Registration extends Model
{
protected $fillable =
['name', 'father_name', 'contact1', 'contact2', 'address', 'amount',
'day', 'month_id', 'year_id'
];
public function month()
{
return $this->belongsTo(Month::class);
}
public function year()
{
return $this->belongsTo(Year::class);
}
}
This is Month model:
class Month extends Model
{
public function registration()
{
return $this->hasMany(Registration::class);
}
}
This is Year model:
class Year extends Model
{
public function registration()
{
return $this->hasMany(Registration::class);
}
}
Now, when I want to show one registration record with its relationships like below, I get all the registration records instead of one.
public function show(Registration $reg)
{
$registration = $reg::with('month', 'year')->get();
return ['registration' => $registration];
}
When I used with function with modal name then I get all records correctly but when I use it even with the single instance of the modal, I still get all the related records which I don't want. I want to select the Month and Year related to the single instance of the registration.
Any help is appreciated in advance.
This is due to ->get();
in $reg you have one instance but then you do but then you make a new request with ->get(); and get displays all records
Do it like this
public function show($regId)
{
$registration = Registration::with('month', 'year')->findOrFail($regId);
return ['registration' => $registration];
}
You can do it like this:
public function show(Registration $reg)
{
$reg->load(['month', 'year']);
return ['registration' => $reg];
}
You can also remove model binding and use with() for eager loading.
public function show($id)
{
$registration = Registration::with(['year', 'month'])
->firstWhere('id', $id);
return ['registration' => $registration];
}
It think you don't have specified the foreign_key in relation.
Or you have to define the
foreign_key by
class Registration extends Model
{
protected $fillable = [
'name', 'father_name', 'contact1', 'contact2', 'address',
'amount','day', 'month_id', 'year_id'
];
public function month()
{
return $this->belongsTo(Month::class,'month_id');
}
public function year()
{
return $this->belongsTo(Year::class,'year_id');
}
}
May be it will solve your problem.
Actually the get() method will return an array of records that you can loop over and that's why you get them all. Have you tried using the first() method that will return exactly one record.
$registration = $reg::with('month', 'year')->first();

Join two database tables in Laravel controller

I have two tables that I want to join in the controller - thought_journal_entries and emotions. A thought journal entry can contain many emotions and the foreign key in the thought_journal_entries table is em_id.
This is an example thought journal entry where the user selected emotions with id 1, 3, 5
This is the emotions table
This is the method I'm using to store data within my thought_journal_entries table
public function store(Request $request)
{
$this->validate($request, [
'thought_entry' => 'required'
]);
$entry = new ThoughtJournalEntry;
$entry->user_id = auth()->user()->id;
$entry['entry_date'] = date('Y-m-d H:i');
$entry->thought = $request->input('thought_entry');
$entry->em_id = $request->has('emotions') ? $request->get('emotions') : [];
$entry->tt_id = $request->has('thinking_traps') ? $request->get('thinking_traps') : [];
$entry->balanced_thought = $request->input('balanced_thought');
$entry->save();
return redirect('/dashboard');
}
In your example em_id column it's not a foreign key, it's a string column as I see.
Therefore, you can't execute a JOIN query for these tables. In your case, I can recommend create a third table thought_journal_entry_emotions.
Here example of code for migration file 2020_02_29_143059_create_thought_journal_entry_emotions_table.php:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateThoughtJournalEntryEmotionsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('thought_journal_entry_emotions', function (Blueprint $table) {
$table->integer('thought_journal_entry_id')->unsigned();
$table->integer('emotion_id')->unsigned();
$table->foreign('thought_journal_entry_id')
->references('id')
->on('thought_journal_entries')
->onUpdate('cascade')
->onDelete('cascade');
$table->foreign('emotion_id')
->references('id')
->on('emotions')
->onUpdate('cascade')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('thought_journal_entry_emotions');
}
}
Then you have to add relationships to your models Emotion and ThoughtJournalEntry.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Emotion extends Model
{
public function thoughtJournalEntries() {
return $this->belongsToMany(ThoughtJournalEntry::class, 'thought_journal_entry_emotions',
'emotion_id', 'thought_journal_entry_id');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class ThoughtJournalEntry extends Model
{
public function emotions() {
return $this->belongsToMany(Emotion::class, 'thought_journal_entry_emotions',
'thought_journal_entry_id', 'emotion_id');
}
}
After that you can attach Emotions to ThoughtJournalEntry in your controller using this code:
$thoughtJournalEntry = ThoughtJournalEntry::find(1);
$emotion1 = Emotion::find(1);
$emotion2 = Emotion::find(2);
$emotion3 = Emotion::find(3);
$thoughtJournalEntry->emotions()->sync([$emotion1->id, $emotion2->id, $emotion3->id]);
And finally you can load your ThoughtJournalEntry with Emotions in your controller using this code:
$thoughtJournalEntry = ThoughtJournalEntry::with('emotions')->find(1);
dd($thoughtJournalEntry);
If you wanna validate and store Emotions relations you must update your store() method (add new validate rule and sync()).
Here example:
public function store(Request $request)
{
$this->validate($request, [
'thought_entry' => 'required',
'emotions' => 'array|max:3',
'emotions.*' => 'exists:emotions,id'
]);
$entry = new ThoughtJournalEntry;
$entry->user_id = auth()->user()->id;
$entry['entry_date'] = date('Y-m-d H:i');
$entry->thought = $request->input('thought_entry');
$entry->tt_id = $request->has('thinking_traps') ? $request->get('thinking_traps') : [];
$entry->balanced_thought = $request->input('balanced_thought');
$entry->save();
$entry->emotions()->sync($request->get('emotions'));
return redirect('/dashboard');
}
Joining the table will be a little trickier since the reference value isn't present.
But if you trying to get the names of emotions from using the id stored in the array.
You will need to first save the emotions array in a variable.
$em = ["1","3","5"]
$em = ["1","3","5"];
foreach ($em as $e) {
$emotions = Emotions::find($e * 1); //am using * 1 just make sure its int
$emotions->em_name;
}
I hope that helps.
this should done using Many to Many Relationships, you are using string to store array(thats not mysql way). (but looks like you are going to save space in 'thought_journal_entries')
you can use like this:
$journal_entries = thought_journal_entries::find(1);
$icon_ids = json_decode($journal_entries->em_id); // if this column is json
$emocions = emotions::whereIn('id', $icon_ids)->get();
but this executing two quarries, that may affect db and server performance

Is there an easier way to code laravel eloquent models besides what I have here?

I created this code to work with laravel 5.8 to access a database with many foreign keys, seems like I am subverting the foreign keys, am I missing something, was hoping someone could point me in the right direction.
It works, but I think I am overdoing it and missing some eloquent shortcuts.
namespace App\Models\Entities;
use Illuminate\Database\Eloquent\Model;
class AbstractModel extends Model
{
public function isDuplicate(Model $model) {
return $model::where($model->getAttributes())->first();
}
}
///
namespace App\Models\Entities;
abstract class AbstractForeignModel extends AbstractModel {
public $timestamps = false;
public $fillable = ['value'];
public function store($value){
$foreign = $this->newInstance();
$foreign->value = $value;
if(!$this->isDuplicate($foreign)){
$foreign->save();
}
return $foreign->getId($value);
}
public function setValueAttribute($value){
$this->attributes['value'] = $value;
}
public function getId($value){
$result = self::where('value', $value)->first();
if($result){
return $result->id;
}
}
public function getValue($id){
$result = self::where('id', $id)->first();
if($result){
return $result->value;
}
}
}
///
namespace App\Models\Entities\Video;
use App\Models\Entities\AbstractForeignModel;
class ForeignModel extends AbstractForeignModel {
public function video() {
return $this->belongsTo('App\Models\Entities\Video');
}
}
Author, Description, Source, Title extend the above as empty classes
use App\Models\Entities\Video\Author;
use App\Models\Entities\Video\Description;
use App\Models\Entities\Video\Source;
use App\Models\Entities\Video\Title;
use Carbon\Carbon;
class Video extends AbstractModel {
protected $fillable = ['author_id', 'title_id', 'description_id',
'source_id', 'published_at'];
public function store($data) {
$video = new Video;
$video->author_id = $data->author;
$video->title_id = $data->title;
$video->description_id = $data->description;
$video->source_id = $data->source;
$video->published_at = $data->published_at;
if (!$this->isDuplicate($video)) {
$video->save();
}
}
public function setPublishedAtAttribute($value){
$this->attributes['published_at'] = Carbon::parse($value)->toDateTimeString();
}
public function setTitleIdAttribute($value) {
$this->attributes['title_id'] = (new Title)->store($value);
}
public function setDescriptionIdAttribute($value) {
$description = (new Description)->store($value);
$this->attributes['description_id'] = $description;
}
public function setSourceIdAttribute($value) {
$this->attributes['source_id'] =(new Source)->store($value);
}
public function setAuthorIdAttribute($value) {
$this->attributes['author_id'] = (new Author)->store($value);
}
public function getAuthorIdAttribute($value) {
$this->attributes['author_id'] = (new Author)->getValue($value);
}
public function getTitleIdAttribute($value) {
$this->attributes['title_id'] = (new Title)->getValue($value);
}
public function getDescriptionAttribute($value) {
$this->attributes['description_id'] = (new Description)->getValue($value);
}
public function getSourceIdAttribute($value) {
$this->attributes['source_id'] = (new Source)->getValue($value);
}
public function author() {
return $this->belongsTo('App\Models\Entities\Video\Author', 'author_id');
}
public function description() {
return $this->belongsTo('App\Models\Entities\Video\Description', 'description_id');
}
public function title() {
return $this->belongsTo('App\Models\Entities\Video\Title', 'title_id');
}
public function source() {
return $this->belongsTo('App\Models\Entities\Video\Source', 'source_id');
}
}
video migration file
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateVideosTable extends Migration {
public function up() {
Schema::create('videos', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('source_id');
$table->unsignedBigInteger('title_id');
$table->unsignedBigInteger('description_id');
$table->unsignedBigInteger('author_id');
$table->dateTimeTz('published_at');
$table->timestamps();
$table->foreign('source_id')->references('id')->on('sources');
$table->foreign('title_id')->references('id')->on('titles');
$table->foreign('description_id')->references('id')->on('descriptions');
$table->foreign('author_id')->references('id')->on('authors');
});
}
public function down() {
Schema::dropIfExists('videos');
}
}
The foreign key migration files follow this layout for Author, Description, Source, Title
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTitlesTable extends Migration
{
public $timestamps = false;
public function up()
{
Schema::create('titles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('value');
});
}
public function down()
{
Schema::dropIfExists('titles');
}
}
could probably create a foreign migration class and just set the variables that I need
What you're probably looking for is firstOrCreate
There are two other methods you may use to create models by mass
assigning attributes: firstOrCreate and firstOrNew. The firstOrCreate
method will attempt to locate a database record using the given column
/ value pairs. If the model can not be found in the database, a record
will be inserted with the attributes from the first parameter, along
with those in the optional second parameter.
The firstOrNew method, like firstOrCreate will attempt to locate a
record in the database matching the given attributes. However, if a
model is not found, a new model instance will be returned. Note that
the model returned by firstOrNew has not yet been persisted to the
database. You will need to call save manually to persist it.

One-To-One Eloquent Relationship functions

There is something I miss in the eloquent one-to-one relationship:
class MeetingTest extends Model
{
protected $table = 'meeting_tests';
public function meeting() {
return $this->belongsTo('App\Meeting','meeting_id','id');
}
public function observation() {
return $this->hasOne('App\Observation','meeting_test_id','id');
}
public function activity() {
return $this->hasOne('App\TestActivity','activity_id','id');
}
}
The Observation Class is
class Observation extends Model
{
protected $table = 'observations';
public function meetingTest() {
return $this->belongsTo('App\MeetingTest','meeting_test_id','id');
}
}
If I run php artisan tinker and
$mtn = App\MeetingTest::create();
$mtn->save();
$ob = App\Observation::create();
$ob->save;
$mtn->observation()->save($ob);
At this point inside the Observation record I can see the meeting_test_id filled with the correct id of the meetingTest, but if I try:
$mtn->observation
it gives me null; and in the Database there is no observation ID in the observation_id field;
this is the migration:
Schema::create('meeting_tests', function (Blueprint $table) {
$table->increments('id');
$table->integer('meeting_id')->unsigned();
$table->integer('observation_id')->unsigned()->nullable();
$table->integer('activity_id')->unsigned()->nullable();
$table->timestamps();
});
I don't understand what is not correct.
I can see observation_id and activity_id in your meeting_tests table, which makes records in this table the owned side of one-to-one/one-to-many relation. Therefore, both activity and observation relations in MeetingTest should return $this->belongsTo instead of $this->hasOne

Laravel Defining Relationships

I have one table named Content which is a master table like
Content : id content_name created_at updated_at
and another table Course like
Course table have many content_id
Course : id content_id course_name created_at updated_at
I have created relation like this.
Content Model
class Content extends Eloquent {
protected $table = 'contents';
protected $guarded = array('id');
public function course()
{
return $this->belongsTo('Course');
}
}
Course Model
class Course extends Eloquent {
protected $table = 'courses';
protected $guarded = array('id');
public function content()
{
return $this->hasMany('Content');
}
}
When i am fething the data like this
$courses=Course::find(1)->content;
It throws error like
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'contents.course_id' in 'where clause' (SQL: select * from contents where contents.course_id = 1)
I am unable to rectify the problem in relations as I am new to laravel.
Close, but you have your relationships backwards. The table that has the foreign key is the one that belongsTo the other one. In this case, your course table has the foreign key content_id, therefore Course belongs to Content, and Content has one or many Courses.
class Content extends Eloquent {
public function course() {
return $this->hasMany('Course');
}
}
class Course extends Eloquent {
public function content() {
return $this->belongsTo('Content');
}
}
in your migrations(create_courses_table) , make sure to set the foreign key like that ,
$table->integer('content_id)->unsigned()->index();
$table->foreign('content_id')
->references('id')
->on('contents')
->onDelete('cascade');
I don't really understand your table design, maybe it should be something like this.
Taking your statement: "Course table have many content_id". I perceive that you are saying that 1 course can have multiple content, is that right? If yes, you might want to change your table design to something like below
Course
======
id
course_name
created_at
updated_at
Content
=======
id
course_id (set this as FK)
content_name
created_at
updated_at
migration code for content
public function up()
{
Schema::create('content', function(Blueprint $table)
{
$table->engine = 'InnoDB';
$table->increments('id');
$table->integer('course_id')->unsigned();
$table->string('content_name');
});
Schema::table('content',function($table)
{
$table->foreign('course_id')->references('id')->on('course')->onDelete('cascade');
});
}
Then in your model
class Course extends Eloquent
{
protected $table = 'course';
public function content()
{
return $this->hasMany('content', 'course_id', 'id');
}
}
class Content extends Eloquent
{
protected $table = 'content';
public function course()
{
return $this->belongsTo('course', 'course_id', 'id');
}
}
Then to access your data via eager loading
$course = Course::with('content')->get();
OR
$content = Content::with('course')->get();
This is about determining associations. Your associations should be:
Content
Content has many courses
class Content extends Eloquent {
protected $table = 'contents';
protected $guarded = array('id');
public function courses()
{
return $this->hasMany('Course');
}
}
Course
The course belongs to content.
class Course extends Eloquent {
protected $table = 'courses';
protected $guarded = array('id');
public function content()
{
return $this->belongsTo('Content');
}
}
So you can do query association.
For finding content -> courses:
$courses = Content::find(1)->courses;
For finding course -> content:
$content = Course::find(1)->content;

Categories