Laravel Increase SQL speed - php

I am trying to increase the speed of my queries in Laravel 5.7 and I have the call down to ~2.5 seconds. I am trying to figure out more ways to make it faster and if I could get some help I'd greatly appreciate it.
Thanks
How my data is structured:
Function(Controller):
public function getUserDataTmp(Request $request) {
$input = file_get_contents("php://input");
$request = json_decode($input);
if ($this->authTokenAccess($request) == true) {
$bottomWords = bottom_exterior_word::select('word','sentence','sequence','id','group_id')->where('user_id','=', $request->id)->get();
$emergencyWords = left_exterior_word::select('word','sentence','sequence','id')->where('user_id','=', $request->id)->get();
foreach($bottomWords as $tmp => $key) {
$group_id = $key->group_id;
$bottomWords->user_id = $request->id;
$bottomWords[$tmp]->words = $key->getMainWords($group_id, $request->id);
}
foreach($emergencyWords as $key => $word) {
$emergencyWords[$key]->image = imageModel::select('base64','id')->where('emergency_id','=', $word->id)->first();
}
$data = [
'data' => [
'return' => 'success',
'code' => 'VEDC001',
'response' => 'Successfully Gathered Words',
'main_categories' => $bottomWords,
'emergency_words' => $emergencyWords
]
];
return(json_encode($data));
}
}
getMainWords Function(bottom_exterior_word model):
public function getMainWords($group_id, $id)
{
// return("TEST");
$words = \App\main_word::select('id','group_id','sentence','sequence','word')->where('group_id','=', $group_id)->where('user_id','=', $id)->get();
foreach ($words as $key => $word) {
$words[$key]->image = Image::select('base64','id')->where('word_id','=', $word->id)->first();
}
return $words;
}

Start by refactoring so that you dont query inside a foreach loop
foreach($bottomWords as $tmp => $key) {
$group_id = $key->group_id;
$bottomWords->user_id = $request->id;
$bottomWords[$tmp]->words = $key->getMainWords($group_id, $request->id);
}
I would change the getMainWords function to accepts an array of group id's and use the whereIn clause:
The whereIn method verifies that a given column's value is contained
within the given array:
$users = DB::table('users')
->whereIn('id', [1, 2, 3])
->get();
Same treatment for this loop.
foreach($emergencyWords as $key => $word) {
$emergencyWords[$key]->image = imageModel::select('base64','id')->where('emergency_id','=', $word->id)->first();
}
In general minimizing the NUMBER of queries will improve response time.

Old post, would just like to update it though. Since I have first posted this, I have learned a lot more about Laravel and am a lot more experienced with it.
Here is my new function and solution:
Controller:
public function data(Request $request)
{
return response()->success(
[
'emergencywords' => EmergencyWord::with('image')->whereUserId($request->user()->id)->get(),
'categorywords' => CategoryWord::with(['image','words.image'])->whereUserId($request->user()->id)->get(),
]
);
}
Category Word Relationships:
public function image()
{
return $this->hasOne('App\Image','id','image_id');
}
public function words()
{
return $this->hasMany('App\MainWord','category_words_id','sequence');
}
Emergency Word Relationships:
public function image()
{
return $this->hasOne('App\Image','id','image_id');
}
Main Word Relationships:
public function image()
{
return $this->hasOne('App\Image','id','image_id');
}

Related

How to loop foreach in laravel dynamically

Am just learning Laravel and I have this logic were in I want to display array of total items based from user, to explain this further here is my database
user table
items table
this is my current code
public function display()
{
$users = User::where('type', 'Shop')->get();
foreach($users as $user){
$shop_id = $user['id'];
$shop_name = $user['name'];
}
$total = Item::where('user_id', $shop_id)->sum('total');
$shops =[
['Name' => $shop_name, 'total' => $total],
];
return response()->json([
"shops" =>$shops
], 200);
}
and here is my sample output:
am only getting 1 object instead of 2 as I have two shops how to loop this dynamically.
thanks
the $shops and $total variable is not in foreach loop that's because it returns only one row. and you must use $shops[] .
public function display()
{
$users = User::where('type', 'Shop')->get();
foreach($users as $user){
$shop_id = $user['id'];
$shop_name = $user['name'];
$total = Item::where('user_id', $shop_id)->sum('total');
$shops[] =['Name' => $shop_name, 'total' => $total];
}
return response()->json([
"shops" =>$shops
], 200);
}
but the best and clean way is to use laravel relationship
in User model:
public function items()
{
return $this->hasMany(Item::class) ;
}
and display controller :
public function display()
{
$shops = User::where('type', 'Shop')->get()
->mapWithKeys(function($user){
return ['name'=>$user->name ,
'total'=> $user->items->sum('total')
]});
return response()->json(["shops" =>$shops], 200);
}
Do this
$shops[] = ['Name' => $shop_name, 'total' => $total];
to push all the shops into one array.
You are currently overriding the hole array.
UPDATE: Also move the sql part into the foreach:
foreach($users as $user){
$shop_id = $user['id'];
$shop_name = $user['name'];
$total = Item::where('user_id', $shop_id)->sum('total');
$shops[] =['Name' => $shop_name, 'total' => $total];
}

Addition of a new value to API response

Currently learning Laravel and any help is much appreciated!
My API controller has the following index function
public function index()
{
abort_if(Gate::denies('course_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$response=Course::all()->toArray();
$allData = [];
foreach (Course::all() as $ids=>$CMF) {
UNSET($response[$ids]['media']);
$data_sequence = DB::table('media_sequence')->where('data_id', $CMF["id"])->where('type','CMF')->first();
$data_id=$data_sequence->id;
$data_sequence = json_decode($data_sequence->data_sequence);
$data = [];
$data["id"] = $CMF["id"];
$data["title"] = $CMF["title"];
foreach ($data_sequence as $id => $dataSeq) {
if ($dataSeq->type == "Text") {
$response[$ids]['media'][]=["id"=>$data_id,"text"=> $dataSeq->name,"mime_type"=>"text"];
} elseif ($dataSeq->type == "file") {
foreach ($CMF["media"] as $file) {
if (str::slug($dataSeq->name) == str::slug($file["file_name"])) {
$file["thumb"] = $file->getUrl('video_thumb');
$response[$ids]['media'][]=$file;
}
}
}
}
$allData[] = $data;
}
return new CourseResource($response);
//Commented: return new CourseResource(Course::with(['category', 'assigned_teams', 'team'])->get());
}
Getting no result when trying to return 'assigned_teams' with $response
The API response still doesn't include 'assigned_teams'
I tried: return new CourseResource($response, 'assigned_teams');
It is not returning the assigned_items since it is not included in the $response array.
Change
$response=Course::all()->toArray();
To
$response=Course::with(['category', 'assigned_teams', 'team'])->get();
Read more: eager-loading-multiple-relationships
Btw, as #apokryfos mentioned, you should refactor your code using Eloquent Relationships and Eager Loading.
I assume that the assigned_teams are not handled in your CourseResource.
You need to extend your resource to respect this additional relation.
class CourseResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
// return teams if they have been loaded
'teams' => TeamsResource::collection($this->whenLoaded('assigned_teams')),
];
}
}
This is just exemplary, since you did not provided your code for CourceResource yet, you need to update it according to your needs.
Here is the link to the appropriate laravel documentation: https://laravel.com/docs/8.x/eloquent-resources#conditional-relationships

Add to each array element another element php

I'm having one more problem in the logical realm.
I have an array containing ids:
$product_ids = ['1', '5', '3']; <- Example
Another string that I convert to an array separating it by commas, this to indicate the quantities of the products to be withdrawn. For example for product 1 I want 3 drives so I would need the array element to be "1,3".
$finalarray = ["1,3", "5,2", "3,10"];
Next I indicate the code that is executed in the controller (where is what I previously told):
public function ordenform(Request $request)
{
$input = $request->all();
$request->validate([
'nombre' => 'required|string',
'apellido' => 'required|string',
'productos' => 'required',
'cantidades' => 'required|string',
'enviosino' => 'required|in:si,no',
]);
// Quantity Array
$cantidades = explode(',', $input['cantidades']);
if (count($cantidades) != count($input['productos'])) {
return back()->withErrors(['Las cantidades no corresponden a los productos agregados']);
}
$total = 0;
$ganancia = 0;
foreach ($input['productos'] as $producto) {
$producto = Product::find((int) $producto);
$total += $producto->value;
$ganancia += $producto->ganancia;
$producto->stock = (int) $producto->stock - 1;
$producto->save();
}
if ($input['enviosino'] == 'si') {
$total += (int) $input['envio'];
}
if ($input['envio'] == null) {
$input['envio'] = 0;
}
// Products IDS Array
$jsonproductos = json_encode($input['productos']);
Order::create([
'nombre' => $input['nombre'],
'apellido' => $input['apellido'],
'product_ids' => $finalprods,
'value' => $total,
'ganancia' => $ganancia,
'envio' => $input['envio'],
]);
$caja = Config::where('id', 1)->get()->first();
$caja->dinerototal += $total;
$caja->gananciatotal += $ganancia;
$caja->save();
return back()->with('success', 'Orden creada correctamente');
}
Finally, I need to pass as creation parameter the final array to the column products_ids (later I will modify the name).
Another option I thought of is passing objects to an array:
[{id: 1, quantity: 3}]
But I don't know how to get to create that object, I'm still kind of new hehe.
I hope I have explained myself well, English is not my native language. I'm sorry.
I am attentive to your comments !! Greetings.
PS: I am using Laravel
To achieve [{id: 1, quantity: 3}] there will be several idea, but it seems to be an arrayList, so below is how you can create an arrayList in PHP. I have not tested the code, just written here, but should give you the idea to achieve this.
I am considering one is Order class.
<?php
class Order {
private $id;
private $quantity;
public function setId(int $id) {
$this->id = $id;
return $this;
}
public function getId(){
return $this->id;
}
public function setQuantity(int $quantity) {
$this->quantity = $quantity;
return $this;
}
public function getQuantity(){
return $this-> quantity;
}
public function toArray(){
return [
'id' => $this->getId(),
'quantity' => $this->getQuantity()
];
}
}
?>
another is OrderList.
<?php
class OrderList {
private $orderList;
public function __construct(Order ...$orders) {
$this->orderList = $orders;
}
public function toArray(){
$arr = [];
foreach ($this->orderList as $order) {
$arr[] = $order->toArray();
}
return $arr;
}
}
?>
and then use like
$order1 = new Order();
$order1 = $order1->setId(1)->setQuantity(10);
$order2 = new Order();
$order2 = $order1->setId(2)->setQuantity(20);
$orderList = new OrderList($order1, $order2);
var_dump(json_encode($orderList->toArray()));
//Output
string(47) "[{"id":2,"quantity":20},{"id":2,"quantity":20}]"
You do not need json_encode, I have added it to print only.
Nevermind, resolved ->
$prodsfinal = array();
for ($i = 0; $i < sizeof($cantidades); $i++) {
$array = [
'id' => json_decode($input['productos'][$i]),
'cantidad' => (int) $cantidades[$i],
];
array_push($prodsfinal, $array);
}

Where like not working inside foreach loop in laravel

Where like not working inside foreach loop in Laravel. The following always return null. Here i want to use multi sorting, but the response in always blank.
public function searchBy(Request $request)
{
if($request->name!=''){
$data['name']=$request->name;
}
if($request->s_name!=''){
$data['short_name']=$request->s_name;
}
if($request->pin!=''){
$data['pin_code']=$request->pin;
}
if($request->city!=''){
$data['city']=$request->city;
}
$customers = Customer::get();
foreach ($data as $key => $value) {
// return $key;
$customers = $customers->where($key,'LIKE','%'.$value.'%');
}
return response()->json([
'data' =>$customers,
]);
}
The variable $customers should be a QueryBuilder and you should call get() on it in the end to retrieve your items.
$customers = Customer::query();
foreach ($data as $key => $value) {
$customers->where($key,'LIKE','%'.$value.'%');
}
return response()->json([
'data' => $customers->get(),
]);
The QueryBuilder is an object, which is by design pass by reference, therefor you do not need to reassign it.

php+laravel , quantity get back

I have 3 tables (sales, sales_detail, and bicycle). I don't know how to get back my quantity (sales) to unit balance (bicycle) and then delete the sales_detail entry because I'm going to update new sales.
public function edit(Request $request, $id) {
$sales = Sales::find($id);
$sales_details = SalesDetail::where('sales_id', $id)->get();
$bicycles = Bicycle::where('sales_id', $id)->get();
foreach ($bicycles as $bc && $sales_details as $sd) {
$bc->unit_balance = $sd->quantity + $bc->unit_balance;
//then delete sales_detail
}
return view('sales/edit', array(
'sales' => $sales,
'sales_details' => $sales_details,
'bicycles' => $bicycles
));
}
I suggest the use of Elequents relations in your Models such as 'belongsto' and 'hasmany' to better prepare data. Following this practice would allow you to simplify your queries during development. Your approach is very messy/novice and procedural.
Checkout https://laravel.com/docs/5.8/eloquent-relationships
public function edit(Request $request, $id) {
$sales = Sales::find($id); // get sales where sales_id = 40
$sales_details = SalesDetail::where('sales_id', $id)->get();
return view('sales/edit', array( 'sales' => $sales,
'sales_details' => $sales_details ));
}
public function update(Request $request, $id) {
$sales = Sales::find($id);
$sales_details = SalesDetail::where('sales_id',$id)->get();
foreach ($sales_details as $sales_dtl) {
$bicycle = Bicycle::find($sales_dtl->bicycle_id);
$bicycle->unit_balance = $bicycle->unit_balance + $sales_dtl['quantity'];
$bicycle->save();
$sales_dtl->delete();
}
$this->saveData($sales,$request);
return redirect()->route('sales.index');
}
i get my answer already

Categories