Laravel assumes the database table is the plural form of the model name - laravel

By default, Laravel is assuming that the database table is the plural form of the model name. But what if my table name is "news" and i still want to use this feature? should i change it to "newses" or should i use "new" for the model name?

You may specify a custom table by defining a table property on your model as below
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
/**
* The table associated with the model.
*
* #var string
*/
protected $table = 'my_flights';
}
Ref:https://laravel.com/docs/5.1/eloquent

If you have a model ending with the letter 's', it will keep the table name the same. In your case, your model will name your table news by default.
If you want to use another name though, you can use:
protected $table = 'tablename';
inside of your model.
EDIT: I tested this in my application. I made a model named News. Then I made a new instance of News and retrieved the table name:
$news = new News();
dd($news->getTable());
It returns: news

Inside your eloquent model you have to define table name. For example if my model is named user and table in database is named user_of_application then i do it this way
class user extends Model
{
protected $table = 'user_of_application';
}

Laravel uses a "standard set" rule that defines:
A Model is a single instance of a record
A Collection is one or more records
Therefore it assumes that a table is a collection of records.
The nomenclature has a problem when it clashes with various features / gotchas of human languages. For example, what if I have a Model called Sheep? That does mean my Database Table should be called "Sheeps"?
It's up to the developer to avoid "Gollum/Smeagol" syntax. Indeed, you wouldn't want a table called "Newses" as much I'd like to end up with a table called "Sheeps".
Ultimately, I construct Migrations with:
sudo php artisan make:migration create_sheep_table --create=sheep
As for Models, you'll notice in the documentation that they have a different table name for "Flights" called "my_flights"
https://laravel.com/docs/master/eloquent#defining-models
Again, it's up to the developer / DB manager to make decisions on naming conventions that make sense in an application context.

Related

Can we use an observer on the attach method in Laravel?

I would like to observe a pivot table in which, rows are created with an attach method in a specific model, is there a way to Observe that pivot table through the attach method that is responsible for creating rows?
after struggling some time, I came to answer my question,
so in order to observe a table whose rows are created by the attach method, we will need to do 3 things
1- we will need to create a model that extends
$Illuminate\Database\Eloquent\Relations\Pivot
2- Connect the model to the database table with this line:
protected $table = 'data_base_table_name';
3- use the method 'using' at the end of the BelongsToMany relationship in each model that is related to the pivot table
Example:
let's say we have a model called Student and another one called Group, we have also a pivot table called group_students that is filled with the attach method since we have a student BelongsToMany groups and Group BelongsToMany Students,
we will need to create a model named GroupStudent that extends
Illuminate\Database\Eloquent\Relations\Pivot
and link it to the group_students by adding the following line in the GroupStudent Class:
protected $table = 'group_student'
After that, we will need to add the using method The BelongsToMany relations in the Student Model and the Group Model like the following:
public function students()
{
return $this->BelongsToMany(Student::class)->using(GroupStudent::class);
}
and
public function groups()
{
return $this->belongsToMany(Group::class)->using(GroupStudent::class);
}
And here we go, now whenever I create a row in the group_students table through the attach method, this will be observed and the method created will be executed.

Laravel Polymorphic Many-to-Many relationship pivot table with relationship to another Model

I have the following table structure as shown in the diagram:
Briefly, it is composed of several many-to-many polymorphic relationships as described:
many resources can have many sources and the pivot table sourceables contains catalog_number and lot_number information to make each row in the pivot table unique. Many resources could also come from the same source or from different sources, differentiated by the catalog number and lot number on the pivot table.
many resources can also have many publications attached to it, through the publicationables table with notes on the pivot table
a resource's source could also be described in many publications.
My questions:
Since the resource's source is differentiated by the pivot table sourceables how should I save the relationship between the pivot rows of sourceables to the publications?
Can you have a custom intermediate table models between both sourceables and 'publicationables' to link to the publications?
How to retrieve a resource with all it's publications and also with the sources with all corresponding publications?
Here is my answer and I hope that I can bring some light to your problem. I already publish a GitHub repository with an example of all the code I write here. I add more information about how to replicate my scenario there.
The Database and The Relations
Here is my interpretation of the Database and its relations. You can check all the Migrations on the repository.
The Solution
Question 1:
How should I save the relationship between the pivot rows of sourceable to the publications?
Answer:
Before proceeding with the code example, I would like to explain some important concepts to understand. I'm going to use the expression tag to refer to the identifier or index Morph Relations used to relate models.
The way this works, it's by assigning the tag to any Model you want to add into a relation. Any model using these tags can be store in the Morph Pivot Table. Laravel uses the _"modelable"type column to filter the call on the relations storing the Model Name. You can "tag" your Model with a Relation creating a method into the Model that returns the morphToMany relation function.
For this specific case, here's how to proceed:
In your Resource Model, you have two methods, one related to the sourceable index and the other with the publicationable tag using morphToMany in return.
Here's how it's look the Resource Model (./app/Models/Resource.php):
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Resource extends Model
{
use HasFactory;
protected $guarded = [];
public function publications()
{
return $this->morphToMany(Publication::class, 'publicationable')->withPivot('notes');
}
public function sources()
{
return $this->morphToMany(Source::class, 'sourceable')->withPivot(['catalog_number', 'lot_number']);
}
}
In your Publication Model, you have two methods, one related to the sourceable index and the other with the inverse relation with the Resource Method to the publicationable tag using morphedByMany in return.
Here's how it looks the Publication Model (./app/Models/Publication.php):
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Publication extends Model
{
use HasFactory;
protected $guarded = [];
public function sources()
{
return $this->morphToMany(Source::class, 'sourceable')->withPivot(['catalog_number', 'lot_number']);
}
public function resources()
{
return $this->morphedByMany(Resource::class, 'publicationable');
}
}
With this, you can be able to accomplish your goal of relating Publications with Resources and Sources.
Question 2: Can you have an intermediate table between both sourceable and publicationable to link to the publications?
Answer:
No, you don't need to. You can use the sourceables table to accomplish this. You can always relate a Source with ANY model by creating the method that returns the morphToMany relation to the Source model. These what we do with Publications on Question 1.
Question 3: How to retrieve a resource with all its publications and the sources with all corresponding publications?
Answer:
I think Eloquent it's my favorite feature on the whole Laravel Framework. This the cherry on the cake with all we do on the Model definition.
If you check the Resource and Publication Model definition again, we add a withPivot() method with the related field we want to include on any call we do to the relation with eloquent. This method made it possible to read custom values from the Pivot table.
IMPORTANT: For this example, I'm implicitly adding the pivot values because I don't declare those columns as NULL on the migrations.
To relate (Store on the Pivot table) a publication with a resource using the relation, you just need to:
(Using artisan tinker)
Psy Shell v0.10.8 (PHP 8.0.6 — CLI) by Justin Hileman
>>> $publication = \App\Models\Publication::find(5)
>>> $resource = \App\Models\Resource::find(19)
>>> $resource->publications()->attach($publication, ["notes" => "Eureka!"]);
### Adding another Publication
>>> $publication = \App\Models\Publication::find(10)
>>> $resource->publications()->attach($publication, ["notes" => "Eureka 2!"]);
(Using a Controller)
use App\Models\Resource;
use App\Models\Publication;
...
$id_resource = 1; // This is the Resource Id you want to reach.
$id_publication = 10; // This is the Resource Id you want to reach.
$resource = Resource::find($id_resource);
$publication = Publication::find($id_publication);
$pivotData = [ "notes" => "Eureka!" ];
$resource->publications()->attach($publication, $pivotData);
To retrieve all publications from a resource, you just need to:
(Using artisan tinker)
Psy Shell v0.10.8 (PHP 8.0.6 — CLI) by Justin Hileman
>>> $resource = \App\Models\Publication::find(5)
>>> $resource->publications()->get();
Easy right? :) Eloquent POWER!
(Using a Controller)
use App\Models\Resource;
...
$id_resource = 1; // This is the Resource Id you want to reach.
$resource = Resource::find($id_resource);
$resource->publications()->get();
Just in case of any doubt, this is how you can store and retrieve from all the models:
(Using a Controller)
use App\Models\Publication;
use App\Models\Resource;
use App\Models\Source;
...
... Method ...
$id_publication = 1;
$id_resource = 1;
$id_source = 1;
$publication = Publication::find($id_resource);
$resource = Resource::find($id_resource);
$source = Source::find($id_resource);
$publicationPivotColumns = [
"notes" => "This is a note...",
];
$sourcePivotColumns = [
"catalog_number" => 100,
"lot_number" => 4903,
];
// Storing Data
// Attach (Store in the publicationables table) a Publication to a Resource
$resource->publications()->attach($publication, $publicationPivotColumns);
// Attach (Store in the sourceables table) a Source to a Resource
$resource->sources()->attach($source, $sourcePivotColumns);
// Attach (Store in the sourceables table) a Source to a Publication
$publication->sources()->attach($source, $sourcePivotColumns);
// Retraiving Data
// Get all Sources from a Resource
$resource->sources()->get();
// Get all Publications from a Resource
$resource->publications()->get();
// Get all Sources from a Publication
$publication->sources()->get();

Laravel: Saving a relationship when instanciating an Eloquent model rises this SQL error: "Integrity constraint violation"

Summary
Context and Needs
Minimal, Testable and Executable sources (with instructions for testing)
Actual Results and Expected Results
What I've tried
The Question
Context and Needs
The relationship between both Eloquent models GalleryImage and GalleryGroup is: GalleryImage * <-> 1 GalleryGroup. I want to save an instance of GalleryGroup, then of GalleryImage.
Minimal, Testable and Executable sources
Instructions to test
I wanted to show you how to test my code in the case you really want to do it ;-) . However, I think you don't actually need to test. Indeed, the code is very simple. By reading it, if you know more than me Laravel, maybe you will find the problem and be able to bring me some help. I let you reading the following contents but I think you'll agree with me.
Create the tables for GalleryGroup and GalleryImage (out of topic). The fields to create and the name of the tables are contained in the following sources.
Copy/Paste the Eloquent models and the script that instanciates them and tries to save them in DB.
Creates the routes of your choice to run the script and then, run the script (ie.: access the Web page or use a REST client)
The Eloquent models
-- GalleryGroup.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class GalleryGroup extends Model
{
use HasFactory;
protected $primaryKey = 'group_id';
private $name;
public function images() {
return $this->hasMany(GalleryImage::class);
}
}
-- GalleryImage.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class GalleryImage extends Model
{
use HasFactory;
protected $primaryKey = 'image_id';
public function group() {
return $this->hasOne(GalleryGroup::class, 'group_id', 'image_id');
}
}
Instanciations and concretization of the relationship
The Eloquent model GalleryGroup is instanciated and saved in db; then, the Eloquent model GalleryImage is instanciated and should be saved in db:
$img_group = new GalleryGroup();
$img_group->name = 'foobar';
$img_group->save();
$image = new GalleryImage();
var_dump($img_group->group_id); // It exists and it's not empty
$image->group()->save($img_group);
$image->save();
Actual Results and Expected Results
The last line is never executed because this error is raised at the line $image->group()->save($img_group);:
Illuminate\Database\QueryException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'group_id' cannot be null (SQL: update gallery_groups set group_id = ?, gallery_groups.updated_at = 2021-01-09 10:16:44 where group_id = 24) in file /var/www/html/api/vendor/laravel/framework/src/Illuminate/Database/Connection.php on line 671
I don't understand why it tries to update the group entry, and I don't understand why group_id is NULL or empty, because $img_group actually has a non-empty group_id (cf.: the line var_dump($img_group->group_id);).
The actual results are: 1) the model GalleryGroup is correctly instanciated and correctly saved in db and 2) the model GalleryImage is correctly instanciated and not saved in db because of the above SQL error is raised.
The expected results are: 1) the model GalleryGroup is correctly instanciated and correctly saved in db and 2) the model GalleryImage is correctly instanciated and saved in db.
What I've tried
I've tried to var_dump several times several variables but did not found any relevant information to help debugging this issue.
I've read and re-read the docs https://laravel.com/docs/8.x/eloquent-relationships#the-save-method and https://laravel.com/docs/8.x/eloquent#primary-keys but did not found any relevant information to help debugging this issue.
The Question
Why is this error raised and how to fix it?
One of these relationships needs to be a belongsTo as one of these tables has the foreign key on it that relates to the other table. I would assume a GalleryImage belongs to a GalleryGroup:
GalleryGroup
images
hasMany GalleryImage
GalleryImage
gallery
belongsTo GalleryGroup
Once those are setup correctly you should be able to do this to save the relationship:
$img_group->images()->save($image);

Laravel retrieve records from database using mysql view instead of the table itself

I know this is a simple question and I tried hard to search a solution for this. Maybe someone knows or experienced this already that might help me.
I am only a beginner in using Laravel please bear with me.
So I have this AgencyModel, the name of my table in the database is agency.
And I have a MySQL view which is named view_agency, this contains the inner join of the agency table and other tables that has connection with it.
Model (This is the working code)
protected $table = 'agency';
The records displays when I use the agency as the table name
But MySQL view table view_agency does not display/retrive the records from the database.
Model (This code is not working)
protected $table = 'view_agency';
I have a suspicion that the laravel eloquent might have to do with this, because $table is only being accepted and not mysql view.
use Illuminate\Database\Eloquent\Model;
Thanks...
In SQL, a view is a virtual table based on the result-set of an SQL statement.
And you can get datas from view just like table's datas:
select * from view_agency
So you can use Laravel query builder or Eloquent builder to query records like table,
Laravel will convert the query builder or Eloquent to sql, so it will works:
DB::table('view_agency')->get();
I used do this before, I created a views/ directory inside the models/, and create the all views' files inside.
I think you can create that view model like this:
namespace App\Models\Views;
use Illuminate\Database\Eloquent\Model;
class ViewAgency extends Model {
}
However, I am following the laravel's way. I use the lowercase underscore plural form. So when I use ViewAgency, Laravel will find the table or view's name which is view_agencies:
ViewAgency::first();
It works fine.
And If you want to change the name, and I think there is no error with protected $table = 'view_agency;', You can try this way:
class ViewAgency extends Model {
public function __construct()
{
$this->setTable('view_agency');
}
}
This will work, too

Eloquent join with where clause

I have problems to build a relationship with eloquent.
I have two models created, Spielplan and Verein. In model Spielplan I have the fields Team_ID and Spiel_ID. In model Verein I have the field V_ID and Name. Now I need to join this two tables about Team_ID = V_ID.
This is my model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Spielplan extends Model
{
protected $table = 'Spielplan';
public function vereinFunction(){
return $this->hasOne('App\Verein', 'V_ID');
}
}
And this is a function in my web route where I want to get Spiel_ID and Name.
Route::get('test', function(){
$spieleT = App\Spielplan::where('Spiel_ID', '=', 30)->get();
foreach($spieleT as $da){
echo $da->Spiel_ID;
echo $da->vereinFunction->Name;
}
});
The first echo works and I get back Spiel_ID but the second echo gives back ErrorException Trying to get property of non-object.
What is wrong with my code?
Try editing this line:
$spieleT = App\Spielplan::with('vereInFunction')->where('Spiel_ID', '=', 30)->get();.
The with() allows you to fetch the association at the time you use get(). After using get(), you're working with a collection, and can't query the database again.
Try specifying the model primary key as a third argument, because if not, Laravel will assume it is named id, which is not the case.
Allow me to suggest you something: I used to name the tables and fields like you do (in the days I use Codeigniter) but since I started using Laravel around three years ago, I follow Laravel convention (which is recommended, but not imposed). I now name the tables in lowercase, (snakecase) plural, table fields also snakecasm lowercase. Models singular, camelcase similar corresponding table, relation function names as related model, being singular if relation is to one, plural if to many, etc. The advantage of this is among other reflected in model relationship declaration, which is a lot simpler and easier to define.
For instance (only as demonstration of stated above),
tables (with relation one to many:
managers (primarykey: id, name, ......)
technicians (primary key: id, foreingkey: manager_id (related table name in singular plus underscore plus id), name, .....)
models:
Manager:
/* relationships */
public function technicians () // see name as related table, plural due to as many relationship)
{
return $this->hasMany(Technician::class); // as naming convention has followed, you don't need to specify any extra parameters;
}
Techician:
/* relationship */
public function manager() // named as related table, singular due to to one relationship
{
$this->belongsToOne(Manager::class); // again, as naming convention has followed, you don't need to specify any extra parameters;
}
Therefore you can do this:
$manager::find(1);
echo $manager->technicians->first()->name,
or
foreach ($manager->technicians as $technician) {
echo $technician->name;
}
as well as:
$technician->manager->name;
Remember, a proper model relationship definition will save a lot of headache along the way, like the one you have
Hope this help in anyway

Resources