New to Laravel php and trying to find out solution of this,
$periods = Period::where('timetable_id', $id);
echo $periods;
giving this error
Object of class Illuminate\Database\Eloquent\Builder could not be converted to string
i know why its giving this error but can not think of an alternate.
You'd need to ->get() your results first. Also, since you'll get a Collection returned you'd need to use dd() (or print_r/var_dump) to output the results:
$periods = Period::where('timetable_id', $id)->get();
dd($periods);
More on Building Queries
I am trying to extract from my php laravel some data like this:
$x = Carbon::now()->timestamp;
$data=Notifications->where('happened_at','>',$x)
->where('id_user',Auth::user()->getAuthIdentifier());
If I enter this sql statement in my oracle database directly it works perfectly:
select * from notifications where happened_at > '10-06-2017 00:11:12,000000000';
^ this returns correct, however in my php laravel it doesn't return the good rows(returns all the rows from the database)
Later Edit: The where is the problem, I just want to compare the timestamp location in my DB('happened_at') with the current time...I don't know how though
Let's break down your model call code.
// first, you retrieve all notifications and assign them to $data
$data = Notifications::all()
// then, you try to start a new query
->where('happened_at','>',$x)
// then, you continue the new query
->where('id_user',Auth::user()->getAuthIdentifier())
// and finally, you finish the call
;
So basically, you already get all rows at the beginning, and then you try to start building a query that you never execute. (But you can't, since all() returns a collection.)
Remove the all() and finish up with ->get() at the end, and it should work. (Although I don't know anything about Oracle timestamps.)
In my application I have to check whether or not a certain date has expired, when so a e-mail has to be send out. The date's are saved in the Clients table. How can I add 5 days to the retrieved date, so I can check whether or not it will be expired in 5 days? The function which I have until now.
public function handle() {
$users =\App\Client::select('subscription_ends_at')
->groupBy('subscription_ends_at')
->get();
$data_now = Carbon::now();
foreach($date_expired as $users ){
// $date_expired + 5 days
if($date_expired > $data_now){
//Send e-mail
}
}
}
You should make your comparision part of your query by using whereDate(). There's no benefit in your case for filtering this data on PHP side:
$now = Carbon::now()->addDays(5);
$users =\App\Client::select('subscription_ends_at')
->groupBy('subscription_ends_at')
->whereDate('date_expired', '>', $now->toDateString()),
->get();
Docs on Eloquent where clauses here.
EDIT
Your query is broken for me. Using groupBy() will make it return only a fraction of clients grouping those expiring the same day into one entry. This in result defeats the purpose of sending notifications as not everyone will get it, so I'd rather remove groupBy() completely.
Use addDays() to add days:
Carbon::now()->addDays(5);
Also, it's always a good idea to add this to the query instead of loading all the data and filter collection:
->where('subscription_ends_at', '>', Carbon::now()->addDays(5))
This will work if you'll add subscription_ends_at to the $dates property.
In CakePHP3, there is a ORM that helps with building queries.
From the documentation, I can see that
$query = $articles->find(); // build a query that has not run yet
$query->where(['id' => 1]); // Return the same query object
So in this case, I want the string
WHERE `articles`.`id` = 1
After much googling, I found out that there is a way to return just the where clause of a query object.
$query->where(['id' => 1])->clause('where'); // Return the where clause in the form of a QueryExpression
More googling leads me to find out how to get the QueryExpression to spit out string representation
$query->where(['id' => 1])->clause('where')->sql($valueBinder); // Return the where clause in string format
Here is my problem. I don't know what the $valueBinder is supposed to look like. I don't know how to initialize it.
I am also happy not to use ValueBinder as long as I can get the where clause in string format using CakePHP 3 ORM and in the right SQL dialect. Please assume I am using MySQL.
Please advise.
EDIT
I tried to use $query->valueBinder() as the $valueBinder.
It is empty and does not contain the associated c:0 to the value 1.
To directly answer your question, you can get the SQL for any clause this way:
$binder = new \Cake\ORM\ValueBinder();
$query->clause('where')->sql($binder);
That will return the SQL with the correct placeholders, not with the values to be used. The values live in the $binder variable and are used for statement objects.
As I can see, you only wanted to preserve the internal structure of the where clause to pass it to another query in a different request. Your solution is fine, but I'd like to add that you can also encode a full conditions tree from an existing query:
$where = serialize($query->clause('where'));
$anotherQuery->where(unserialize($where)); // A query in another request
In any case, you need to be careful with what you are unserializing as taking it directly from user input will certainly lead to security problems.
You can choose to omit this param if you like. Please see http://api.cakephp.org/3.0/class-Cake.Database.Query.html#_sql
In addition, you can use the Query member function traverse($visitor, $parts) to isolate the where clause. $visitor is a function that takes a value and a clause. You define the behavior of $visitor. $parts is an array of clause names. I suggest passing array('where') into this param.
My workaround is that I store the conditions in json string format.
Using the same example, what I do is
$data['conditions'] = json_encode(['Articles.id' => 1]); // encode into JSON string
$this->DynamicRules->patchEntity($dynamicRule, $data); // use in edit action of DynamicRulesController
then when I need to reuse the conditions, I do:
$articlesTable = TableRegistry::get('Articles');
$query = $articlesTable->find(); // new query for Articles
$rule = json_decode($dynamicRule->conditions, true); // get back the conditions in associative array format
$query->where($rule); // re-assign the conditions back
This got me what I ultimately wanted.
How can I select a random row using Eloquent or Fluent in Laravel framework?
I know that by using SQL, you can do order by RAND(). However, I would like to get the random row without doing a count on the number of records prior to the initial query.
Any ideas?
Laravel >= 5.2:
User::inRandomOrder()->get();
or to get the specific number of records
// 5 indicates the number of records
User::inRandomOrder()->limit(5)->get();
// get one random record
User::inRandomOrder()->first();
or using the random method for collections:
User::all()->random();
User::all()->random(10); // The amount of items you wish to receive
Laravel 4.2.7 - 5.1:
User::orderByRaw("RAND()")->get();
Laravel 4.0 - 4.2.6:
User::orderBy(DB::raw('RAND()'))->get();
Laravel 3:
User::order_by(DB::raw('RAND()'))->get();
Check this article on MySQL random rows. Laravel 5.2 supports this, for older version, there is no better solution then using RAW Queries.
edit 1: As mentioned by Double Gras, orderBy() doesn't allow anything else then ASC or DESC since this change. I updated my answer accordingly.
edit 2: Laravel 5.2 finally implements a wrapper function for this. It's called inRandomOrder().
This works just fine,
$model=Model::all()->random(1)->first();
you can also change argument in random function to get more than one record.
Note: not recommended if you have huge data as this will fetch all rows first and then returns random value.
tl;dr: It's nowadays implemented into Laravel, see "edit 3" below.
Sadly, as of today there are some caveats with the ->orderBy(DB::raw('RAND()')) proposed solution:
It isn't DB-agnostic. e.g. SQLite and PostgreSQL use RANDOM()
Even worse, this solution isn't applicable anymore since this change:
$direction = strtolower($direction) == 'asc' ? 'asc' : 'desc';
edit: Now you can use the orderByRaw() method: ->orderByRaw('RAND()'). However this is still not DB-agnostic.
FWIW, CodeIgniter implements a special RANDOM sorting direction, which is replaced with the correct grammar when building query. Also it seems to be fairly easy to implement. Looks like we have a candidate for improving Laravel :)
update: here is the issue about this on GitHub, and my pending pull request.
edit 2: Let's cut the chase. Since Laravel 5.1.18 you can add macros to the query builder:
use Illuminate\Database\Query\Builder;
Builder::macro('orderByRandom', function () {
$randomFunctions = [
'mysql' => 'RAND()',
'pgsql' => 'RANDOM()',
'sqlite' => 'RANDOM()',
'sqlsrv' => 'NEWID()',
];
$driver = $this->getConnection()->getDriverName();
return $this->orderByRaw($randomFunctions[$driver]);
});
Usage:
User::where('active', 1)->orderByRandom()->limit(10)->get();
DB::table('users')->where('active', 1)->orderByRandom()->limit(10)->get();
edit 3: Finally! Since Laravel 5.2.33 (changelog, PR #13642) you can use the native method inRandomOrder():
User::where('active', 1)->inRandomOrder()->limit(10)->get();
DB::table('users')->where('active', 1)->inRandomOrder()->limit(10)->get();
You can use:
ModelName::inRandomOrder()->first();
it's very simple just check your laravel version
Laravel >= 5.2:
User::inRandomOrder()->get();
//or to get the specific number of records
// 5 indicates the number of records
User::inRandomOrder()->limit(5)->get();
// get one random record
User::inRandomOrder()->first();
or using the random method for collections:
User::all()->random();
User::all()->random(10); // The amount of items you wish to receive
Laravel 4.2.7 - 5.1:
User::orderByRaw("RAND()")->get();
Laravel 4.0 - 4.2.6:
User::orderBy(DB::raw('RAND()'))->get();
Laravel 3:
User::order_by(DB::raw('RAND()'))->get();
In Laravel 4 and 5 the order_by is replaced by orderBy
So, it should be:
User::orderBy(DB::raw('RAND()'))->get();
For Laravel 5.2 >=
use the Eloquent method:
inRandomOrder()
The inRandomOrder method may be used to sort the query results randomly. For example, you may use this method to fetch a random user:
$randomUser = DB::table('users')
->inRandomOrder()
->first();
from docs: https://laravel.com/docs/5.2/queries#ordering-grouping-limit-and-offset
You can also use order_by method with fluent and eloquent like as:
Posts::where_status(1)->order_by(DB::raw(''),DB::raw('RAND()'));
This is a little bit weird usage, but works.
Edit: As #Alex said, this usage is cleaner and also works:
Posts::where_status(1)->order_by(DB::raw('RAND()'));
Use Laravel function
ModelName::inRandomOrder()->first();
You can easily Use this command:
// Question : name of Model
// take 10 rows from DB In shuffle records...
$questions = Question::orderByRaw('RAND()')->take(10)->get();
There is also whereRaw('RAND()') which does the same, you can then chain ->get() or ->first() or even go crazy and add ->paginate(int).
I prefer to specify first or fail:
$collection = YourModelName::inRandomOrder()
->firstOrFail();
Laravel has a built-in method to shuffle the order of the results.
Here is a quote from the documentation:
shuffle()
The shuffle method randomly shuffles the items in the collection:
$collection = collect([1, 2, 3, 4, 5]);
$shuffled = $collection->shuffle();
$shuffled->all();
// [3, 2, 5, 1, 4] - (generated randomly)
You can see the documentation here.
At your model add this:
public function scopeRandomize($query, $limit = 3, $exclude = [])
{
$query = $query->whereRaw('RAND()<(SELECT ((?/COUNT(*))*10) FROM `products`)', [$limit])->orderByRaw('RAND()')->limit($limit);
if (!empty($exclude)) {
$query = $query->whereNotIn('id', $exclude);
}
return $query;
}
then at route/controller
$data = YourModel::randomize(8)->get();
I have table with thousands of records, so I need something fast. This is my code for pseudo random row:
// count all rows with flag active = 1
$count = MyModel::where('active', '=', '1')->count();
// get random id
$random_id = rand(1, $count - 1);
// get first record after random id
$data = MyModel::where('active', '=', '1')->where('id', '>', $random_id)->take(1)->first();
Here's how I get random results in eloquent in one of my projects:
$products = Product::inRandomOrder()->limit(10);
10 - The number of random records to pull.
Try this code! It Works:
User::orderBy(DB::raw('RAND()'))->get();