How to update all data by repository (laravel 5.3)? - php

My repository is like this :
<?php
namespace App\Repositories;
use App\Models\UsersBank;
use Illuminate\Contracts\Container\Container;
use Rinvex\Repository\Repositories\EloquentRepository;
class UserBankRepository extends EloquentRepository
{
public function __construct(Container $container)
{
$this->setContainer($container)
->setModel(UsersBank::class)
->setRepositoryId('rinvex.repository.uniqueid');
}
}
My model is like this :
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class UsersBank extends Model
{
protected $fillable = ['user_id','bank_id','status','account_name','account_number'];
}
My service is like this :
public function setMain($id)
{
$param['status'] = 1;
$this->user_bank_repository->update($id, $param);
}
When setMain function executed, It will update field status = 1 by the id
I want to update status = 1 to all record. So, Not by id
How can I do it?
Note :
Update which I mean here is the update via the repository. Not update through a model

Look into the source code of update() method of the package and you'll see it's impossible, so you'll need to use foreach() and create a bunch of queries.
My opinion is this and similar packages are useless since they are still using Eloquent and do not provide any handful functionality. I'd recommend you to use Eloquent directly to update all rows with just one query:
Model::query()->update(['status' => 1]);

Related

How to pass type and id to laravel polymorphic relation

I have a navigation model that can have many items associated with it:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use JetBrains\PhpStorm\ArrayShape;
use Laravel\Scout\Searchable;
class Navigation extends Model
{
use HasFactory;
use Searchable;
protected $guarded = [];
public function navigation_items(): HasMany
{
return $this->hasMany(NavigationItem::class);
}
}
The navigation item model looks like this
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class NavigationItem extends Model
{
use HasFactory;
protected $guarded = [];
public function navigation(): BelongsTo
{
return $this->belongsTo(Navigation::class);
}
public function navigatable(): MorphTo
{
return $this->morphTo();
}
}
Now an item can either be of type Page or Blog, in this case the Page model looks like this:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use JetBrains\PhpStorm\ArrayShape;
use Laravel\Scout\Searchable;
class Page extends Model
{
protected $guarded = [];
public function navigatable(): MorphOne
{
return $this->morphOne(NavigationItem::class, 'navigatable');
}
}
When I try to save a navigation model and associate it with a item, the following error appears:
SQLSTATE[HY000]: General error: 1364 Field 'navigatable_type' doesn't have a default value
I save the model like this:
foreach ($this->selected as $id) {
$this->navigation->navigation_items()->create([
'navigation_id' => $this->navigation->id,
]);
Where $this->selected is the navigation id, it should automatically get the correct navigatable_type and navigatable_id, but this doesn't seem to be working.
passing in the type and id manually works, but this kinda defeats the point of a polymorphic relationship.
any ideas?
On NavigationItem model, since you defined polymorphic relation as 'navigatable' it is expected that NavigationItem model's table contains navigatable_type and navigatable_id. First please ensure this checks out.
Creating records through relation's base function is not a valid method. It is not clear what you are trying to achieve there but when you want to set relation there is two standard way of achieving it:
1- Associate
When a relation is defined as belongsTo, you may use associate() function. Like so:
$account = Account::find(10);
$user->account()->associate($account);
2- Attach
Attach is used when relation is defined belongsToMany (pivot). It allows you to attach multiple records to a model instance/record.
$user = User::find(1);
$user->roles()->attach($roleId);
So if you want to set a 'navigatable' to a Navigation instance, you may:
$somePageInstance=Page::find(55);
$nagivation->navigatable()->associate($somePageInstance)
$nagivation->save();//remember to save, otherwise it won't be

Specify DB table in laravel query

Im new to laravel, i am trying to query a specific table in my DB. I only have 1 data table and the standard user auth tables. I am getting a error: BadMethodCallException
Call to undefined method App\Figures::table().
Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Figures extends Model
{
}
controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Figures;
class figuresController extends Controller
public function figurespag2() {
$dummyDetails = Figures::table('figures')->where('name', 'batman');
return view ( 'pagination2.index' )->withUsers($dummyDetails);
}
route
Route::get ( '/pagination2', 'figuresController#figurespag2' );
I know it's going to be something obvious, but I am new to this.
this is wrong
$dummyDetails = Figures::table('figures')->where('name', 'batman');
Method 1---------- laravel eloquent
Model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Figures extends Model
{
protected $table = 'figures';
}
Controller
$dummyDetails = Figures::where('name', 'batman')->get();
and
Method 2 ---------- laravel Query Builder
$dummyDetails = \DB::table('figures')->where('name', 'batman')->get();
Use this you not need to define table name
public function figurespag2() {
$dummyDetails = Figures::where('name', 'batman')->get();
return view ( 'pagination2.index' )->withUsers($dummyDetails);
}
First you may need to know laravel model rules.
If you create a table name like "figures" (plural) you need to create its model by Figure (singular).
if you create a table other then this rule then you have to mentioned table name in model like this.
protected $table = "table_name";
you can access table with where condition in controller like this.
public function figurespag2() {
$dummyDetails = Figure::where('name', 'batman')->get();
return view ( 'pagination2.index' )->withUsers($dummyDetails);
}
Hope this may help you.

How to Inverse the Eloquent Has One and Has Many Through (laravel 5.8)?

I have three relational table attached below.
https://drive.google.com/file/d/1q1kdURIwFXxHb2MgdRyBkE1e3DMug7r-/view?usp=sharing
I have also three separate models where defined relation among all of my table's.I can read the City Model's information from Country model using hasManyThrough() relation But cannot read the Country information from City model. I have tried to retrieve City model's using ``hasManyThrough``` but didn't get result (attached as commented country method ). Please read my model and it's relational method here..
Is there someone to help me for getting City model's information using Eloquent method hasManyThrough / hasManyThrough or using inverse of hasManyThrough / hasManyThrough ?
01.
<?php
namespace App\Hrm;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Country extends Model
{
//use SoftDeletes;
protected $fillable = ['name','description','status'];
public function districts(){
return $this->hasMany(District::class);
}
public function cities(){
return $this->hasManyThrough(City::class,District::class);
}
}
02.
<?php
namespace App\Hrm;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class District extends Model
{
//use SoftDeletes;
protected $fillable = ['country_id','name','description','status'];
public function country(){
return $this->belongsTo(Country::class);
}
public function cities(){
return $this->hasMany(City::class);
}
}
3.
namespace App\Hrm;
use App\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class City extends Model
{
//use SoftDeletes;
protected $fillable = ['district_id','name','description','status'];
public function district(){
return $this->belongsTo(District::class);
}
// public function country(){
// return $this->hasOneThrough(Country::class, District::class);
// }
Doesn't look like there is a native way to define the inverse of a "hasManyThrough" relationship yet in Laravel. There have been a few issues opened on github to request it, but they were closed.
You could use the staudenmeir/belongs-to-through package if you don't mind installing a third-party package for this functionality. Then you should be able to define a belongsToThrough relationship like this:
class City extends Model
{
use \Znck\Eloquent\Traits\BelongsToThrough;
public function country() {
return $this->belongsToThrough(Country::class, District::class);
}
}
Why can't use parent method?
$city = City::find(1);
$country = $city->district->country();
i just had a similar situation i was able to accomplish a belongsToThrough with hasOneThrough
public function country()
{
return $this->hasOneThrough(
Country::class, // model we are trying to get
District::class, // model we have an _id to
'id', // WHERE `district`.`id` = `city`.`district_id`
'id', // `countries`.`id`
'district_id', // local column relation to our through class
'country_id' // `district`.`country_id`
);
}
what this should generate is
SELECT * FROM `countries`
INNER JOIN `districts`
ON `districts`.`country_id` = `countries`.`id`
WHERE `districts`.`id` = ?
-- ? == city.district_id
Database structure:
City:
id: increments
district_id: integer
...
Country:
id: increments
...
District:
id: increments
country_id: integer
...
we can then do $city->country
note: i have not fully tested this but with the testing that i have done it 'works'
Edit: i originally thought that i needed to leave the localKey
parameter null otherwise the relation wont work. it turns out i didnt
fully understand what that column was doing and that was wrong. That
key is the local column that relates to our through column (unless i
still have more to learn/figure out), when left the value as null, it
would use the local id column which a. is the wrong value, b. can also
be out of range (which is how i discovered it was using the wrong
value)
in my testing i only had two rows, both with the same relations. what
i didnt realize though was that on the "through table" both row 1 and
2 and the same related (relation where are trying to reach) so i didnt
notice the issue right away. hopefully now its all working

Laravel extend or use Traits dynamically

It is possible to extend or use different class during run time?
Example:
Let say we have a model called Player (Our A -model)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Player extends Model{
}
And we have 2 other models (B and C models)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
protected $connection= 'db_b';
class PlayerInfoB extends Model{
function getName(){
return $this->name;
}
}
Our C model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
protected $connection= 'db_c';
class PlayerInfoC extends Model{
function getName(){
return $this->name_g;
}
}
How Model A (Player) can extend Model B or C during run time based on configuration or other data
Why I need this.
I have a 2 or more different tables, this tables columns have different names, so for example:
Table 1 - name
Table 2 - name_g
Table 3 - name_full
So I need a wrapper that I can always call getName(), without checking what table is used now.
$player = Player::get();
echo $player->getName();
If something is not clear, please comment and I will update my question.
Update based on madalin-ivascu answer can be done this way?
class Player extends Model{
protected $model;
public function __construct(){
$this->setModel();
parent::__construct();
}
protected function setModel(){
$this->model = $this->column_model_name
}
function getAttributeName(){
return $this->model->getName();
}
}
It is not possible to compose a calss at runtime without using eval or or dirty hacks. You have to reconsider your class design, because it's very unlikely that you need to do that with a good design.
What you can do is changing table and db connection at runtime on the model instance using methods setTable and on:
Player::on('db_b')->setTable('player_info_b')->find($id);
Another approach (preferable) would be defining the model PlayerInfoC and PlayerInfoB that extend your Player model, and then based on your condition you instantiate the class B or C when needed.
In your code your script must have a state that you check in order to know when to use the correct model?
In this case why not use a parameter in get name?
class Player extends Model{
function getName($field){
return isset($this->{$field}) ? $this->{$field} : null;
}
}
If you do this a lot then use magic methods:
class Player extends Model{
function __get($key){
return isset($this->{$field}) ? $this->{$field} : null;
}
}
...
echo $myModelInstance->{$field};
http://php.net/manual/en/language.oop5.overloading.php#object.get
In Laravel when you have pulled data back via a collection method it does this magic method anyway since all attributes are stored in a nested object called attributes so the __set() and __get() looks something like this:
function __get($key){
return isset($this->attributes->{$key}) ? $this->attributes->{$key} : null;
}
function __set($key, $value){
return $this->attributes->{$key} = $value;
}
The latter with attributes sub set is advised, this way you prevent data conflicts with database column names returned vs names you have already used in a model.
This way you only have to manage one attribute name as a reserved name in every model you create and not worry amount the hundreds of var names you use overwriting another in a model or extension of a model.
use that model value to call the function
$player = Player::get();
echo Player::getName($player->id,'PlayerInfoC');
in the Player model you simply call
public static function getName($id,$class)
return $class::where('player_id',$id)->getName();//each class will have the function
}
ps: you will need to do some validation to test if the class exist with that name
another option will be to create relationships between the models

Laravel 5 mutators only work when I create a record and not when I update a record

Hi I have created a mutator to only store digits on my phone numbers. Here is my code in my Profile Model.
public function setPhoneAttribute($phone)
{
$this->attributes['phone'] = preg_replace("/[^0-9]/","",$phone);
}
This works when I create a new record, but if I update the record it does not work. My question is how do I execute the Mutator on both create and update?
Here is how I update and create in my controller:
namespace App\Http\Controllers;
use App\Http\Requests;
use App\Http\Requests\ProfileRequest;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Auth;
use App\Profile;
class ProfileController extends Controller {
public function create(ProfileRequest $request)
{
// Check if the user does not have a profile yet
if(!Auth::user()->profile()->first()){
// Save to database
$saveToDatabase = Auth::user()->profile()->create($request->all());
return $saveToDatabase;
}
}
public function update(Profile $profile, ProfileRequest $request)
{
// Save to database
$saveToDatabase = Auth::user()->profile()->update($request->all());
return $saveToDatabase;
}
}
Here's what's happening:
Auth::user()->profile()->create($request->all()) calls the create method on your relationship (HasOneOrMany). This method then creates a new instance of the related model. This is important because obviously attribute mutators are only used when the record is created through the model.
However the relationship object doesn't have any update method. (It also wouldn't make sense to have one...). So what's happening instead is, when you do Auth::user()->profile()->update($request->all()). The update call get's proxied off to a query builder instance (that matches the relationship). This results in something like this being executed:
UPDATE profiles SET foo = 'bar' WHERE [relationship conditions]
It doesn't use the model at all. Therefore the mutator doesn't work.
Instead you have to call the update method on the actual related model. You can access it by just calling the relation as a property like this:
$saveToDatabase = Auth::user()->profile->update($request->all());
// ^^
// no parentheses
If the Profile model is injected correctly you actually might also just use that though:
public function update(Profile $profile, ProfileRequest $request)
{
// Save to database
$saveToDatabase = $profile->update($request->all());
return $saveToDatabase;
}
Using this code instead of your code
$saveToDatabase = Auth::user()->profile->update($request->all());

Categories