Is there any way to explode a table inside query? - laravel

I have this table in my database.
ยป roles, and have content of 0,0,0,0,0,0
In this table i store user permissions. Example if he is an administrator it can be 0,0,0,0,0,1 or if he is an moderator and an administrator in the same time it can be 0,0,0,1,0,1.
But i don't know how i can show them in a query separated.
Example for administrator query only last parameter from that list 0,0,0,0,0,0.
So for it i have to do a explode in the query but i don't know how to do this.
I tried something like that to see if i can get the tables and explode it before query execute.
$query = User::where(
function($results) {
dd($results);
foreach($results as $result) {
print($result);
}
})->first();
Someone have an idea how i can do this?

if you have a fixed pattern you can "explode" it easily.
for example:
$result = "0,0,0,0,0,1"; // your data in for is string so:
$permission = explode(",",$result); // convert to an array.
// outpult is:
print ($permission);
[0 , 0 , 0 , 0 , 0 , 1 ];
print ($permission[5]);
// output is:
1
now you can access each cell of the array.
but It's not a clear way to make permission and role.
I suggest you use the different tables with different relationships.

I think this is not convenient way of implementing roles and permissions. If you are using Laravel then there is already a way to implement permissions in the form of gates and policies.
or you can implement it through a package like
Spatie Package

This might help it will return permissions ending with 1
User::where(function ($builder){
$builder->where('permission', 'regex','%1');
});

as a simple and appropriate solution,
you can also write your, where condition as below
->whereRaw("SUBSTRING_INDEX(SUBSTRING_INDEX(permission_column_name, ',', 6), ',', -1) = 1")
as you can see in the above code,
With SUBSTRING_INDEX(permission_column_name, ',', 6) function we will be able to extract everything up to the sixth value in your column separated by a comma.
Because SUBSTRING_INDEX() function also allows us to use negative values to extract fields counting from the right, we are using this ability to extract the rightmost field containing the last value of string with -1.
using the same above method you can also find any value available at any position as required in the given comma-separated string in a column.

Assuming that each user has a role, you can add some methods to the User model to handle permissions.
Class User extends Authenticatable {
private function getPermissions(): array {
return explode(',', $this->role)
}
public function isAdministrator(): bool {
$permissions = $this->getPermissions();
return $permissions[5] == 1;
}
public function isModerator(): bool {
$permissions = $this->getPermissions();
return $permissions[3] == 1;
}
}
Now you can use it in your code. Like this:
$user = auth()->user() // Or User::find($id) ...
if ($user->isAdministrator() || $user->isModerator()) {
// Do something
}

Related

Laravel query builder search by status

In my project, the user can filter the data according to 3 criteria (declared, in progress, finished).
I pass string, in the url parameters [-1,0,1], in order to obtain the active filters. the statuses are defined according to several data coming from different columns of the database, in other words the information is not stored raw in the database.
How can I retrieve filtered data using Query Builder?
$ret = array_filter(explode(',',', $args), 'is_numeric');
$declared = in_array(1, $ret);
$progress = in_array(-1, $ret);
finished = in_array(0, $ret);
if ($declared == false && $progress == false && $finished == false) {
// do the treatment for this case....
}
If I have to deal with all the cases like that, I don't think it's very optimized.
Do you have an idea?
If I understand correctly you have a url like this /your-link?status=n, where n is an int from -1 to 1.
Now, in your controller you can do something like this:
public function yourFunction(Request $request)
{
if (in_array($request['status'], [-1, 0, 1])) {
$data = DB::table('your-table')->where('status', $request['status'])->get();
}
}
I'd recommend you to take a look at pipelines and try to use them with Eloquent or Query builder.
Check out this tutorial and see for yourself how you can implement a solution.

Merging multiple objects which uses same id

I'm trying to merge multiple objects (like Receipts, Reports, etc) with Collection->merge().
This is the code I used:
$receipts = Receipt::all();
$reports = Report::all();
$collection = $receipts->merge($reports);
This is the result:
The above screenshot shows two elements, but the third element is missing because it has the same id (id: "1") as the first one. What I'm trying to achieve is to display all three of them as a collection.
EDIT:
I need the result to be objects (collection) because I also use the code on my view, where I check the class to determine what to display. Also, I use this function to sort the objects in the collection.
$collection->sort(function($a, $b)
{
$a = $a->created_at;
$b = $b->created_at;
if ($a === $b) {
return 0;
}
return ($a > $b) ? 1 : -1;
});
I know that this is an old question, but I will still provide the answer just in case someone comes here from the search like I did.
If you try to merge two different eloquent collections into one and some objects happen to have the same id, one will overwrite the other. I dunno why it does that and if that's a bug or a feature - more research needed. To fix this just use push() method instead or rethink your approach to the problem to avoid that.
Example of a problem:
$cars = Car::all();
$bikes = Bike::all();
$vehicles = $cars->merge($bikes);
// if there is a car and a bike with the same id, one will overwrite the other
A possible solution:
$collection = collect();
$cars = Car::all();
$bikes = Bike::all();
foreach ($cars as $car)
$collection->push($car);
foreach ($bikes as $bike)
$collection->push($bike);
Source: https://medium.com/#tadaspaplauskas/quick-tip-laravel-eloquent-collections-merge-gotcha-moment-e2a56fc95889
I know i'm bumping a 4 years old thread but i came across this and none of the answers were what i was looking for; so, like #Tadas, i'll leave my answer for people who will come across this. After Looking at the laravel 5.5 documentation thoroughly i found that concat was the go-to method.
So, in the OP's case the correct solution would be:
$receipts = Receipt::all();
$reports = Report::all();
$collection = $receipts->concat($reports);
This way every element in the Report collection will be appended to every element in the Receipts collection, event if some fields are identical.
Eventually you could shuffle it to get a more visual appealing result for e.g. a view:
$collection->shuffle();
Another way to go about it is to convert one of your collections to a base collection with toBase() method. You can find it in Illuminate\Support\Collection
Method definition:
/**
* Get a base Support collection instance from this collection.
*
* #return \Illuminate\Support\Collection
*/
public function toBase()
{
return new self($this);
}
Usage:
$receipts = Receipt::all();
$reports = Report::all();
$collection = $receipts->toBase()->merge($reports);
You could put all collections in an array and use this. Depends on what you want to do with the collection.
$list = array();
$list = array_merge($list, Receipt::all()->toArray());
$list = array_merge($list, Report::all()->toArray());

Codeigniter - How to get values as array to use in next select with where_not_in

I have three tables; user, car and user_x_car. user_x_car holds users who own car; user_id and car_id are stored. I want to get users who don't own a car as follows:
$car_owner = $this->db->select()->from('user_x_car')->get()->result();
for ($i = 0; $i < count($car_owners); $i++)
$car_owner_id[$i] = $car_owner[$i]->user_id;
$non_car_owner = $this->db->select()->from('user')->where_not_in('id', $car_owner_id)->get()->result();
I get what I want, however, is there any way to bypass the for loop in the middle which creates and array of id's selected in the first select. Is there any way to get array of selected user_ids directly?
you can do it by two queries like
first one get all ids from user_x_car table
$temp1=array();
$temp=$this->db->distinct()->select('user_id')->get('user_x_car')->result_array();
then from user table fetch those users who have no cars
foreach($temp as $each)
{
array_push($temp1,$each['user_id']);
}
$rs=$this->db->where_not_in('id',$temp1)->get('user');
if($rs->num_rows()>0)
{
$data=$rs->result_array();
print_r($data);die;
}
$data will print all users who have no car. Please let me know if you face any problem.
function get_unread_notifications_ids()
{
//get unread notifications ids
$this->db->select('GROUP_CONCAT(fknotification_id) as alll');
$this->db->from("te_notification_status_tbl");
$this->db->where('read_status',0);
$ids=$this->db->get()->row();
return $idss=str_replace(",","','",$ids->alll);
}
and second function like this:
function get_unviewed_photos_events(){
$idss = $this->get_unread_notifications_ids();
$this->db->select('img.*',False);
$this->db->from("te_notifications_tbl notif");
$this->db->join('te_images_tbl img','img.id=notif.reference_id','LEFT OUTER');
$this->db->where("notif.id IN('".$idss."')");
$rslt = $this->db->get()->result_array();
return $rslt;
}
Query
$non_car_owner = $this->db->query('SELECT user.*
FROM user LEFT JOIN user_x_car ON user_x_car.id=user.id
WHERE table2.id IS NULL')->result();
Here users who are not on the table user_x_car
foreach($non_car_owner as $user){
echo $user->user_id;
}

how to make query with substr in eloquent (laravel 4)?

I have this query:
select substr(id,1,4) as id
from meteo.a2012
group by substr(id,1,4)
I just want to take first 4 numbers to my id row, but I'm trying to do in eloquent, how I do?
Thanks.
You need to use raw expressions so you can use special functions like that.
Model::select(DB::raw('substr(id, 1, 4) as id'))->groupBy(DB::raw('substr(id, 1, 4)'))->get();
Where Model is your Eloquent model you want to run the query on.
G'day
I was able to do it like this in Laravel
$data = DataModel::selectRaw("SUBSTRING_INDEX(EMAIL_COLUMN, '#', 1) as 'alias'")->get();
As a result, I get the alias name (address) from the mail address#domain.net
$ids = Model::get(['id']);
foreach ($ids as $str)
{
$str->id =substr($str->id,1,4);
}
return $ids;

Codeigniter Pagination: Run the Query Twice?

I'm using codeigniter and the pagination class. This is such a basic question, but I need to make sure I'm not missing something. In order to get the config items necessary to paginate results getting them from a MySQL database it's basically necessary to run the query twice is that right?
In other words, you have to run the query to determine the total number of records before you can paginate. So I'm doing it like:
Do this query to get number of results
$this->db->where('something', $something);
$query = $this->db->get('the_table_name');
$num_rows = $query->num_rows();
Then I'll have to do it again to get the results with the limit and offset. Something like:
$this->db->where('something', $something);
$this->db->limit($limit, $offset);
$query = $this->db->get('the_table_name');
if($query->num_rows()){
foreach($query->result_array() as $row){
## get the results here
}
}
I just wonder if I'm actually doing this right in that the query always needs to be run twice? The queries I'm using are much more complex than what is shown above.
Unfortunately, in order to paginate you must know how many elements you are breaking up into pages.
You could always cache the result for the total number of elements if it is too computationally expensive.
Yeah, you have to run two queries, but $this->db->count_all('table_name'); is one & line much cleaner.
Pagination requires reading a record set twice:
Once to read the whole set so that it can count the total number records
Then to read a window of records to display
Here's an example I used for a project. The 'banner' table has a list of banners, which I want to show on a paginated screen:
Using a public class property to store the total records (public $total_records)
Using a private function to build the query (that is common for both activities). The parameter ($isCount) we pass to this function reduces the amount of data the query generate, because for the row count we only need one field but when we read the data window we need all required fields.
The get_list() function first calls the database to find the total and stores it in $total_records and then reads a data window to return to the caller.
Remember we cannot access $total_records without first calling the get_list() method !
class Banner_model extends CI_Model {
public $total_records; //holds total records for get_list()
public function get_list($count = 10, $start = 0) {
$this->build_query();
$query = $this->db->get();
$result = $query->result();
$this->total_records = count($result); //store the count
$this->build_query();
$this->db->limit($count, $start);
$query = $this->db->get();
$result = $query->result();
return $result;
}
private function build_query($isCount = FALSE) {
$this->db->select('*, b.id as banner_id, b.status as banner_status');
if ($isCount) {
$this->db->select('b.id');
}
$this->db->from('banner b');
$this->db->join('company c', 'c.id = b.company_id');
$this->db->order_by("b.id", "desc"); //latest ones first
}
And now from the controller we call:
$data['banner_list'] = $this->banner_model->get_list();
$config['total_rows'] = $this->banner_model->total_records;
Things get complicated when you start using JOINs, like in my example where you want to show banners from a particular company! You may read my blog post on this issue further:
http://www.azmeer.info/pagination-hitting-the-database-twise/

Resources