My model looks like:
protected $appends = array('status');
public function getStatusAttribute()
{
if ($this->someattribute == 1) {
$status = 'Active';
} elseif ($this->someattribute == 2) {
$status = 'Canceled';
...
} else {
$status = 'Some antoher status';
}
return $status;
}
And I want to order a collection of this models by this status attribute, is it possible?
Model::where(...)->orderBy(???)
p.s. I need exactly orderBy, not sortBy solution.
There is no way to make Eloquent do this because it only creates a SQL query. It does not have the ability to translate the PHP logic in your code into a SQL query.
A work around is to loop over the results afterwards and manually check the appends fields. Collections may be useful here.
Either you can use
Model::where(...)->orderBy('someattribute')->get();
in this case you will only get integer value in place of someattribute, or you can use DB query s follows
DB::select(DB::raw('(CASE WHEN someattribute = 1 THEN "Active" CASE WHEN someattribute = 1 THEN "Canceled" ELSE "Some antoher status" END) AS status'))
->orderBy('someattribute', 'desc');
Related
I've create a table order on my code, My idea is to generate an Unique order Id per user.
On my controller I have a code with the MYSQL request, and a function to return the result (which works on other SQL requests).
So My idea is on MySQL request is to count the number of order with the same number and If result is =1 I have to generate a new order number. On my order class I have this function:
public static function getCountOrderIfExist($bdd, $order_number) {
$requete = "SELECT * FROM Order WHERE order_number='$order_number'";
$commandes = getResultatRequete($bdd, $requete);
return !empty($commandes) ? $commandes : null;
}
And I call it on my Controller:
$count = Order::getCountOrderIfExist($bdd, $order_number);
while ($count >= 1) {
$order_number= $user_role."_".$user->getUtilisateurId().rand(1,99999)."_".$user->getEntreprise()->getId().rand(1,999999);
}
And here is the code of my getResultatRequete:
function getResultatsRequete(PDO $bdd, $requete) {
$reponse_requete = $bdd->query($requete);
if ($reponse_requete != false) {
$resultat_requete = $reponse_requete->fetchAll();
return str_replace("\\", "", $resultat_requete);
} else {
printErrorInfo($bdd, $requete, true);
return array();
}
}
When I run my code on debug mode the SQL request return NULL and I don't understand why, because when I run my Request on a terminal it works well. Any idea?
From our correspondence in the comments, it seems that the problem lies in the return statement:
return !empty($commandes) ? $commandes : null;
That statement returns any found records, or null if no records are found. However, it seems that the controller expects the function to return the number of matching records (0 if none are found).
In order to return a number for you to work with, you need to instead do a count of the returned records:
return count($commandes);
This should give you the results you need.
I have a function that looks for possible boxes that can carry the article.
public static function get_possible_boxes($article,$quantity)
{
$i = 0;
$possible_boxes = array();
$total_weight = $articles->grams * $quantity;
$boxes = Boxes::all();
foreach($boxes as $box)
{
if($total_weight+ $box->grams < $box->max_weight)
{
$possible_boxes[$i] = $box;
$i++;
}
}
return collect($possible_boxes);
}
This gives me a collection with boxes that can carry my items.
Now I should check if the ID of the box selected by the customer exists. If it does not exist, it will pick the first valid one.
This is where I am stuck. I have tried to use puck:
public function someotherfunction(){
...
$boxes = get_possible_boxes($something,$number);
$valid_box = $boxes->where("id", $request->selected_box)->pluck("id");
if(!$valid_box){
$valid_box = $boxes[0]
}
...
This works if the selected box cannot be used. The function pluck only gives me the id, clearly it is not the function I am looking for and I have already read the Laravel documentation.
So the question is, how do I get the correct eloquent model ?
You're looking for the first() method.
$valid_box = $boxes->where("id", $request->selected_box)->first();
Alternatively, if you rework your get_possible_boxes() method to return a Illuminate\Database\Eloquent\Collection instead of a plain Illuminate\Support\Collection, you could use the find() method, like so:
Function:
public static function get_possible_boxes($article,$quantity)
{
$total_weight = $article->grams * $quantity;
$boxes = Boxes::all()->filter(function ($box) use ($total_weight) {
return $total_weight + $box->grams < $box->max_weight;
});
return $boxes;
}
Find:
$boxes = get_possible_boxes($something, $number);
$valid_box = $boxes->find($request->selected_box) ?? $boxes->first();
And you could probably squeeze out a little more performance by adding the weight condition as part of the SQL query instead of filtering the collection after you've returned all the boxes, but I left that up to you.
What you want is probably filter.
$valid_box = $boxes->filter(function($box) use ($request){
return $box->id == $request->selected_box;
});
if($valid_box)...
I should note that if you don't want $valid_box to be a collection, you can use first instead of filter in the exact same way to only get the object back.
It could be done in many ways but I would rather use the following approach:
$boxes = get_possible_boxes($something,$number)->keyBy('id');
$valid_box = $boxes->get($request->selected_box) ?: $boxes->first();
For this question you need to know about 2 entities :
Loan and Charge. One Loan has Multiple Charges.
So, in my controller, I am querying for each entity and it seems to be lame.
$query = $this->getDoctrine()
->getRepository('AppBundle:Loan')
->find($id);
$query1 = $em->createQuery(
'SELECT p
FROM AppBundle:Charge p
WHERE p.loanId = :loanId
AND p.isActive = true
')->setParameter('loanId', $id);
I want to transform query1 in smth better, using relationship.
So, from my point of view it must be smth like :
foreach($query->getCharges() as $charge) {
if($charge->getIsActive() == true) {
//what to put here?
}
}
If condition passes, how can I obtain the same object that came from DB from my first code?
You can create an extra method on your Loan class that uses ArrayCollections::filter:
public function getActiveCharges()
{
return $this->getCharges()->filter(function (Charge $charge) {
return $charge->getIsActive() === true;
//or you can omit '=== true'
return $charge->getIsActive();
});
}
I've got the below function, which attempts to match users on specific whitelisted fields, which works brilliantly, for small amounts of data, but in our production environment, we can have > 1 million user records, and Eloquent is (understandably) slow when creating models in: $query->get() at the end. I asked a question this morning about how to speed this up and the accepted answer was brilliant and worked a treat, the only problem now, is that the resulting query being sent to DB::select($query->toSql()... has lost all of the required extra relational information I need. So is there any way (keeping as much of the current function as possible), to add joins to DB::select so that I can maintain speed and not lose the relations, or will it require a complete re-write?
The recipients query should include relations for tags, contact details, contact preferences etc, but the resulting sql from $query->toSql() has no joins and only references the one table.
public function runForResultSet()
{
$params = [];
// Need to ensure that when criteria is empty - we don't run
if (count($this->segmentCriteria) <= 0) {
return;
}
$query = Recipient::with('recipientTags', 'contactDetails', 'contactPreferences', 'recipientTags.tagGroups');
foreach ($this->segmentCriteria as $criteria) {
$parts = explode('.', $criteria['field']);
$fieldObject = SegmentTableWhiteListFields::where('field', '=', $parts[1])->get();
foreach ($fieldObject as $whiteList) {
$params[0] = [$criteria->value];
$dateArgs = ((strtoupper($parts[1]) == "AGE" ? false : DatabaseHelper::processValue($criteria)));
if ($dateArgs != false) {
$query->whereRaw(
DatabaseHelper::generateOperationAsString(
$parts[1],
$criteria,
true
),
[$dateArgs['prepared_date']]
);
} else {
// Need to check for empty value as laravel's whereRaw will not run if the provided
// params are null/empty - In which case we need to use whereRaw without params.
if (!empty($criteria->value)) {
$query->whereRaw(
\DatabaseHelper::generateOperationAsString(
$parts[1],
$criteria
),
$params[0]
);
} else {
$query->whereRaw(
\DatabaseHelper::generateOperationAsString(
$parts[1],
$criteria
)
);
}
}
}
}
// Include any tag criteria
foreach ($this->segmentRecipientTagGroupCriteria as $criteria) {
$startTagLoopTime = microtime(true);
switch (strtoupper($criteria->operator)) {
// IF NULL check for no matching tags based on the tag group
case "IS NULL":
$query->whereHas(
'recipientTags',
function ($subQuery) use ($criteria) {
$subQuery->where('recipient_tag_group_id', $criteria->recipient_tag_group_id);
},
'=',
0
);
break;
// IF NOT NULL check for at least 1 matching tag based on the tag group
case "IS NOT NULL":
$query->whereHas(
'recipientTags',
function ($subQuery) use ($criteria) {
$subQuery->where('recipient_tag_group_id', $criteria->recipient_tag_group_id);
},
'>=',
1
);
break;
default:
$query->whereHas(
'recipientTags',
function ($subQuery) use ($criteria) {
$dateArgs = (DatabaseHelper::processValue($criteria));
$subQuery->where('recipient_tag_group_id', $criteria->recipient_tag_group_id);
if ($dateArgs != false) {
$subQuery->whereRaw(
DatabaseHelper::generateOperationAsString(
'name',
$criteria,
true
),
[$dateArgs['prepared_date']]
);
} else {
// Need to check for empty value as laravel's whereRaw will not run if the provided
// params are null/empty - In which case we need to use whereRaw without params.
if (!empty($criteria->value)) {
$subQuery->whereRaw(
\DatabaseHelper::generateOperationAsString(
'name',
$criteria
),
[$criteria->value]
);
} else {
$subQuery->whereRaw(
\DatabaseHelper::generateOperationAsString(
'name',
$criteria
)
);
}
}
},
'>=',
1
);
}
}
//$collection = $query->get(); // slow when dealing with > 25k rows
$collection = DB::select($query->toSql(), $query->getBindings()); // fast but loses joins / relations
// return the response
return \ApiResponse::respond($collection);
}
By lost relational information do you mean relations eagerly loaded the name of which you passed to with()?
This information was not lost, as it was never in the query. When you load relations like that, Eloquent runs separate SQL queries to fetch related objects for the objects from your main result set.
If you want columns from those relations to be in your result set, you need to explicitely add joins to your query. You can find information about how to do this in the documentation: https://laravel.com/docs/5.1/queries#joins
I have a search query that needs to be done. However, a search doesn't always have all values set, like in this case.
$aEvents = DB::table('events')
->where('client_id', '=', $client_id);
The question is, how can I make this where statement depend on the value of $client_id. So if the value is empty I don't want the Where statement to occur.
Also, I do not want to write several complete queries with if statements in PHP. To many variables. Ideally I'd like something like this:
$aEvents = DB::table('events')
->(($client_id != "") ? where('client_id', '=', $client_id) : "");
Using eloquent is (really!) nice and save, but I'm not yet up to speed with if statements in std Class objects I guess. Any help is appreciated.
You may try something like this:
$query = DB::table('events');
if(!empty($client_id)) {
$query->where('client_id', $client_id);
}
$aEvents = $query->get(); // Call this at last to get the result
If you are passing client_id to the server via a form/query string(user input) then you may try something like this:
if($client_id = Input::get('client_id')) {
$query->where('client_id', $client_id);
}
Update: For pagination try this:
$aEvents = $query->paginate(10); // For 10 per page
So you may call links() method in your view if you pass it like this:
return View::make('viewName')->with('aEvents', $aEvents);
In the view for pagination links:
$aEvents->links()
You can also use query scopes in the model for this purpose. Scopes allow you to easily re-use query logic in your models. In the model Event, you can add the following query scope:
public function scopeClientID($query, $client_id)
{
if ($client_id != '') {
return $query->where('client_id', '=', $client_id);
} else {
return $query;
}
}
Then from your controller or wherever you're calling it from, you can do the following:
$aEvents = Event::clientID($client_id);
If you want to get all the results, then you can do:
$aEvents = Event::clientID($client_id)->get();
Or if you want pagination, you can do:
$aEvents = Event::clientID($client_id)->paginate();
You can also chain it with other methods like you'd do in a eloquent query.
You can read more about model query scopes at http://laravel.com/docs/eloquent#query-scopes