How to encrypt value of DB query in Laravel - laravel

$collection = DB::table('collections')
->join('users','users.id','collections.user_id')
->get([value(md5(encrypt('collections.id'))), 'collections.name', 'collections.category_id', 'users.name as username', 'collections.price', 'collections.image'])->toArray();
return response()->json([
'collection' => $collection,
], 200);
I want to encrypt value of collections.id. It doesn't encrypt value(md5(encrypt('collections.id'))) says
Unknown column
'd0bfdf6d2c0d3a3bb3b9db20b5194e67' in 'field list'

You are currently using the md5 encrypt function on the string collections.id, so you are not encrypting the result of the query but the database column name, which is why you are getting that the column doesn't exist.
By the naming of the $collection variable, I would presume that you are only expecting one result, if so you can do as below otherwise you will have to loop through each row and encrypt the column value.
It's not the nicest way of doing it, it would be much nicer to use casting in a model class if you use models. You can read more about casting in the Laravel documentation https://laravel.com/docs/8.x/eloquent-mutators
Also, a note, if you are only expecting one row, use first() rather than get(), and if you are expecting several rows, use the variable name $collections as it makes the code easier to read as it tells readers that the query will return several collections rather than just one
$collection = DB::table('collections')
->select(['collections.id', 'collections.name', 'collections.category_id', 'users.name as username', 'collections.price', 'collections.image'])
->join('users','users.id','collections.user_id')
->first()
->toArray();
if ($collection) {
$collection['collections.id'] = md5(encrypt('collections.id'));
}
return response()->json([
'collection' => $collection,
], 200);

Related

Count records by field in laravel model

I'm looking the best way to get and array that count existent rows of some eloquent model by a certain field. Guest an Installation model with a type field. Right now Iam using this approach to do it
$typeCount = Installation::select('type', DB::raw('COUNT(*) as count'))
->groupBy('type')
->get()
->mapWithKeys(function($item) {
return [$item['type'] => $item['count']];
})->toArray();
and $typeCount will return an array like this
[
"contrib" => 2,
"official" => 1,
]
Is there a better way or an elegant one????
According to pluck method:
Collection pluck(string $column, string|null $key = null)
Laravel will use the column value of second parameter as key, the column value of first parameter as value:
$typeCount = Installation::select('type', DB::raw('COUNT(*) as count'))
->groupBy('type')
->pluck('count', 'type')
->toArray();

Have select() and/or pluck() been broken in Laravel 6?

The following code does not pluck the name column of the selected user record. Rather, returns the entire row. Before I make a re-creatable example: Is this the expected behaviour here?
I want to explicitly select columns across joins to reduce my JSON payload size, and to return a nested model hierarchy to my clients.
I should add that I'm experiencing the same behaviour when using the pluck() function as well, on the same line. Perhaps I've done something wrong.
There's tons of examples showing this approach with earlier versions of Laravel. Version 6 may have broken this.
$query = Post::whereHas('user.address', function ($query) use ($lat, $lon, $distance) {
$query->distance($lat, $lon, $distance);
})->with([
'user' => function ($query) {
$query->select('name'); // TODO: Report this bug. I've also tried pluck()
},
'user.address' => function ($query) use ($lat, $lon, $distance) {
$query->distance($lat, $lon, $distance);
},
'user.address.city',
'bids' => function ($query) {
$query->orderBy('amount', 'DESC');
},
'bids.user',
'images',
]);
pluck() is a collection method, it executes the query and returns a simple Collection object of the field you specify.
Using pluck() inside your subquery builder executes it (returning nothing, because you are assigning it to nothing) while the $query variable is unmodified and behaves as normal returning all columns.
If you were to dump the value of the pluck() inside this query, you would see it is an array of just names, and because of that, it has no affect on the query itself.
'user' => function ($query) {
dd($query->pluck('name'));
}
select() should work fine in this case. You just need to also provide the relationship key or else it will just return a null object.
'user' => function ($query) {
$query->select(['id', 'name']);
},

Laravel Model Delete Single Record

I'm having trouble getting a chained query to work for deleting a single record in 2 different columns in the user model. On submit, I want to delete the user's record in column A and column B only, nothing else.
DB::table('users')
->where('id', Auth::user()->id)
->select('column_A')->delete()
->select('column_B')->delete()
->update([
'column_A' => 'value',
]);
This actually deletes that user's entire record. I have also tried substituting select for value and then I'll get the error:
calling delete() on string
Thanks!
Try something like this:
DB::table('users')
->where('id', Auth::user()->id)
->update([
'column_A' => '',
'column_B' => ''
]);
I can use delete() only to delete whole rows, but not some information in that row.

Prevent SQL injection for queries that combine the query builder with DB::raw()

In Laravel 4, I want to protect some complex database queries from SQL injection. These queries use a combination of the query builder and DB::raw(). Here is a simplified example:
$field = 'email';
$user = DB::table('users')->select(DB::raw("$field as foo"))->whereId(1)->get();
I've read Chris Fidao's tutorial that it is possible to pass an array of bindings to the select() method, and therefore prevent SQL injection correctly, by using prepared statements. For example:
$results = DB::select(DB::raw("SELECT :field FROM users WHERE id=1"),
['field' => $field]
));
This works, but the example puts the entire query into a raw statement. It doesn't combine the query builder with DB::raw(). When I try something similar using the first example:
$field = 'email';
$user = DB::table('users')->select(DB::raw("$field as foo"), ['field' => $field])
->whereId(1)->get();
... then I get an error: strtolower() expects parameter 1 to be string, array given
What is the correct way to prevent SQL injection for queries that combine the query builder with DB::raw()?
I discovered the query builder has a method called setBindings() that can be useful in this instance:
$field = 'email';
$id = 1;
$user = DB::table('users')->select(DB::raw(":field as foo"))
->addSelect('email')
->whereId(DB::raw(":id"))
->setBindings(['field' => $field, 'id' => $id])
->get();
Eloquent uses PDO under the hood to sanitize items. It won't sanitize items added to SELECT statements.
The mysqli_real_escape_string method is still useful for sanitizing SQL strings, however.
Consider also (or instead) keeping an array of valid field names from the users table and checking against that to ensure there isn't an invalid value being used.
$allowedFields = ['username', 'created_at'];
if( ! in_array($field, $allowedFields) )
{
throw new \Exception('Given field not allowed or invalid');
}
$user = DB::table('users')
->select(DB::raw("$field as foo"))
->whereId(1)->get();

Laravel Eloquent query with optional parameters

I am trying to learn whether or not there is a simple way to pass a variable number of parameters to a query in Eloquent, hopefully using an array.
From what I can find, there doesn't seem to be a way to do this without looping through the Input to see what was set in the request.
Examples here: Laravel Eloquent search two optional fields
This would work, but feels non-Laravel to me in its complexity/inelegance.
Here is where I am, and this may not be possible, just hoping someone else has solved a similar issue:
$where = array("user_id" => 123, "status" => 0, "something else" => "some value");
$orders = Order::where($where)->get()->toArray();
return Response::json(array(
'orders' => $orders
),
200
);
That returns an error of course strtolower() expects parameter 1 to be string, array given.
Is this possible?
Order::where actually returns an instance of query builder, so this is probably easier than you thought. If you just want to grab that instance of query builder and "build" your query one where() at a time you can get it like this:
$qb = (new Order)->newQuery();
foreach ($searchParams as $k => $v) {
$qb->where($k, $v);
}
return $qb->get(); // <-- fetch your results
If you ever want to see what query builder is doing you can also execute that get() and shortly after:
dd(\DB::getQueryLog());
That will show you what the resulting query looks like; this can be very useful when playing with Eloquent.
You can try this:
Method 1:
If you have one optional search parameter received in input
$orders = Order::select('order_id','order_value',...other columns);
if($request->has(user_id)) {
$orders->where('orders.user_id','=',$request->user_id);
}
//considering something_else as a substring that needs to be searched in orders table
if($request->has('something_else')) {
$orders->where('orders.column_name', 'LIKE', '%'.$request->something_else.'%');
}
$orders->paginate(10);
Method 2:
If you have multiple optional parameters in input
$orders = Order::select('columns');
foreach($input_parameters as $key => $value) {
//this will return results for column_name=value
$orders->where($key, $value);//key should be same as the column_name
//if you need to make some comparison
$orders->where($key, '>=', $value);//key should be same as the column_name
}
return $orders->paginate(15);

Resources