So I have the following scope on an Investor Model:
public function scopeCountUsersInRegionForCompany(Builder $query, $companyName, $regionCode)
{
return $query->select('users.*')
->join('user_profile', 'user_profile.user_id', '=', 'users.id')
->join('investments', 'users.id', '=', 'investments.user_id')
->join('offerings', 'investments.offering_id', '=', 'offerings.id')
->join('companies', 'offerings.company_id', '=', 'companies.id')
->where('companies.slug', '=', $companyName)
->where('user_profile.region', '=', $regionCode)
->count();
}
Its used in the following context:
public function regionCountForCompany($slug)
{
$regions = [];
$totalUsersForCompany = Investor::countUsersForCompany($slug);
if ($totalUsersForCompany === 0) {
return [];
}
foreach ($this->getAllRegions() as $regionCode => $regionName) {
$regions[$regionName] = (Investor::countUsersInRegionForCompany($slug, $regionCode) / Investor::countUsersForCompany($slug)) * 100;
}
if (max($regions) > 0) {
return $regions;
} else {
return [];
}
}
Note the for each loop:
foreach ($this->getAllRegions() as $regionCode => $regionName) {
$regions[$regionName] = (Investor::countUsersInRegionForCompany($slug, $regionCode) / Investor::countUsersForCompany($slug)) * 100;
}
the following call:
Investor::countUsersInRegionForCompany($slug, $regionCode)
will return 1 and then every other time after that it returns: Object of class Illuminate\Database\Eloquent\Builder could not be converted to int If I do: var_dump(is_object(Investor::countUsersInRegionForCompany($slug, $regionCode))) Its false once, then true for every other time its called.
This is the only scope that causes this issue. How ever if I do a var dump inside the scope to get the variable $query instead of returning it like you see me doing, it comes back as an int.
If I hit the end point in the browser that calls this particular set of code, all of this works, no errors about objects or any of that. The test is as follows:
public function it_should_return_region_count_for_investors() {
$this->createInvestment();
$investor = factory(User::class)->create([
'role_id' => 4
]);
$response = $this->actingAs($investor)
->call('GET', 'api/v1/investors-signedup-by-jurisdiction/');
$this->assertNotEmpty(json_decode($response->getContent()));
}
The response comes back as: Object of class Illuminate\Database\Eloquent\Builder could not be converted to int (It actually renders a html laravel error page with this message)
What is going on?
It's because of a little bit stupid check of Laravel. When it calls scope it checks what the function must return and add fallback for chaining :
return call_user_func_array([$this->model, $scope], $parameters) ?: $this;
so when your function returns 1 - ternary operator equals to true and result returns, when it return 0 - ternary operator fails, and you get this instead.
I advice you to not return result from scope. It's done to modify query, not to return results. Put count() outside the scope like
Investor::usersInRegionForCompany($slug, $regionCode)->count()
Related
I've done a query at Laravel and to check result content, I've used dd, but, for some reason, when I remove the dd(), it throws an exception sayint "Undefined array key 0". However, with dd DO find the key.
Code is this:
public function getFormatosArticulo(Articulo $articulo){
$formatoRaw = Formato::where('articulo_id', '=', $articulo->id)->get();
dd($formatoRaw[0]);
$formato = $formatoRaw[0];
return $formato;
}
And dd output is this:
I guess you are calling getFormatosArticulo function for multiple times, and passed not exists id into it. The get() function will always return a empty collection even if no data matched.
Can you test your function use code below and check if id does exists or not?
public function getFormatosArticulo(Articulo $articulo){
try {
$formatoRaw = Formato::where('articulo_id', '=', $articulo->id)->get();
$formato = $formatoRaw[0];
return $formato;
catch (Exception $e) {
dd($articulo->id); // i guess there is no articulo_id equal this in formato table.
}
}
The reason this happens is that dd stands for “dump and die” so your first iteration goes through but you don’t check the rest because you use die(). A solution to this can be as simple as:
public function getFormatosArticulo(Articulo $articulo) {
$formatoRaw = Formato::where('articulo_id', '=', $articulo->id)->get();
if ($formatoRaw) {
$formato = $formatoRaw[0];
return $formato;
}
}
Since you are only interested for the [0] position though a similar approach would be:
public function getFormatosArticulo(Articulo $articulo) {
$formatoRaw = Formato::where('articulo_id', '=', $articulo->id)->first();
if ($formatoRaw) {
return $formatoRaw;
}
}
What I want is that when a user visits this link /api/bonus?provider[]=MyCompany
the result will show only bonus provided by providers=[MyCompany].
In my controller:
public function all(Request $request)
{
$size = $request->input('size');
$bonus = Bonus::with('category', 'bonus');
$bonus = Filterer::apply($request, $size, $bonus);
$bonus = Filterer::apply($request, $size, $bonus);
return response()->json([
'code' => 0,
'success' => true,
'data' => BonusResource::collection($bonus),
}
My expected result is to get all the providers that equal the [MyCompany]
But somehow this query doesn't work.
Filterer
public static function apply(Request $filters, $size, $bonus)
{
if ($filters->has('provider')) {
$bonus->whereHas('bonus', function ($query) use ($filters) {
$query->whereIn('providers', $filters->input('provider',[]));
});
}
return $bonus->paginate($size);
}
but at the end I'm getting this result. The data is null [].
I'm wonder why I can't get the data. Which part I had done wrong?
To actually get results you should use some function that gets data from database, for example get, first (depends whether you want to get multiple rows or only first row). Now you only prepare query that should be executed but you never execute it, so yo should change line:
$bonus = Filterer::apply($request, $size, $bonus);
into
$bonus = Filterer::apply($request, $size, $bonus);
$bonus = $bonus->get();
to execute query and get results.
I might be wrong, but based on your code, the function apply didn't return anything, it will always empty. Shouldn't it be return $bonus? and don't forget the get.
public static function apply(Request $filters, $size, $bonus)
{
if ($filters->has('provider')) {
$bonus->whereHas('bonusRelease', function ($bonus) use ($filters) {
return $bonus->whereJsonContains('providers', $filters->input('provider',[]));
});
}
return $bonus->get();
}
Updated my answer
The providers is a json type. You can't just query it with where in (a,b,c). Change to whereJsonContains. Please check this link another case and laravel docs.
First, convert the input into array, here I'm using explode()
and then I loop the converted array and use %% to search the providers. Hope it will help!
if ($filters->has('provider') && trim($filters->input('provider')) != "") {
$bonus_list->whereHas('bonusCompany', function ($query) use ($filters) {
$providers = explode(',', (trim($filters->input('provider'), '[]')));
foreach ($providers as $key => $provider) {
if ($key == 0) {
$query->where('providers', 'LIKE', ['%' . trim($provider) . '%']);
} else {
$query->orwhere('providers', 'LIKE', ['%' . trim($provider) . '%']);
}
}
});
};
Let suppose I have a function:
public function __getalldata($tablename,$tablefield=array(),$orderbyfield = 'id',$ascdesc = 'desc',$limit = 200,$type='result')
{
//Query generation according to above parameters
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->limit($limit)
->get();
return $data->$type();
}
This function is been used to many pages. Now, I want to skip the parameter $limit From function. That means I don't want to give $limit value but I need all data from database.
So what happens is if I have data like 600 and I don't know how many data I have, I don't give any parameter value to function (so by default it will take 500 data). But here I need all data so how can I manage this situation?
From https://www.codeigniter.com/user_guide/database/query_builder.html passing in NULL to the limit method as the first parameter will cause the limit statement to not limit anything - hence returning all of the rows (see on github):
public function limit($value, $offset = 0)
{
is_null($value) OR $this->qb_limit = (int) $value;
empty($offset) OR $this->qb_offset = (int) $offset;
return $this;
}
So in short if you want to skip the $limit parameter try setting its value to NULL. Like so...
public function __getalldata($tablename, $tablefield=array(), $orderbyfield = 'id', $ascdesc = 'desc', $limit = NULL, $type='result')
{
// Query generation according to above parameters
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->limit($limit)
->get();
return $data->$type();
}
I assume that the default value of $limit = 200 is already used in a number of places in the application. So the goal is to bypass the default when you want all the matching records. My suggestion is to simply pass the value 0 (zero) when you want them all. Then the only a small code change is required in the class method.
public function __getalldata($tablename, $tablefield=array(), $orderbyfield = 'id',
$ascdesc = 'desc',$limit = 200,$type='result')
{
if($limit > 0)
{
$this->db->limit($limit);
}
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->get();
return $data->$type();
}
public function __getalldata($tablename,$tablefield=array(),$orderbyfield = 'id',$ascdesc = 'desc',$limit = '',$type='result')
{
//Query generation according to above parameters
if($limit == '') {
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->get();
} else {
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->limit($limit)
->get();
}
return $data->$type();
}
Did you tried this?
As per MySQL documentation:
You can used bigint max values 18446744073709551615 to retrieve all data from MySQL.
So your function should look like this
public function __getalldata($tablename,$tablefield=array(),$orderbyfield = 'id',$ascdesc = 'desc',$limit = 18446744073709551615,$type='result')
{
//Query generation according to above parameters
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->limit($limit)
->get();
return $data->$type();
}
Note my main answer is at the bottom (IF you can't edit this function) but I have put in alternative answers as am unclear from OP as to if the function can/should be edited.
Edit this function
Your declared function has:
public function __getalldata($tablename,...,$limit = 200 ...){ ... }
Where the reference given in various answers here appearing to be adjusting this default value - the simplest solution is to NOT edit the default but set a special case and explicitly check for if $limit is exactly (and only) null.
To clarify:
PHP will use an explicitly set NULL value over any default value (in this case, 200).
So;
// within the function
if($limit !== null) {
//use limit in your PDO
}
This does not convert if $limit == 0 or other type-juggling cases, common to PHP
This above means that if no $limit value is given then default of 200 is used. If an explicit NULL value is given, that will be used instead.
Code
Please note this code is for example only and can probably be simplified further to better follow DRY patterns, but I don't know enough about CodeIgniter to do this here and now.
public function __getalldata($tablename,$tablefield=array(),$orderbyfield = 'id',$ascdesc = 'desc',$limit = 200,$type='result')
{
//Query generation according to above parameters
if($limit !== null){
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->limit($limit)
->get();
}
else {
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->get();
}
return $data->$type();
}
If you can't edit the function
I'm unclear on if you can (or want) to edit the function itself, if you're using Codeigniter, so instead simply refer an automatic value to the function arguments to return every valud row, no matter what (in effect removing the case for limit.
To do this use the PHP Constant PHP_INT_SIZE or PHP_INT_MAX which will return exactly that value. Reading this question/answer tells you more about this, but these constants should be self explanatory, as the maximum int values.
If a MySQL LIMIT exceeds the rows returned, this has no effect, so by setting this to a maximal value, it will always exceed the rows returned and/or the rows usable by the resulting page output.
Therefore:
$var = __getalldata("table",[0=>'columnname'],'id','desc',PHP_INT_MAX,'result');
Will return you every row within the PHP Integer limit of [2,147,483,647] or [9,223,372,036,854,775,807], depending on your system (32bit or 64bit).
And let's face it -- if 2 billion is not enough of a limit, you need to face you have some serious problems with your SQL query ;-)
That is easy with the use of an if statement. Just check to see if a condition is true for your limit, if not resolve to else. Like so:
public function __getalldata($tablename,$tablefield=array(),$orderbyfield = 'id',$ascdesc = 'desc',$limit = 200,$type='result')
{
if () // check $limit condition here
{
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->limit($limit)
->get();
return $data->$type();
}
else {
$data = $this->db
->select($tablefield)
->from($tablename)
->order_by($orderbyfield, $ascdesc)
->get();
return $data->$type();
}
}
EDIT: I am not sure what your conditions for the $limit variable are, so just enter them in the if statement's arguments.
I have a event table with status o or 1.
I have to filter the event with status 1,0 or ALL.
I tried with laravel when conditional clause,its not working with value zero,other conditionals are working.
$status = Input::get('status');
$events = DB::table('events')
->select('events.*')
->when($status, function ($query) use ($status) {
return $query->where("events.status",$status);
})
->get();
in_array function used in when method try this one
because 0(zero) means(false) by default understand so try to use inner function in when method
if didn't pass status then set default value as 2 or any number but not 0,1 and null
$status = Input::has('status') ? Input::get('status') : 2;
$events = DB::table('events')->select('events.*')
->when(in_array($status,[0,1]), function ($query) use ($status) {
return $query->where("events.status",$status);
})->get();
second way create a new function
function checkStatus($status,$array) {
if(isset($status)) {
return in_array($status,$array);
}
return false;
}
$events = DB::table('events')->select('events.*')
->when(checkStatus($status,[0,1]), function ($query) use ($status) {
return $query->where("events.status",$status);
})->get();
For any future reader using 0 and 1
we can use when in the following way
->when($request->has('status'),
fn ($query) => $query->where("status", $request->status)
)->get();
we are getting the user requested status using has method in Laravel to deal with it.
I'm trying to build a query based on URL parameters. When the Controller is loaded I need to check which parameters have been provided and build a query from them. It's working with static values, but isn't working with conditional statements. Is my laravel syntax correct?
class OrdenesController extends BaseController {
public function showOrdenes($action)
{
$my_id = Auth::user()->id;
$my_cod = Auth::user()->codprov;
switch ($action)
{
case 'list':
$rows = DB::table('ordens')->count();
if(Input::get("jtSorting"))
{
$search = explode(" ", Input::get("jtSorting"));
$numorden= Input::get("nro_orden");
$filtros =explode(" ", $filtros);
$data = DB::table("ordens")
->select(array('*', DB::raw('SUM(cant_pend) as cant_pend'), DB::raw('SUM(importe) as importe')))
->where('cod_prov', '=', $my_cod)
->where('nro_orden', '=', $numorden)///work
---------- ////no work
if (Input::has('nro_orden')) {
->where('nro_orden', '=', $numorden)
}
---------- /// no work
->groupBy('nro_orden')
->skip(Input::get("jtStartIndex"))
->take(Input::get("jtPageSize"))
->orderBy($search[0], $search[1])
->get();
}
return Response::json(
array(
"Result" => "OK",
"TotalRecordCount" => $rows,
"Records" => $data
)
);
break;
};
}
}
You are missing the variables, no? You haven't told PHP what variable/object to do the where() to in your condition. The magic of Laravel's Eloquent (and a lot of other libraries) is that when you call its methods, it returns itself (the object) back so you can make another method call to it right away.
So when you do this:
$data = DB::table("ordens")
->select(...)
->where(...);
is the same as:
$data = DB::table("ordens");
$data = $data->select(...);
$data = $data->where(...);
But you are trying to do ->where(...) right away after if condition. You need to tell PHP which object/variable you are trying to call the method from. Like this:
$num = Input::get("nro_orden");
$data = DB::table("ordens")
->select(array('*', DB::raw('SUM(cant_pend) as cant_pend'), DB::raw('SUM(importe) as importe')))
->where('cod_prov', '=', $my_cod);
if (Input::has('nro_orden')) {
$data = $data->where('nro_orden', '=', $num);
}
$data = $data->groupBy('nro_orden')
->skip(Input::get("jtStartIndex"))
->take(Input::get("jtPageSize"))
->orderBy($search[0], $search[1])
->get();