Multiple queries in laravel scope function - php

I am attempting to make multiple queries in a scope function in laravel. my code is as follows. the first query executes normally but the second seems to be ignored. what is the correct way to do this?
public function scopeUpdateStatus($query,$oldUser, $newUser, $alias, $env) {
$query->where('db_conn_app_alias_user', $newUser)->where('db_conn_app_alias', $alias)->where('app_instance_environment', $env)->update(array('user_status' => 'active'));
$query->where('db_conn_app_alias_user', $oldUser)->where('db_conn_app_alias', $alias)->where('app_instance_environment', $env)->update(array('user_status' => 'passive'));
return "success";
}

The trick here is to use with (a Laravel helper function) and clone.
function scopeSomeName($query) {
with(clone $query)->whereStuff;
with(clone $query)->whereOtherStuff;
}

This happens because you use the same $query variable in the two updates. You add where()s to the $query in the first update query and then run it, but when you add your where()s in the second update query the where()s from the first query are still there. Because of this your query will return zero result so there is nothing to update. Copy the $query first to a new variable then run the second query in the copied one:
public function scopeUpdateStatus($query, $oldUser, $newUser, $alias, $env) {
$queryTemp = $query;
$query->where('db_conn_app_alias_user', $newUser)
->where('db_conn_app_alias', $alias)
->where('app_instance_environment', $env)
->update(array('user_status' => 'active'));
$queryTemp->where('db_conn_app_alias_user', $oldUser)
->where('db_conn_app_alias', $alias)
->where('app_instance_environment', $env)
->update(array('user_status' => 'passive'));
return "success";
}

A minor edit (reduces overhead) to #merlinpatt answer. You don't need to clone the $query twice. Just once, as you already have the existing/original variable
function scopeSomeName($query) {
$query_cloned = clone $query;
$query->whereStuff;
$query_cloned->whereOtherStuff;
}
Also, there's no need for the with() helper function.
Tested it and works as expected.

Related

Method Illuminate\Support\Collection::find does not exist

Edit function:
public function editCheck($id, LanguagesRequest $request)
{
try{
$language = language::select()->find($id);
$language::update($request->except('_token'));
return redirect()->route('admin.languages')->with(['sucess' => 'edit done by sucsses']);
} catch(Exception $ex) {
return redirect()->route('admin.addlanguages');
}
}
and model or select function
public function scopeselect()
{
return DB::table('languages')->select('id', 'name', 'abbr', 'direction', 'locale', 'active')->get();
}
This code is very inefficient, you're selecting every record in the table, then filtering it to find your ID. This will be slow, and is entirely unnecessary. Neither are you using any of the Laravel features specifically designed to make this kind of thing easy.
Assuming you have a model named Language, if you use route model binding, thing are much simpler:
Make sure your route uses the word language as the placeholder, eg maybe your route for this method looks like:
Route::post('/languages/check/{language}', 'LanguagesController#editCheck');
Type hint the language as a parameter in the method:
public function editCheck(Language $language, LanguagesRequest $request) {
Done - $language is now the single model you were afer, you can use it without any selecting, filtering, finding - Laravel has done it all for you.
public function editCheck(Language $language, LanguagesRequest $request) {
// $language is now your model, ready to work with
$language::update($request->except('_token'));
// ... etc
If you can't use route model binding, or don't want to, you can still make this much simpler and more efficient. Again assuming you have a Language model:
public function editCheck($id, LanguagesRequest $request) {
$language = Language::find($id);
$language::update($request->except('_token'));
// ... etc
Delete the scopeselect() method, you should never be selecting every record in your table. Additionally the word select is surely a reserved word, trying to use a function named that is bound to cause problems.
scopeselect() is returning a Collection, which you're then trying to filter with ->find() which is a method on QueryBuilders.
You can instead filter with ->filter() or ->first() as suggested in this answer
$language = language::select()->first(function($item) use ($id) {
return $item->id == $id;
});
That being said, you should really find a different way to do all of this entirely. You should be using $id with Eloquent to get the object you're after in the first instance.

Set Query Builder conditions to Model in Laravel 5.1

First I have to say that I tried to find solution, and i didn't.
Basic question:
$Br = new BrandTop;
dd( $Br->limit(10)->get() ); // Will return 10 rows
and
$Br = new BrandTop;
$Br->limit(10);
dd( $Br->get() ); // Will return all rows.
So, the basic question - why? How can I set some limit for Model, but still work with it, for example set (or not set) some where or order depends on other variables.
Advanced question:
I want to use Model like this:
class BrandTop extends Model
{
public function withBrand() {
return $this->leftJoin('brand', 'brand.id' , '=', 'brandtop.brand_id');
}
public function forType($type) // there is much more conditions for type
{
return $this->where(['type' => $type]);
}
// main function
public function forSunglasses($limit = 0, $logo = false)
{
if ($logo)
$this->where(['menu_logo' => 1])->orderBy('total_sales', 'desc');
if ($limit)
$this->limit($limit);
return $this->forType('sunglasses')->withBrand();
// But there goes Error, because forType() return Builder object, and it has no withBrand() method
}
}
So, there is much more conditions, and it's much easier to set all conditions in separate methods. But how?
Model vs Builder
The thing to understand here is the difference between the Model object and the underlying Builder (query builder) object.
The statement $Br = new BrandTop; will create a new instance of a Model, and assign it to the $Br variable. Next, the $Br->limit(10) statement will create a new instance of a Builder object for the brand_tops table, with a limit of 10 applied.
In your first example, by doing $Br->limit(10)->get(), you're calling get() on the Builder that has your limit applied.
In your second example, your individual $Br->limit(10) creates the new Builder instance, but never uses it for anything. The next statement, $Br->get(), creates another new Builder instance without any constraints, so it retrieves all the records.
To be able to build up your query, you need to assign your Builder instance to a variable, and continue to modify that instance before finally calling get(). For example, to get your second example to work:
$query = BrandTop::query();
$query->limit(10);
$query->where(/*conditions*/);
dd($query->get());
Query Scopes
In relation to the second part of your question, you probably want to look into query scopes.
class BrandTop extends Model
{
// renamed to "JoinBrand" instead of "WithBrand", as "with" would imply
// an eager loaded relationship vs a joined table
public function scopeJoinBrand($query)
{
return $query->leftJoin('brand', 'brand.id' , '=', 'brandtop.brand_id');
}
// got rid of "for" prefix
public function scopeType($query, $type)
{
return $query->where('type', $type);
}
// got rid of "for" prefix
public function scopeSunglasses($query, $limit = 0, $logo = false)
{
if ($logo)
$query->where(['menu_logo' => 1])->orderBy('total_sales', 'desc');
if ($limit)
$query->limit($limit);
return $query->type('sunglasses')->joinBrand();
}
}
With the above model, your code would look something like:
dd(BrandTop::sunglasses()->get());
// or, more verbosely:
$query = BrandTop::query();
$query->sunglasses(); // $query already an object, no need to reassign it to itself
dd($query->get());

preserving aliases in laravel query builder

function getPerson(){
return \DB::table('user')->select('firstname as name', 'age');
}
function getPet(){
return \DB::table('pet')->select('petname as name', 'age');
}
function getNames($var){
return $var->select('name')->where('age', 10)->get();
}
$base = getNames(getPerson());//empty here
$base = getNames(getPet());//empty here
The main problem is I got a lot of different queries and I want to put aliases on them and then prepare data for diagram with another query. It is difficult if aliases diseappear.
Each query can have only one select(). $var being passed into getNames() is a query already has select() so adding more select() will override previous one.
Try remove select() from getNames() and test whether you get your result.
function getNames($var){
return $var->where('age', 10)->get();
}
Remember that you are using 'query builder' which means every query constraint you are adding is being added into the same query, not different one. The entire query will be actually built and executed once you try to get the result data set like calling get(), first(), etc.

Returning object in a function Laravel 4

I am trying to access a functions variable from another function in the same class. i am fairly new to the concept and I can get it to work in another function but when I try to create it's own function I get an Trying to get property of non-object I know what that means but it's confusing as to what needs to be returned in my function since it does work in my other function.
Function getting the error
public function getEditTotal($id) {
$techs = $this->technician();
$tech = $techs->tech;
var_dump($tech); die;
return View::make('report.edit', array('pageTitle' => 'Edit Report Total', 'id' => $id, 'tech' => $tech));
}`
The function I am trying to call
public function technician() {
$tech = DB::table('technician')
->get();
return $tech;
}
I had that same $tech variable in this function and it worked perfectly fine if I called $this->setComplete($id) instead.
Returned statement in the setComplete($id) function
return View::make('report.total', array('pageTitle' => 'Reporting', 'id' => $id, 'tech' => $tech, 'status' => $status));
I am sure it's just the way it's being returned since that variable is being returned in setComplete($id) in the array. I just don't know how to strictly call it in the technician() function.
When you call $techs = $this->technician(); you are setting the $techs to be whatever the value of the $tech variable in the technician function. That is going to be the result of DB::table('technician')
->get();
Theoretically this should be an array of objects where each object represents one row in the technician table.
If you want to know what's going on, add a var_dump($tech) inside the your technician() function, just prior to the return $tech statement.
Since you indicate it is working as expected, you're getting an array of objects. I'm not sure what you want to do with those, but inside the controller:
foreach ($techs as $tech) {
echo $tech->somefieldInTech;
}
or perhaps
echo $techs[0]->somefieldInTech;
So to be clear, in your laravel template, you might want to pass the entire $techs and foreach through it in the template, although from your code it's not clear what you need to do with the data.

Call to a non-object workaround?

I have a method like this:
public function query ($sql) {
$this->result = $this->db->query($sql);
}
Binds the query statement to the result variable. This is really handy because I have several methods that output something and another method that then handles the $result variable for other tasks.
However I wanted to use the same kind of method, but on prepared statements(to escape data that gets inserted) and I ran into a problem:
public function prepare ($sql) {
$this->result = $this->db->prepare($sql);
}
I tried to use it like this:
public function insert ($this, $that) {
// Then I tried to use my prepare method
$var = $this->prepare(INSERT INTO Table (Row1, Row2) VALUES (:Val1, :Val2));
$var->bindValue(":Val1", $this, PDO::PARAM_INT);
//... and so on
}
The problem shows up on the $var->bindValue() "Call to a member function bindvalue() on a non-object". What is exactly happening here because I don't really understand the error message? If I query my db using the query method it works just fine, but how can I bind values using the prepare method?
In:
public function ($sql) {
$this->result = $this->db->prepare($sql);
}
You forget to return the result. (You also forgot the name of the function in the snippet.)
The error message is quite clear, you're calling a method on something that's not an object. In this case you're calling it on NULL because your own prepare-method doesn't return anything.
first off i noticed your methods don't have a name.
public function ($sql) {
$this->result = $this->db->query($sql);
}
shouldn't it be something like
public function doSomething($sql) {
$this->result = $this->db->query($sql);
}
secondly, it seems you are calling an instance of another class in your method.
$this->db->query($sql)
if am not wrong the 'db' should be anothe class that you are trying to access its query method...Look at your code again.
Lastly i you are missing a return statement.

Categories