Laravel weird behavior orderByRaw(field()) - php

I'm creating a multi roll registration system. And I'm trying to list all existing rolls. These have to be sorted ascendingly on the amount of permissions they have assigned to them. (in this example: User first, Moderator second and Admin third)
I cannot define the rolls in the code because new rolls can be created and existing rolls can be deleted. (exept for the user and admin roll)
I retrieve the permission count of all the available rolls and place them in a array with the id of the roll.
the array per_count returns the following ids:
2, 4, 3
Id's:
2 = User
3 = Admin
4 = Moderator
However, When I execute the following query:
Roll::orderByRaw("FIELD(id, ?)", array($per_count))->get()
It reverses the order and I get
3 Admin
4 Moderator
2 User
Controller:
public function index()
{
// Check if user is authorized to use this action, else redirect to login page
$this->authorize_action(__FUNCTION__, $this->classname);
foreach (Roll::all() as $roll) {
$rollpermission['id'] = $roll->id;
$rollpermission['count'] = $roll->permissions->count();
$permission[] = $rollpermission;
}
$this->array_sort_by_column($permission, 'count');
$per_count = array();
foreach ($permission as $per) {
$per_count[] = $per['id'];
}
$foo = implode(', ', array_fill(0, count($per_count), '?'));
return view('roll')
->with('roll', Roll::orderByRaw("FIELD(id, " . $foo . ") desc", array_reverse($per_count))->get());
}
I managed to get it working correctly with the array_reverse function.
However it is sloppy and should not be necessary. And I cant find the reason why the query reverses the results.
Can somebody explain to me why the results are reversed? Thanks

orderByRaw() expects the second parameter to be an array of bindings, not an array to implode for one binding. But on the other hand, if you implode it, it will be passed in as one string '2, 3, 4', when you need a comma delimited list of numbers. Do this instead:
Roll::orderByRaw("FIELD(id, " . implode(", ", $per_count) . ")")->get();
Which will yield:
select * from `[table_name]` order by FIELD(id, 2, 3, 4)
Also, you may want to check the difference between roll and role before you code too much ;)

Related

Laravel Collections - compare and check how many times a word exits in a collection

i am new to Laravel and i am trying to do the following:
i have 2 Collections: "requirements" and "skills":
$req = collect([
'Installation',
'Konfiguration',
'Automatisierung'
]);
$skills = collect([
'Engineering Team',
'Installation',
'Konfiguration',
'Konfiguration',
'Automatisierung',
'Security',
'Automatisierung',
'Automatisierung',
'Automatisierung'
]);
I am trying the following: I want to take the first item of $req ("Installation") and count how many times it exists in the $skills collection. Then i need to take the second value of the $req collection and do the same thing. At the end i need to have some output like:
Installation exits 2 times
Konfiguration exists 2 times
Automatisierung exists 3 times
all others -> 0 (or even ignoring it)
i thought about iterating with nested for loops and if clauses and so on like "classic" coding, but isnt there something in laravel to make it nicer? I tried like contains and so on but its like "if" clause.
Thanks a lot in advance
You could use countBy of laravel, it counts depending on a function
Learn more about countBy here
This code would return another array with the 3 sentences you've said
$req->map(function($i) use ($skills) {
$count = $skills->countBy(function ($skill) use ($i) {
return $skill == $i;
});
if (isset($count[1])) {
return $i . " exits ". $count[1] ." times";
} else {
return $i . " doesn't exits";
}
});
You can also just do $skills->countBy() that it would return an collection with key beeing the name of the skill and the value beeing the number of times it appears

How to implement tree like structure in mysql and laravel

A question struck in my mind for 2 days and wondering whether it is possible to implement this type of tree structure in laravel and MySQL.
(First, take a look at the image attached. Thanks)
Suppose our platform uses refer system, and initially, a user 'A' join. Now, this user 'A' further refers 3 persons 'B','C','D'. Now, the total refer on A is 3 (because it refers 3 persons).
Now, let B further refers 'E','F' and 'C' further refers 'G','H', 'I' and 'D' refers 0. So, now refer of each person is "D = 0", "C = 3", "B = 2". and these refers will also add up on "A". So, it has "A = 8".
Now, 'G' refers 'J', so 'G' gets +1 and 'C' also gets +1 and 'C' is referred by 'A', so 'A' also gets +1. Now, total refer to each person is :
"j = 0","G=1","H=0","I=0", "D=0","E=0","f=0","B=2","C=4 (beacuse G refers J also)","A=9(beacuase 9 childers are refered by him)"
The chain continues until A gets total refer of 40.
In simple, if a person refers another person then it will get +1 and it's parent whom he gets refer also get +1 and so on until parent reaches 40, the chain continues.
I know, this is One-Many relationship between a user and refer and we can use a pivot table, but, How can we implement this type of logic. Give me some hints. Thanks.
I have written out something that should hopefully help you with this, using a while loop.
public function totalReferredBy(User $user)
{
// Initialise the queue to contain only the provided user
$queue = collect([$user]);
// This collection will eventually contain all of the "child"/referred users
$results = collect();
while ($queue->isNotEmpty() > 0) {
// Run a where in query to select all the referred users of the users in the queue.
$referredUsers = User::whereIn('referred_by', $queue->pluck('id'))->get();
// Merge the referredUsers we have found in the database with the results collection, so we can later count.
$results = $results->merge($referredUsers);
// Make the referredUsers we have just found in the database, the new queue. If the query did not return any
// referred users, the queue count would be 0 and the loop will exit.
$queue = $referredUsers;
}
// Now we should have all of the given user's "children" and "children of children" in the $results collection.
// We just need to return the count of that collection to get the total number of users that have been referred.
return $results->count();
}
You can use it like this:
$user = User::find(1);
$totalReferred = $this->totalReferredBy($user);
Then if your application does something when the user reaches 40 or more referred, you can just do:
if ($this->totalReferredBy($user) > 40) {
// Do something
}
This assumes that you have a referred_by column on the users table.

SilverStripe get by id in exact order

Suppose you have an array of keys
$key_list = array(3, 6, 2);
And you want to retrieve records from a certain table, using these keys as identifiers (WHERE ID = id_from_key_list)
Foo::get()->byIDs($key_list);
This returns the rows with the ID's that match those in $key_list (3, 6 and 2) but not in that order.
How do we maintain the same order when retrieving these items?
What you might need to do is to run a foreah loop of the IDs and push each Foo Object into an ArrayList
$aFooList = ArrayList::create();
foreach ($key_list as $key_list_id){
$oFoo = Foo::get()->byID($key_list_id);
$aFooList->push($oFoo);
}
return $aFooList;

Symfony: Delete all the records in a table who have the id in the string in table's column

[Please note that I do not have code for this problem, I need code, I have tried to explain it the best way, and if you can help, it will be great]
so here is the deal, I have a field in the table named "order" for every user. The main job of the user is to bring other users to the system and when they bring a new user their id is sticked to (concated with) the referring user's id and stored in his "order field"
for eg.
user 'a' has id 31. 'a' brings in 'b' whose is assigned 32, now b's therefore b has the value: '31-32' stored in his 'order' field. simililarly if b brings in 'c' whose id is 35, the order for c will be: '31-32-35' and it goes so on.
Now when I delete 'a' I want ALL the users who have his id in their order fields, that is if i decide to delete 'a' in this above field, all the users should be deleted from he system too!
I want to do this via symfony controller, and I think that can be done by findAll() function in symfony but I have no clue how to use it.
Please help, I am really stuck!
I did by using a parent field in each table for the user:
and here is the code if such thing arises for someone:
<?php
$repo = $em->getRepository('SystemBundle:Distributor');
$temp = $slug;
$pd = $repo->findAll();
for ($i = 1; $i <= count($pd); $i++) {
$u = $repo->findOneBy(['parent' => $temp]);
if ($u) {
$temp = $u->getId();
$em->remove($u);
$em->flush();
} else {
break;
}
}
$dis = $repo->findOneBy(["id" => $slug]);
$em->remove($dis);
$em->flush();
Using for loop it was possible to do this

Get current user access level in Joomla 2.5

In Joomla 2.5.14, I have a script that gets the current user group id, like:
$groups = $user->get('groups');
foreach($groups as $group) {
echo "<p>Your group ID is:" . $group . "</p>";
};
Now, I need to count the number of articles this user is able to read, given his access level.
For that, I need to select the access level from the viewlevels table, that looks like this:
id title rules JSON encoded access control.
1 Public [1]
2 AccessA [13,8,16,17]
3 AccesssF [8]
4 AccessD [14,8]
6 AccessB [8,16,17]
7 AccessC [8,17]
So, for example, Group 17 may read the articles in AccessA, AccessB and Access C.
I tried the following query, but it isn't selecting any rows:
$query="SELECT * FROM xmb9d_viewlevels WHERE rules LIKE '%.$group.%'";
How can I select all the acess levels for the current user group and then count the number of articles he's able to read?
Thanks for helping!
First
https://github.com/joomla/joomla-cms/blob/master/libraries/joomla/access/access.php#L285
JAccess::getGroupsByUser($userId, $recursive = true)
Will get you the groups a user is matched to including via inheritance (unless you make $recursive false)
https://github.com/joomla/joomla-cms/blob/master/libraries/joomla/access/access.php#L402
JAccess::getAuthorisedViewLevels($userId) will give you all the view levels a user is allowed to see as an array.
If you do
$allowedViewLevels = JAccess::getAuthorisedViewLevels($userId);
if nothing else you could do
$implodedViewLevels = implode(',', $allowedViewLevels);
....
$query->select($db->quoteName('id'))
->from('#__content')
->where($db->quoteName('access') . 'IN (' . $implodedViewLevels . ')';
....
(not tested but you get the general idea).
In joomla always try to let the api do the work for you rather than fight with it.
I think you just need to remove the periods from within the LIKE clause. Such as:
$query="SELECT * FROM xmb9d_viewlevels WHERE rules LIKE '%$group%'";
Also, to make it not specific to the database you should substitute #__ (Note: it's two underscores) for the table prefix:
$query="SELECT * FROM #__viewlevels WHERE rules LIKE '%$group%'";

Categories