I have an array in $genreArr, i want it to be readable in the line whithin the function(query) inner select:
if($genreArr){
$movies = DB::table('movie_list')->whereIn('movie_id',function($query){
$query->select(DB::raw('movie_id'))
->from('movie_genre')
->whereIn('genre_id',$genreArr)
->distinct();
})->orderBy(DB::raw('RAND()'))->take(10)->get();
}
How do i do that without using global variables, i tried pass that variable as the second param next to the $query and than it gives me this kind of error:
Missing argument 2 for MovieController::{closure}()
You should adjust the closure to use the variable you want.
function ($query) use ($genreArr) {
... ->whereIn('genre_id', $genreArr);
}
Not sure whether the whereIn method will accept this. But rather than using a closure, you could use an alternative callable option. i.e Something like
$obj = new SomeClass();
$obj->setGenreArray($genreArr);
$movies = DB::table('movie_list')->whereIn('movie_id',array($obj, 'getQuery'))->orderBy(DB::raw('RAND()'))->take(10)->get();
And then you're query builder stuff will be inside the getQuery method, with access to the property $this->genreArray
Related
I am wondering that whether it is possible to write two different mysql queries in one php class object method and use those results in an another class method. Here's I am trying to do (I put only the relevant part of my code here), but I think it's not working:
<?php
public function sql()
{
$sql = "SELECT * FROM customers";
// Another sql
$sql_sales = "SELECT SUM(sales) as sales FROM customers";
// Execute this sql and result is stored in a variable
$this->sales = $row['sales'];
return $sql;
}
public function customers_list()
{
$sql = $this->sql();
$customers = '
<div id="customers">
<div id="customers_num"><span>'.$this->sales.'</span> Sales</div>
</div>';
return $customers;
}
?>
Can we use value of variable $this->sales inside another method?
If not then what's the correct way of getting it's value?
In case your code is inside a class and you're using an instantiated object :
From PHP basics
The pseudo-variable $this is available when a method is called from
within an object context. $this is a reference to the calling object
Therefore you can access any of your object properties inside its methods.
In your specific case $this->sales = $row['sales']; stores a value in its sales
property which can be used anywhere else in the object scope.
We can not get variable value like your approach. Your main query $sql is returning the result but the value of your second query $sql_sales is nowhere returned. That's why it is undefined property in your method customers_list().
The solution is to create a separate method to get $this->sales value. Then you can call this method in your customers_list() and access its value.
I have array which contains laravel model (App\User) attribute names like following:
$documents = array(
'passport_expire' => 22,
'residency' => 13
);
If I called these functions directly it will return a boolean value like:
App\User::find(2)->passport_expire;//will output true / false
I want to execute the functions inside a foreach:
foreach($documents as $type => $val){
// I want to call the attributes
App\User::find(1)->{$type};
//I want to call and execute App\User::find(1)->passport_expire and App\User::find(1)->residency
I read in php documentation about a way with similar approach called Variable functions but I don't know how to accomplish that in laravel.
How about
App\User::find(1)->$type;
Also you want to use string & variable
App\User::find(1)->$type . '_test';
However, if you want to use string as first, I think you need to create a variable beforehand and use first approach.
$type = "xx_$type_xx"
App\User::find(1)->$type;
Whereas, App\User::find(1)->{$type}; works,
But App\User::find(1)->{$type . 'text'}; doesn't work.
You're calling the attributes/properties as functions?
So far I think you meant variable variables.
If you want to access the properties like passport_expire or residency then you can try like
$user = App\User::find(1);
foreach (array_keys($documents) as $document) {
$documents[$document] = $user->{$document};
}
The above code will update the $documents array with the values of $user object's properties.
But, if you want to execute as functions as you mentioned, you need to try call_user_func or call_user_func_array
I have a method display() in the book class.
$name = 'display()';
$book = new Book('PHP Object-Oriented Solutions', 300);
$book->$name;
How can i call display method using $book->$name
You need to tell PHP that you're trying to execute a method, not in the variable itself, but within the actual code:
$name = 'display';
$book = new Book('PHP Object-Oriented Solutions', 300);
$book->$name();
Otherwise, as you have seen, it will treat $name as a property name, and rightly so ... If you have both a property and a method named 'display', there wouldn't be a way to distinguish between the two using what you've tried.
The cleanest way (imo at least) is to use something like:
$name = 'display';
$book = new Book('PHP Object-Oriented Solutions', 300);
call_user_func([$book, $name]); // This looks cleaner and/or more obvious on first sight.
// call_user_func_array([$book, $name], $arrayOfArguments);
// And as #Narf suggested (and I agree cuz we move forward)
call_user_func([$book, $name], ... $arrayOfArguments);
And yes you can pass parameters to this function, that will be passed to the function, but you have to list them after the callable array. in order to avoid doing that (hard to maintain and not always what you want) you can use call_user_func_array which accepts an array of arguments as second argument that is passed to the callable.
call_user_func Documentation
call_user_func_array Documentation
$users = [
"Andrew",
"Max",
"Larry",
"Ricardo",
"Lucy",
"Marcus",
"Sophie"
];
$sector_rel = [];
$location_rel = [];
function sectorRel($user){
return sector_rel[] = round(1/rand(1,10),3);
}
function locationRel($user){
return $location_rel[] = round(1/rand(1,20),3);
}
foreach($users as $user){
sectorRel($user);
locationRel($user);
}
This:
function sectorRel($user){
return sector_rel[] = round(1/rand(1,10),3);
}
Should be/could be:
function sectorRel($user){
global sector_rel;
sector_rel[] = round(1/rand(1,10),3);
}
The problem is that the functions don't have access to the array variables. You can import them into the function scope using the keyword global, if they are indeed global variables. Now, having global variables isn't a good thing, and for a small test it's okay, but eventually you'll be eliminating your globals and this solution won't work.
But alternatively, you could pass the array variables to the function as an argument. However, this still introduces a lot of logic in the function. The function has to be told about the array, it must know that it needs to add a value to the end, and it also needs to calculate the actual value to add.
So better, make the function just return the calculated value and add it to the array outside of the function:
function sectorRel($user){
// Assuming your are going to use 'user' here somewhere?
return round(1/rand(1,10),3);
}
function locationRel($user){
return round(1/rand(1,20),3);
}
foreach($users as $user){
sector_rel[] = sectorRel($user);
$location_rel[] = locationRel($user);
}
You can then wrap this entire snippet of code into another function and call that to populate the arrays. That way, you've quite reasonably split the responsibilities of the functions and have a piece of code that looks nice and clean.
You do not need to use return in either of sectorRel or locationRel. At the moment this will return the reference to that array and it is not being stored in a variable. You would need to store them in a variable or just get rid of the return. My PHP is a little weak at the moment but you should probably append the values in those functions to the array.
Also if you have a parameter called $user for each of those functions you should either use that parameter or just get rid of it.
I have a Validator class that can build several arrays with methods (names) stored.
Like so $this->rules[1] = ['trim()', 'required()', 'max(35)'];
How can I loop through every method the array and call it exactly by how they are defined?
If I do it like the following, I get Undefined property: Validator::$trim() etc. error.
foreach ($this->rules[1] as $method) {
$this->$method;
}
How can I add an extra parameter $input to each method in the array before it gets in the loop?
So instead of trim() it would be trim($input), and for max(35) max(35, $input), etc.
First of all, use $this->{$method} to call your method in your example.
Secondly, don't call them like that at all. Use call_user_func_array instead.
You need to extract method name and parameters frist in order to call directly.
I recommend you use a placeholder for your $input to add it to your method call.
You can then pass the parameters for your function call as an array.
$ruleset = 'max(34,:input)';
// do the string manipulation yourself please ;-)
$method = 'max';
$input = getInput(); // wherever you get that from
$parameters = array (34, $input),
call_user_func_array(__NAMESPACE__ .'\Validator::' . $method, $parameters);
What you are looking for are the call_user_func and/or call_user_func_array methods.
As Andresch pointed out, the way your rules are defined aren't flexible. Now you would have to parse them to retrieve the inputs for the function. a better way would be the following format:
$this->rules[1] = array(
'trim',
'required',
array('max'=>35)
);
and then
foreach ( $this->rules as $rule )
{
if ( is_array($rule)
{
call_user_func_array(array($this, key($rule)), current($rule));
}
else
{
call_user_func(array($this,$rule));
}
}
P.S. don't just copy paste this code, this is intended for explanation