How do I declare a composite primary key in the Lumen Model? - laravel

I have a table with three primary keys, I'm trying to create a model for it, and I'd like to use the find () function, but it throws the error:
Code:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Visit extends Model
{
protected $table = 'ft_visit';
protected $primaryKey = ['sk_time', 'sk_region', 'sk_device'];
protected $fillable = [
'sk_time', 'sk_region', 'sk_device', 'ds_page',
];
public $timestamps = false;
public function time()
{
return $this->belongsTo(Time::class, 'sk_time');
}
}
Error:
(1/1) ErrorException
mb_strpos() expects parameter 1 to be string, array given

You can try the solution presented in this article Solved: Eloquent doesn’t support composite primary keys.
Adding the setKeysForSaveQuery method below on your model, and removing the $primaryKey attribute, you might be able to add this otherwise not supported functionality to your Eloquent model.
<?php
use Illuminate\Database\Eloquent\Builder;
class Visit extends Model {
public $incrementing = false;
protected function setKeysForSaveQuery(Builder $query)
{
$query
->where('sk_time', '=', $this->getAttribute('sk_time'))
->where('sk_region', '=', $this->getAttribute('sk_region'));
->where('sk_device', '=', $this->getAttribute('sk_device'));
return $query;
}
}
EDIT: As noted by #Devon this might affect Eloquent in other ways and should be tested thoroughly before use. However, this should give you some clearance on the way to solve it, should you not be in a position where you can (preferably) restructure the application or data.

Eloquent does not support composite keys. The best thing to do in this scenario to ensure Eloquent compatibility is to convert your existing primary composite key to a unique composite key and add an autoincrement primary key (id) for Eloquent to use.

Unfortunately you can't. Laravel and lumen (using Eloquent) do not support composite keys.

Related

laravel eloquent migrations

In laravel eloquent relationship, is it still necessary to make migration even though there's an existing database? beginners here.
I create a one-to-one eloquent relationship inside my model to get the specific column from another table's record and fetch to the datatable, but it did not work.
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Directorystatus extends Model
{
use HasFactory;
protected $table = 'user_status';
protected $fillable = ['status_id' , 'status_xtitle'];
public function userbasic() {
return $this->belongsTo(directorybasic::class,'user_xusern','status_xuser');
}
}
class Directoryuser extends Model
{
use HasFactory;
protected $table = 'user_basic';
protected $primaryKey = 'user_id';
protected $fillable = ['user_id' , 'user_xusern' , 'user_xfirtname' ,'user_xmiddlename','user_xlastname'];
public function userstatus() {
return $this->hasOne(directorystatus::class,'user_xusern','status_xuser');
}
}
No. Migrations are not necessary. Defining relationships on both sides is also not necessary, if you don't need them both. (You can have only belongsTo, without having hasOne or hasMany in the opposite model.)
First, make sure you are using the right object (Directorystatus::class / Directoryuser:class - I see they're not capitalized in your code). The next param is the foreign key, meaning the column which points to a model's primary key. The third param is optional and is used only if the primary key is not id.
For example if you have a column status_xuser in the table user_status, which contains a user_id from user_basic table, you should define it like this:
public function userbasic() {
return $this->belongsTo(Directoryuser::class,'status_xuser','user_id');
}
And in order to use this relationship, when you retrieve a model from the db, for example, you should call on it the same way your relationship function is named.
$status = Directorystatus::find(1);
$user = $status->userbasic();
I would also suggest you name your classes in camelCase, because it's the accepted practice (in Laravel especially).

How the save autoincrement values using laravel eloquent

I am trying to save data into a database using Laravel eloquent models. However, the primary key is an auto-increment integer and it's throwing an error:
SQLSTATE[HY000]: General error: 1364 Field 'property_valuation_id' doesn't have a default value.
Any help on how this can be solved.
Here is the controller:
public function index(Request $request)
{
$property_valuation = new PropertValuation();
$property_valuation->property_valuation_id="";
$property_valuation->integer('property_valuation_id')->default(1);
$property_valuation->district_id = $request->input('district');
$property_valuation->propertyneighbourhood = $request->input('neighborhood');
$property_valuation->propertystreet = $request->input('street');
$property_valuation->numberofbedrooms =$request->input('bedrooms');
$property_valuation->currency=$request->input('currency');
$property_valuation->monthlyrent=$request->input('rent');
$property_valuation->save();
}
And here the model:
class PropertValuation extends Model
{
protected $table = 'property_valuation';
public $primaryKey = 'property_valuation_id';
public $timestamps = false;
}
You're overwriting Laravels default behaviour with this lines
$property_valuation->property_valuation_id="";
$property_valuation->integer('property_valuation_id')->default(1);
Remove it and it should be ignored within the SQL query and the auto-increment value should be set.
First of all you should use
$table->bigIncrements('property_valuation_id');
or
$table->increments('property_valuation_id');
in your migration file and then run in console php artisan migration:fresh to update your db structure. Aslo your why you are using custom field increment name instead of default 'id' ?
Second you must do is to set value for fillable variable in your Model. No need to include autoincrement field in this array.
protected $fillable = ['neighborhood', 'district',.....];
And the last thing. It is unnessessary to set all values for model from request, laravel do it itself. So your controller store method might be
public function store(Request $request)
{
PropertValuation::create($request->all());
return redirect()->back();
}
Much cleaner, yeah? :)

Laravel - Illegal offset type when accessing property on OneToMany relationship

I'm learning how to use laravel and relationships. I'm having trouble accessing data from a hasMany relationship, I understand this might be a silly question. This might be a duplicate question, but I didn't find any specific answer like this.
I have two models, a salesman table and a prices table table. One salesman has many prices tables, so it's like this:
On Salesman model
<?php
namespace App\Pedidos;
use Illuminate\Database\Eloquent\Model;
class Vendedores extends Model
{
protected $connection = 'Pedidos';
protected $primaryKey = 'CD_VENDEDOR';
public function TabelaDePreco() {
return $this->hasMany('\App\Pedidos\TabelaDePreco', 'CD_VENDEDOR', 'CD_VENDEDOR');
}
}
On the prices table model
<?php
namespace App\Pedidos;
use Illuminate\Database\Eloquent\Model;
class TabelaDePreco extends Model
{
protected $connection = 'Pedidos';
protected $primaryKey = ['CD_VENDEDOR', 'CD_PRODUTO', 'CD_ESTADO'];
public function Vendedores() {
return $this->belongsTo('\App\Pedidos\Vendedores', 'CD_VENDEDOR', 'CD_VENDEDOR');
}
}
On the Controller
public function index()
{
$vendedores = Vendedores::all();
return view('pedidos.tabeladepreco.index')
->with('title', 'Tabela de preços')
->with('vendedores', $vendedores);
}
On the view, this will return TabelaDePreco model
#foreach($vendedores as $vendedor)
#foreach ($vendedor->TabelaDePreco as $tabela)
{{ dd($tabela) }}
#endforeach
Here is a print from the code above:
TabelaDePreco model
As you can see, data is loaded on the $tabela variable.
If I try to print, on the view, {{ $tabela->NR_LIMITE1 }}, I get the illegal offset type error. How do I access this attribute since data is loaded when using dd()? I've tried $tabela['NR_LIMITE1'] but with the same error.
What am I doing wrong?
Best regards.
EDIT:
As pointed by Jonas on the comments, Laravel won't support relationships when one of the tables has composite keys. Back to migrations.
You need to eager load your relation:
$vendedores = Vendedores::with('TabelaDePreco')->all();
return view('pedidos.tabeladepreco.index')
->with('title', 'Tabela de preços')
->with('vendedores', $vendedores);
It may also happen that $vendedor->TabelaDePreco is not defined if there is not TabelaDePreco associated with the $vendedor. Try adding a isset(). Also thing about pagination if you have many entries.

Laravel Eloquent, filtering from pivot table column

I need to filter the active clients from a route using Eloquent.
I'm working with a third party database that I can't modify. In my project I have two models: Cliente(client) and Ruta(route), which have a many to many relationship, so I added the belongsToMany relationship in my models.
The only column I'm interested from the pivot table is called DESACTIV, which tells me if a Client is deactivated for a Route.
Ruta model:
class Ruta extends Model
{
protected $connection = 'mysql2';
protected $table = 'truta';
protected $primaryKey = 'CODIRUTA';
public function clientes(){
return $this->belongsToMany(Cliente::class, 'tcpcarut', 'CODIRUTA', 'CODICLIE')->withPivot('DESACTIV');
}
}
Cliente model:
class Cliente extends Model
{
protected $connection = 'mysql2';
protected $table = 'tcpca';
protected $primaryKey = 'CODICLIE';
public function rutas(){
return $this->belongsToMany(Ruta::class, 'tcpcarut', 'CODICLIE', 'CODIRUTA')->withPivot('DESACTIV');
}
}
What I need is to get the active (or non deactivated) Clients given a specific Route.
I have done it on my controller like this:
$miRuta = Ruta::where('CODIRUTA','=',$ruta)->first();
$clientes = array();
foreach ($miRuta->clientes as $cliente){
if ($cliente->DESACTIV == 0){
array_push($clientes, $cliente->NOMBCLIE);
echo end($clientes)."<br/>";
}
}
And it works fine, but I don't think it's elegant. I know this can be archieved through Eloquent, I'm just to noob at it and don't know how to do it.
Maybe I could add the filter on the clientes method on my Ruta model, so it would return only the active Clients.
Or maybe It could be best to add a method on the Cliente model, like isDeactivated
I know it sounds like I know what I'm talking about but I need someone to hold my hand on this, I'm just too noob with Eloquent :/. Examples would be much appreciated.
You can use the wherePivot method to constrain a relationship based on values in the pivot table. You just need to add the following to your Ruta model
public function desactivClientes() {
return $this->clientes()->wherePivot('DESACTIV', 0);
}
And then you just have to modify the rest of your code a bit to use the constrained relationship. I'm also adding a null check because if this function does return null, which can happen if your table doesn't have a record where CODIRUTA matches whatever is in $ruta, then it will likely throw a fatal error trying to call a method on a non-object.
$miRuta = Ruta::where('CODIRUTA','=',$ruta)->first();
$clientes = array();
if ($miRuta !== null) {
$clientes = $miRuta->desactivClientes()->pluck('NOMBCLIE');
}

laravel Eloquent ORM custom field name

I am trying to get record from a products table with the field productsid by using Eloquent and using the following code. My model name is Products_description.
In my route file.
Route::get('product/{productsid}','productscontroller#show');
In my controller file
public function show($productid)
{
$Products = Products_description::find($productid);
return $Products;
}
But it showing me the error that Unknown column 'products_description.id'. Looks like Eloquent try to get record through the field name id by default like it do with the table names. But how to get records through a table field other than id. e.g. if it is productid, what we would do/use?
In your model, declare your $primaryKey
class Products_description {
protected $primaryKey = "productid";
//
}
This way you can use ::find or firstOrFail and not where.
like this
$Products = Products_description::where('pruductid',$productid)->first();
or you can try this
Products_description model
class Products_description extends Eloquent {
protected $primaryKey = 'productid';
}
I am assuming your need is to query your table for a field other than the primary key . You can use:
Products_description::where('productid',$productId)->first()
If you are speaking about foreign keys, then you should define them in the model like so :
return $this->hasOne('App\Phone', 'foreign_key');
Here is the relevant documentation :
https://laravel.com/docs/5.1/eloquent-relationships#one-to-one

Resources