Laravel/Eloquent collitions with model traits - php

I am using laravel 5.8 for my project, and i am getting the error Bad call Call to undefined method Illuminate\Database\Eloquent\Builder::withSum() because I removed LaravelSubQueryTrait in my traits. When i re-add LaravelSubQueryTrait, my project does not run, I am getting this error Trait method newBaseQueryBuilder has not been applied, because there are collisions with other trait methods on App\Traits\TestModelTrait. Upgrading to laravel 8.x is not an option at this point and I don't quite understand what I am doing wrong. Any tips/advise/ resources to read will be highly appreciated to help solve my problem. Thanks
My TestmodelTrait is as below :
use Alexmg86\LaravelSubQuery\Traits\LaravelSubQueryTrait;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str;
use Watson\Rememberable\Rememberable;
trait MedyqModelTrait
{
protected static $skipUuid = false;
use MedyqTrait, SoftDeletes, Rememberable, LaravelSubQueryTrait;
protected static function boot()
{
parent::boot();
self::creating(function ($record) {
if (!self::$skipUuid) {
$record->{'uuid'} = (string)Str::orderedUuid();
}
if (auth()->check()) {
$record->{'created_by'} = auth()->id();
$record->{'updated_by'} = auth()->id();
}
});
self::updating(function ($record) {
if (auth()->check()) {
$record->{'updated_by'} = auth()->id();
}
});
self::updated(function ($record) {
$record->flushCache();
});
self::deleted(function ($record) {
if (auth()->check()) {
$record->{'deleted_by'} = auth()->id();
$record->save();
}
});
self::restored(function ($record) {
if (auth()->check()) {
$record->{'restored_by'} = auth()->id();
$record->{'restored_at'} = Carbon::now();
$record->save();
}
});
}
/**
* Get the route key for the model.
*
* #return string
*/
public function getRouteKeyName()
{
return 'uuid';
}
public function scopeAlive($query)
{
$query->where("status", config("constants.status.alive"));
}
}
My TestTrait looks like this :
use App\Entities\User;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
trait MedyqTrait
{
public static function getTableName()
{
return with(new static)->getTable();
}
public function scopeActive($query)
{
$query->where("status", config("constants.status.active"));
}
public function scopeInActive($query)
{
$query->where("status", config("constants.status.inactive"));
}
/**
* Mass (bulk) insert for Postgres Laravel 5
*
* insert([
* ['id'=>1,'value'=>10],
* ['id'=>2,'value'=>60]
* ]);
*
*
* #param array $rows
* #param null $table
* #param bool $skipUUid
* #param bool $timestamps
* #param bool $authorstamp
* #return bool
* #throws Exception
*/
public function bulkInsert(array $rows, $table = null, $skipUUid = false, $timestamps = true, $authorstamp = true)
{
$return_values = array_filter($rows, 'is_array');
if (!count($return_values) > 0) {
throw new Exception("This function expects a multidimensional associative array");
}
if (is_null($table)) {
$table = DB::getTablePrefix() . $this->getTable();
}
$rows = array_map(function ($item) use ($skipUUid, $timestamps, $authorstamp) {
$authenticated = auth()->check();
$authorId = auth()->id();
$time = Carbon::now();
if (!$skipUUid) {
$item['uuid'] = Str::orderedUuid();
}
if ($timestamps && !key_exists('created_by', $item) && $authenticated && $authorstamp) {
$item['created_by'] = $authorId;
}
if ($timestamps && !key_exists('updated_by', $item) && $authenticated && $authorstamp) {
$item['updated_by'] = $authorId;
}
if ($timestamps && !key_exists('created_at', $item)) {
$item['created_at'] = $time;
}
if ($timestamps && !key_exists('updated_at', $item)) {
$item['updated_at'] = $time;
}
return $item;
}, $rows);
$first = reset($rows);
$columns = implode(',',
array_map(function ($value) {
return "$value";
}, array_keys($first))
);
$values = implode(',', array_map(function ($row) {
return '(' . implode(',',
array_map(function ($value) {
return "'" . str_replace("'", "''", $value) . "'";
}, $row)
) . ')';
}, $rows)
);
$sql = "INSERT INTO {$table}({$columns}) VALUES {$values}";
return DB::statement($sql);
}
public function deletedBy()
{
return $this->belongsTo(User::class, "deleted_by", "id");
}
}

Guess you have problem with the syntax.
$invoice = Invoice::where('id', $invoice->id)
->with('items')
->withSum('items', 'total_amount')
->withSum('items', 'amount_paid')
->first();
withSum is probably available only since Laravel version 8.x, before that I think only withCount was available. But if you still want to use withSum in earlier version you can define a macro'

You could also try use LaravelSubQueryTrait trait directly in the model/models.
use Alexmg86\LaravelSubQuery\Traits\LaravelSubQueryTrait;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model
{
use LaravelSubQueryTrait;
Reference https://github.com/Alexmg86/laravel-sub-query

Related

how to get record from database within multiple conditions of between max and min value

I have a table that contains products, and I want to automate pricing.
I've tried to create a table called price.
The price table is structured like so :
max_height
max_width
max_long
max_weight
min_height
min_width
min_long
min_weight
price
I want to retreive the price depending on the ( height - width - long - weight ) of product
I've tried this way :
From the controller :
<?php
namespace App\Http\Controllers;
use App\Models\Coli;
use App\Models\Pricing;
use Illuminate\Pipeline\Pipeline;
class ColiPriceController extends Controller
{
public static $data = [];
public static function price($id){
ColiPriceController::setData($id);
$price = app(Pipeline::class)
->send(Pricing::query())
->through([
\App\Filters\Pricing\MaxHeightPriceFilter::class,
\App\Filters\Pricing\MinHeightPriceFilter::class,
\App\Filters\Pricing\MaxLongPriceFilter::class,
\App\Filters\Pricing\MinLongPriceFilter::class,
\App\Filters\Pricing\MaxWidthPriceFilter::class,
\App\Filters\Pricing\MinwidthPriceFilter::class,
\App\Filters\Pricing\MaxWeightPriceFilter::class,
\App\Filters\Pricing\MinWeightPriceFilter::class,
])
->thenReturn()
->first();
}
protected static function setData($id)
{
$coli = Coli::find($id);
$coli->height = ($coli->height) ? intval($coli->height) : 0;
$coli->width = ($coli->width) ? intval($coli->width) : 0;
$coli->longeur = ($coli->longeur) ? intval($coli->longeur) : 0;
$coli->wieght = ($coli->wieght) ? intval($coli->wieght) : 0;
$data = [
'height' => $coli->height,
'width' => $coli->width,
'long' => $coli->longeur,
'weight' => $coli->wieght,
];
return ColiPriceController::$data = $data;
}
}
From MaxHeightFilter :
<?php
namespace App\Filters\Pricing;
use Closure;
class MaxHeightPriceFilter extends PriceFilter
{
public $column = "max_height";
public $dataColumn = "height";
public $operator = "<=";
public function handle($request, Closure $next)
{
return $this->filter($request, $next);
}
}
From PriceFilter :
<?php
namespace App\Filters\Pricing;
use Illuminate\Database\Eloquent\Builder;
use App\Http\Controllers\ColiPriceController;
class PriceFilter
{
public $column = "max_weight";
public $dataColumn = "weight";
public $operator = "<=";
protected function filter($request, $next)
{
if($this->chequePriceToContinue($request)){
return $next(static::removeWhere($request, $this->column));
}
return $next($request);
// return $next($request->where($this->column, $this->operator, ':'.ColiPriceController::$data[$this->dataColumn]));
}
public function chequePriceToContinue($request){
$price = $request->where($this->column, $this->operator, ColiPriceController::$data[$this->dataColumn] )->get();
if(is_array($price)){
return true;
}
return false;
}
/**
* #param Builder $builder
* #param $whereColumn
* #return Builder
*/
public static function removeWhere(Builder $builder, $whereColumn)
{
$bindings = $builder->getQuery()->bindings['where'];
$wheres = $builder->getQuery()->wheres;
$whereKey = false;
foreach ($wheres as $key => $where) {
if ($where['column'] == $whereColumn) {
$whereKey = $key;
break;
}
}
if ($whereKey !== false) {
unset($bindings[$whereKey]);
unset($wheres[$whereKey]);
}
$builder->getQuery()->wheres = $wheres;
$builder->getQuery()->bindings['where'] = $bindings;
return $builder;
}
}
Ok, based on your info, I think your solution should look something like this:
First, make sure you have a Price model if you don't have it already.
Second, build your query in your controller with your model like so:
//ColiPriceController.php
function findPrices(Request $request) {
//If id is provided, take coli from db
if($request->has('id')) {
//FindOrFail returns 404 if not found
$coli = Coli::findOrFail($request->id);
}
//Start query.
$query = Price::query();
//Set values based on coli if set OR by request parameters
$height = $coli->height ?? $request->height;
$width = $coli->width ?? $request->width;
$long = $coli->long ?? $request->long;
$weight = $coli->weight ?? $request->weight;
//If the initialized height/width/long/weight is greater than 0, add the where clauses to query
if($height > 0) {
$query
->where('max_height', '>', $height)
->where('min_height', '<', $height);
}
if($width > 0) {
$query
->where('max_width', '>', $width)
->where('min_width', '<', $width);
}
if($long > 0) {
$query
->where('max_long', '>', $long)
->where('min_long', '<', $long);
}
if($weight > 0) {
$query
->where('max_weight', '>', $weight)
->where('min_weight', '<', $weight);
}
//I'm using get() and not first() because im not sure if you can guarantee you only find 1 result and not multiple.
//If you are confident you only get 1 result per query, feel free to make it first()
return $query->get();
}
So here I only add the where clauses if you initialized the respective variable. This is not mandatory but seemed logical from my point of view. The findPrices function should be called by a route. You can pass id, height, width,long, weight as request parameters. If id is set and the coli is found, the other parameters are ignored.
I hope it helps, any feedback is welcome

Laravel Query Search Function

This is my controller:
public function index($mid,$payload){
$search = $payload['search'];
$users = DB::select('SELECT a.id, a.alternate_id, a.setujuterma, a.mykad, a.nama, a.email, a.notel, a.etunai,
b.ranktitle, c.ranktitle AS appointed_rank, d.nama as hirarki, e.alternate_id as placement,
e.nama as leadername, a.akses, a.suspendreason, a.regstamp,
a.matagajet, f.display as hirarkidisplay, IF(a.mykadverify = "3","1","0") as mykadverifydecode
FROM pengguna as a
LEFT JOIN penggunarank b ON a.effective_rank = b.id
LEFT JOIN penggunarank c ON a.appointed_rank = c.id
LEFT JOIN hirarki d ON a.userrank = d.id
LEFT JOIN pengguna e ON a.placement = e.id
LEFT JOIN hirarkimid f ON a.userrank = f.hirarki AND a.mid = f.mid
WHERE a.mid ='. $mid .' AND a.akses != -1'
);
$sortUser = collect($users)->sortByDesc('alternate_id')->toArray();
$collection = collect($sortUser);
$count = count($users);
// SEARCH BOX
if ($search) {
$collection->where(function ($q) use ($search) {
$q->where("alternate_id","LIKE","%{$search}%")
->orWhere("nama","LIKE","%{$search}%")
->orWhere("mykad","LIKE","%{$search}%")
->orWhere("notel","LIKE","%{$search}%")
->orWhere("email","LIKE","%{$search}%");
});
}
return [
$user,
$count
];
}
So,
$users return an array.
$collection return collection
for the search box, if I use $users, I get error
"Call to a member function where() on Array"
and if I use $collection, I get
message: "explode() expects parameter 2 to be string, object given", exception: "ErrorException",…}
Any help would be greatly appreciated. Thanks.
public function search(Request $payload){
$search = $payload['search'];
if($search == "")
{
$users = Payee::whereNotNull('payee_name')->take(10)->get();
}
else
{
$users = Payee::whereNotNull('payee_name')
->where(function ($q) use ($search) {
$q->where("payee_name","LIKE","%$search%")
->orWhere("payee_nick_name","LIKE","%$search%");
})->take(10)->get();
}
return [
$users,
];
}
I found an answer to my question. All I need is to change the query into eloquent model class. There is no other way if I want to use the where() function for my search. First I create model User.php:
<?php
namespace App;
use App\WithdrawEcash;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Propaganistas\LaravelPhone\PhoneNumber;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens, Notifiable, HasFactory;
protected $table = 'pengguna';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $guarded = ['id'];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
// user registered by
public function userRegby()
{
return $this->belongsTo(User::class, 'regby');
}
// user leader
public function userPlacement()
{
return $this->belongsTo(User::class, 'placement');
}
public function penggunaRank()
{
return $this->belongsTo(PenggunaRank::class, 'effective_rank');
}
public function appointedRankUser()
{
return $this->belongsTo(PenggunaRank::class, 'appointed_rank');
}
public function penyatabonus()
{
return $this->belongsTo(User::class, 'id', 'pengguna');
}
//Hirarkimid userrank
public function userHirarki()
{
return $this->belongsTo(Hirarkimid::class, 'userrank', 'hirarki');
}
public function userhirarchy()
{
return $this->belongsTo(Hierarchy::class, 'userrank')->select('id', 'nama');
}
public function systemHirarki()
{
return $this->belongsTo(Hierarchy::class, 'userrank');
}
// user order
public function userOrders()
{
return $this->hasMany(Order::class, 'pengguna');
}
// user order for registration report
public function userOrder()
{
return $this->hasOne(Order::class, 'pengguna');
}
public function hierarchy()
{
$hirarki = $this->belongsTo(Hirarkimid::class, 'userrank', 'hirarki')
->select('hirarki', 'display', 'shownilaibelian', 'show_harga_ketika_pesanan')
->where('mid', auth()->user()->mid);
if ($hirarki) {
return $hirarki;
} else {
return $this->belongsTo(Hierarchy::class, 'userrank')->select('id', 'nama');
}
}
public function myCartLists()
{
return $this->hasMany(AddToCart::class, 'user_id');
}
public function bonusStatement()
{
return $this->hasMany(PenyataBonus::class, 'pengguna');
}
public function currentBonusStatement()
{
return $this->hasMany(PenyataBulanSemasa::class, 'pengguna');
}
public function withdrawEcash()
{
return $this->hasMany(WithdrawEcash::class, 'pengguna');
}
public function fileupload()
{
return $this->morphOne(FileUpload::class, 'file_upload');
}
public function fileuploads()
{
return $this->morphMany(FileUpload::class, 'file_upload');
}
public function voucherdetail()
{
return $this->hasMany(Voucherdetail::class, 'pengguna');
}
public function countryCode()
{
return $this->hasOne(Negara::class, 'nama', 'negara')->value('kod');
}
public function setNotelAttribute($value)
{
if (!is_null($value)) {
$country_code = $this->countryCode() != '' ? $this->countryCode() : 'MY';
$this->attributes['notel'] = PhoneNumber::make($value, $country_code)
->formatForMobileDialingInCountry($country_code);
} else
$this->attributes['notel'] = $value;
}
public function setNotelcsAttribute($value)
{
if (!is_null($value)) {
$country_code = $this->countryCode() != '' ? $this->countryCode() : 'MY';
$this->attributes['notelcs'] = PhoneNumber::make($value, $country_code)
->formatForMobileDialingInCountry($country_code);
} else
$this->attributes['notelcs'] = $value;
}
}
And in my controller I simply call the user model:
$user = User::query()->select('id', 'alternate_id', 'setujuterma', 'mykad', 'nama', 'email', 'notel', 'etunai',
'effective_rank','appointed_rank', 'akses', 'suspendreason', 'regstamp',
'matagajet', 'userrank','mykadverify','placement')
->with([
'penggunaRank' => function($q) use ($mid){
$q->select('id','ranktitle')->where('mid',$mid);
},
'appointedRankUser' => function($q) use ($mid){
$q->select('id','ranktitle')->where('mid',$mid);
},
'systemHirarki'=> function($q){
$q->select('id', 'nama');
},
'userHirarki' => function($q) use ($mid){
$q->select('hirarki','display')->where('mid',$mid);
},
'userPlacement' => function($q){
$q->select('id','alternate_id','nama');
}
])
->where('mid',$mid)
->where('akses','!=',-1);
if ($search) {
$user->where(function($q) use ($search){
$q->where("alternate_id","LIKE","%{$search}%")
->orWhere("nama","LIKE","%{$search}%")
->orWhere("mykad","LIKE","%{$search}%")
->orWhere("notel","LIKE","%{$search}%")
->orWhere("email","LIKE","%{$search}%");
});
}
return $user->orderBy('alternate_id','desc')
Hope everyone can get benefits from this. Thank you.

Laravel Model is freezing the server. Timeout error

I'm having a really strange issue here. I have a user model (detailed below).
It all works fine until I added the getReportsSharedAttribute function. When this is added, the server freezes and I get:
PHP Fatal error: Maximum execution time of 60 seconds exceeded in C:\Users\User\PhpstormProjects\laravel-vue\vendor\laravel\framework\src\Illuminate\Database\Eloquent\Concerns\HasRelationships.php on line 637
more:
exception: "Symfony\\Component\\ErrorHandler\\Error\\FatalError"
file: "C:\\Users\\User\\PhpstormProjects\\laravel-vue\\vendor\\laravel\\framework\\src\\Illuminate\\Database\\Eloquent\\Concerns\\HasAttributes.php"
I thought there was something up with the code, so I ran it manually in a controller and dumped it, it worked fine.
So I tried it as a relation instead of an attribute. Same error.
So then I thought, is it just specific to the ReportingSetAssigned model, so I did another query on another collection, and another, and I still get the timeout error.
I tried another Model, it worked fine, for no apparent reason. Even though there were a lot more records inside. It doesn't seem to be dependant on how many columns are involved in the return. None of my tables have more than 50 records inside, even in the relations.
What's going on here? Is there some limit somewhere?
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Query\Builder;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\DB;
use Laravel\Sanctum\HasApiTokens;
use stdClass;
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable, SoftDeletes;
public $appends = [
'full_name',
'profile_photo_thumb',
'permissions_alt',
'line_managed_only_id',
'line_managers_only_id',
'permissions_meetings_only_id',
'reports_shared',
];
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
protected $dates = ['deleted_at'];
public function permissions(){
return $this->belongsToMany(Permission::class);
}
public function timelineitems(){
return $this->hasMany(TimelineItem::class);
}
public function line_managers(){
return $this->belongsToMany(User::class,'permissions_lm','user_id','lm_id');
}
public function line_managed(){
return $this->belongsToMany(User::class,'permissions_lm','lm_id','user_id');
}
public function permissions_meetings(){
return $this->belongsToMany(Area::class,'permissions_meetings','user_id','area_id')->withPivot('level');
}
public function getPermissionsMeetingsOnlyIdAttribute(){
return $this->permissions_meetings()->pluck('permissions_meetings.area_id');
}
public function permissions_qed(){
return $this->belongsToMany(Area::class,'permissions_qed','user_id','area_id')->withPivot('level');
}
public function permissions_reporting(){
return $this->belongsToMany(Area::class,'permissions_reporting','user_id','area_id')->withPivot('level');
}
public function permissions_reporting_sets(){
return $this->belongsToMany(ReportingSet::class,'permissions_reporting_sets','user_id','set_id')->withPivot('level');
}
public function improvement_category_objective_action_milestones(){
return $this->belongsToMany(ImprovementSetCategoryObjectiveActionMilestone::class);
}
public function planning_review_forms(){
return $this->hasMany(PerformanceManagementSetAssigned::class)->whereHas('set', function($q) {
$q->where('appraisal', 0);
});
}
public function appraisal_forms(){
return $this->hasMany(PerformanceManagementSetAssigned::class)->whereHas('set', function($q) {
$q->where('appraisal', 1);
});
}
public function performance_manager_set_as_lm(){
return $this->belongsTo(PerformanceManagementSetAssigned::class, 'lm_id');
}
public function getPermissionsAttribute(){
return $this->permissions()->get();
}
public function getLineManagersOnlyIdAttribute(){
return $this->line_managers()->pluck('permissions_lm.lm_id');
}
public function getLineManagedOnlyIdAttribute(){
return $this->line_managed()->pluck('permissions_lm.user_id');
}
public function hasPermissionTo($permission){
if(auth()->user()->super_admin){
return true;
}
if($permission==='super_admin'&&auth()->user()->super_admin){
return true;
}
if(!is_array($permission)){
$access = $this->permissions()->where('permission', $permission)->exists();
if($access){
return true;
}
return false;
}else{
foreach($permission as $p){
$access = $this->permissions()->where('permission', $permission)->exists();
if($access){
return true;
}
}
}
}
public function checkPermissionReportingSet($permission){
$access = $this->permissions_reporting_sets()->where('set_id', $permission)->first();
if($access){
if($access->pivot->level=='read'){
return 'read';
}
if($access->pivot->level=='write'){
return 'write';
}
}
}
public function checkPermissionReportingArea($permission){
$access = $this->permissions_reporting()->where('area_id', $permission)->first();
if($access){
if($access->pivot->level=='true'){
return true;
}
}
}
public function truePermission($permission){
$access = $this->permissions()->where('permission', $permission)->exists();
if($access){
return true;
}
}
public function updateTimeline($type_main,$type_sub,$title,$content,$icon,$color,$link,$relevant_id = null,$user_id = null){
if(!$user_id){
$user_id = $this->id;
}
$t = new TimelineItem();
$t->type_main = $type_main;
$t->type_sub = $type_sub;
$t->title = $title;
$t->content = $content;
$t->icon = $icon;
$t->color = $color;
$t->link = $link;
$t->user_id = $user_id;
$t->relevant_id = $relevant_id;
$t->save();
}
public function getPermissionsForVueAttribute(){
$permissions = $this->permissions;
$new = [];
foreach($permissions as $p){
$new[$p->permission] = true;
}
$new['meeting_areas'] = [];
$permissions = $this->permissions_meetings;
foreach($permissions as $p){
$new['meeting_areas'][$p->id] = $p->pivot->level;
}
$new['qed_areas'] = [];
$permissions = $this->permissions_qed;
foreach($permissions as $p){
$new['qed_areas'][$p->id] = $p->pivot->level;
}
$new['reporting_areas'] = [];
$permissions = $this->permissions_reporting;
foreach($permissions as $p){
$new['reporting_areas'][$p->id] = $p->pivot->level;
}
$new['reporting_sets'] = [];
$permissions = $this->permissions_reporting_sets;
foreach($permissions as $p){
$new['reporting_sets'][$p->id] = $p->pivot->level;
}
return json_encode($new);
}
public function getPermissionsAltAttribute(){
//General permissions
$permissions = Permission::get();
$newP = [];
foreach($permissions as $p){
$newP[$p->permission] = false;
}
$permissions = $this->permissions;
foreach($permissions as $p){
$newP[$p->permission] = true;
}
$newP['meeting_areas'] = [];
$newP['qed_areas'] = [];
$newP['reporting_areas'] = [];
$newP['reporting_sets'] = [];
foreach(Area::orderBy('name', 'ASC')->get() as $p){
$newP['meeting_areas'][$p->id] = "false";
$newP['qed_areas'][$p->id] = "false";
$newP['reporting_areas'][$p->id] = "false";
}
$meetings = DB::table('permissions_meetings')->where('user_id', '=', $this->id)->get();
foreach($meetings as $p){
$newP['meeting_areas'][$p->area_id] = $p->level;
}
$qed = DB::table('permissions_qed')->where('user_id', '=', $this->id)->get();
foreach($qed as $p){
$newP['qed_areas'][$p->area_id] = $p->level;
}
$reporting = DB::table('permissions_reporting')->where('user_id', '=', $this->id)->get();
foreach($reporting as $p){
$newP['reporting_areas'][$p->area_id] = $p->level;
}
foreach(ReportingSet::orderBy('name', 'ASC')->get() as $p){
$newP['reporting_sets'][$p->id] = "false";
}
$reporting = DB::table('permissions_reporting_sets')->where('user_id', '=', $this->id)->get();
foreach($reporting as $p){
$newP['reporting_sets'][$p->set_id] = $p->level;
}
return $newP;
}
public function getCyclesAttribute(){
return Cycle::orderBy('id')->get();
}
public function getFullNameAttribute(){
return $this->first_name . " " . $this->last_name;
}
public function getProfilePhotoThumbAttribute(){
if($this->profile_photo){ return "THUMB-" . $this->profile_photo; }else{ return "no-avatar.png"; }
}
public function getReportsSharedAttribute(){
return ReportingSet::where('observee_id', $this->id)->where('observee_share', 1)->where('published', 1)->without('set.modules')->get()->toArray();
}
public function canLineManage($id){
if($this->super_admin==1) return true;
foreach($this->line_managed as $lm){
if($lm->id==$id){
return true;
}
}
}
}
EDIT: If I run this code in a controller, it does't hang at all. It loads up the data in less than a second
EDIT: Restarted computer, still happening
This looks a lot like an infinitive call-loop, please refer to this on github issue
Allowed Memory size exhaused when accessing undefined index in toArray
You are just running out of memory when calling parent::toArray(). You
either need to reduce the amount of items in your collection or
increase your allowed memory allocation.

How can I retrieve only filtered records in a Child Model?

I have a table that I want to use to show records of timesheet logs, I've been able to do a filter using whereHas which works, but when I try to filter by employee I still get the logs for all employees attribtued to those jobs instead of the one I'm searching for.
My controller:
$request = json_decode(json_encode($request->all(), true))->params;
$jobs = Job::whereHas('timesheets', function($query) use ($request) {
if (count($request->selected_employees) > 0) {
$query->wherein('employee_id', $request->selected_employees);
}
if (count($request->selected_clients) > 0) {
$query->wherein('client_id', $request->selected_clients);
}
if (!empty($request->start_date)) {
$query->where('date','>=',$request->start_date);
}
if (!empty($request->end_date)) {
$query->where('date','<=',$request->end_date);
}
});
$jobs = (new Job)->generateReport($jobs->get(), $request->selected_employees);
$result = array_merge_recursive($jobs);
return $result;
My Model which iterates through the job. So far everything is accurate except for the child relationship called 'timesheets', it's not defined here, but laravel auto populates it and I am not able to overwrite/replace anything with that attribute. Any ideas?
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Job extends Model
{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ["client_id", "job_number", "job_date", "payment_type", "rate", "description"];
public $totalHoursArray = array();
/**
* #var array|mixed
*/
private $report_totals;
public function client() {
return $this->belongsTo(Client::class);
}
public function timesheets() {
return $this->hasMany(TimesheetLog::class);
}
public function creator(){
return $this->belongsTo(User::class,'created_by');
}
public function editor(){
return $this->belongsTo(User::class,'edited_by');
}
/**
*
* Returns a count of Employee Hours per job for timesheet entries
* currently selected in the Job model
*
* #return array
*/
public function getEmployeeHoursPerJob($employee_ids){
$i = 0;
$hours_per_job = array();
$timesheets = empty($employee_ids) ? $this->timesheets : $this->timesheets->whereIn('employee_id',$employee_ids);
foreach ( $timesheets as $trow) {
$trow->employee_code = Employee::find($trow->employee_id)->code;
$date = new \DateTime($trow->date);
$trow->date = date_format($date, 'd-m-Y');
//find if the employee exists in the hours per job array if not, push a new row
$found = array_search($trow->employee_id,array_column($hours_per_job, 'employee_id', isset($hours_per_job['employee_id']) ? 'employee_id' : null));
if($i > 0 && $found !== false){
$hours_per_job[$found]['total_time'] += $trow->total_time;
} else {
array_push($hours_per_job, ['employee_id' => $trow->employee_id, 'employee_code' => $trow->employee_code, 'total_time' => ($trow->total_time)]);
}
$i++;
}
return $hours_per_job;
}
public function generateReport($jobs, Array $employee_ids){
$report_totals = array();
$filtered_timesheets = array();
foreach ($jobs AS $jobrow) {
$i = 0;
$jobrow->client_name = Client::find($jobrow->client_id)->name;
$jobrow->attention = Client::find($jobrow->client_id)->attention;
$jobrow->rate = "$".$jobrow->rate ." ". $jobrow->payment_type;
$dateT = new \DateTime($jobrow->job_date);
$jobrow->job_date = date_format($dateT, 'd-m-Y');
$hours = $jobrow->getEmployeeHoursPerJob($employee_ids);
$jobrow->employee_hours = $hours;
foreach ($filtered_timesheets as $timesheetf){
array_push($timesheets_filtered, $timesheetf);
}
foreach($hours AS $hoursRow){
$found = array_search($hoursRow['employee_id'],array_column($report_totals, 'employee_id',
isset($report_totals['employee_id']) ? 'employee_id' : null));
if($found !== false){
$report_totals[$found]['total_time'] += $hoursRow['total_time'];
} else {
array_push($report_totals, $hoursRow);
$i++;
}
}
}
return compact('jobs','report_totals');
}
}
In the foreach loop I assigned a new property of the row to a wherein query and this was accurate and what I wanted. But again, I couldn't replace or assign the original property that I want to send to the view.
$jobrow->timesheets_filtered = $jobrow->timesheets->wherein('employee_id',$employee_ids)->toArray();

Create Backup controller in Laravel

I am not experienced in programming. I am trying to create a controller in laravel that backups tables. The tables are backed up correctly, but I've received some remarks that my code can easily be broken. I've been trying to do my best, but I'm really exhausted and getting frustrated. I have a table, and each row in the table takes from 1 to 10 MB of memory. Total rows in table 100. The maximum amount of memory (memory_limit) is set to 35 MB. What would be the best way solve this problem? I really appreciate any suggestion or help. This is my code:
The BackupController class
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use Illuminate\Database\Events\StatementPrepared; // set the fetch mode
use Illuminate\Support\Facades\Cache;
use Carbon\Carbon;
use Illuminate\Support\Facades\Schema;
use DB;
use App\Post;
use App\User;
use App\Jobs\BackupTableJob;
use Artisan;
class BackupController extends Controller
{
const MAX_VALUE = 35000; //kilobytes
public function lockTable()
{
// lock all tables
DB::unprepared('FLUSH TABLES WITH READ LOCK;');
}
public function setQueueJob(User $user, Post $post)
{
BackupTableJob::dispatch($user, $post)
->delay(Carbon::now()
->addSeconds(5));
// Artisan::call('queue:work');
}
public function unlockTable()
{
// unlock all tables
DB::unprepared('UNLOCK TABLES');
}
public function queryFetch($data)
{
$pdo = DB::connection()->getPdo();
$stmt = $pdo->prepare($data);
$stmt->execute();
// $stmt = $pdo->query($data);
$results = $stmt->fetch();
return $results;
}
public function create(Request $request)
{
$this->setPdoMode();
$numTables = DB::select("SHOW TABLES");
$countUserRecords = User::count();
$countPostRecords = Post::count();
return view('backup', compact('numTables','countUserRecords', 'countPostRecords'));
}
public function setPdoMode()
{
\Event::listen(StatementPrepared::class, function($event) {
$event->statement->setFetchMode(\PDO::FETCH_ASSOC);});
}
// public function backup(Request $request, User $user, Post $post)
public function backup(Request $request, User $user, Post $post)
{
$this->setQueueJob($user, $post);
if ($request->all()) {
$tables = request('table');
$output = '';
foreach ($tables as $key => $table) {
$this->lockTable();
$show_table_query = $this->queryFetch("SHOW CREATE TABLE {$table}");
$output .="\n" . $show_table_query[1] . ";\n";
$this->setPdoMode();
$single_result = DB::select("SELECT * FROM {$table}");
$output .= $this->getTableData($single_result, $table);
$output .= $this->cacheData($table, $output);
}
if ($this->checkFileSize($output)) {
return redirect()->route('create');
}
}
return redirect()->route('backupError');
}
// Stores the file in this location: storage/app
public function download($output)
{
$dt = Carbon::now();
$file_name = 'backup_on[' . $dt->format('y-m-d H-i-s') . '].sql';
Storage::disk('local')->put($file_name, $output);
}
public function getTableData($single_result, $table)
{
$this->unlockTable();
$output = '';
foreach ($single_result as $key => $table_val) {
if ($table === "posts" || $table === "users") {
$output .= "\nINSERT INTO $table(";
$output .= "" .addslashes(implode(", ", array_keys($table_val))) . ") VALUES(";
$output .= "'" . addslashes(implode("','", array_values($table_val))) . "');\n";
}
}
// $output .= $this->cacheData($table, $output);
return $output;
}
public function checkFileSize($file)
{
$file_size = strlen($file);
// convert bytes to kilobytes
$file_size = round($file_size / 1024, 0, PHP_ROUND_HALF_UP);
if ($file_size <= self::MAX_VALUE) {
$this->download($file);
return true;
}
return false;
}
public function cacheData($table, $data)
{
// $table = $table;
$start = microtime(true);
$data = Cache::remember('table', 10, function() use ($table){
return DB::table($table)->get();
});
$duration = (microtime(true) -$start) * 1000;
\Log::info("From cache: " . $duration .' ms');
return $data;
}
}
BackupTableJob class
<?php
namespace App\Jobs;
use App\User;
use App\Post;
use App\Http\Controllers\BackupController;
use Illuminate\Http\Request;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
class BackupTableJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable; //SerializesModels;
protected $user;
protected $post;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct(User $user, Post $post)
// public function __construct()
{
$this->user = $user;
$this->post = $post;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
// $this->user->save();
// $this->post->save();
}
}
You don't need to process that data with PHP. You can simply use raw SQL queries in laravel:
SELECT *
INTO tableToBeBackedUp
FROM currentTable;

Categories