cakephp - triggered - after execution of query - php

How can change output one of model in all queries?
This means that queries run on this model, then go to a specific function.
for example, in user model, how remove password field for all queries
thanks

Add the following to your model:
public function afterFind($results, $primary = false){
foreach ($results as $key => $val) {
unset($results[$key][$this->alias]['password']);
}
return $results;
}
This should also work:
public function afterFind($results, $primary = false){
return Hash::remove($results, '{n}.'.$this->alias.'.password');
}

Related

Laravel Nova Filter using joined table

I am trying to build a Laravel Nova Filter for my Model "Question", based on data from two different tables. I have figured out the exact SQL query I would need to use, but cannot figure out how to use it in the apply() method of the Nova filter.
Table "questions" columns:
id, ...
Table "themes" columns:
id, question_id, theme_id
The SQL Query I am trying to use:
SELECT questions.*
From questions
Inner JOIN themes on questions.id=themes.question_id
WHERE themes.theme_id = 3 (value taken from the Nova Filter options)
My Filter in Laravel Nova QuestionsThemeFilter.php:
class QuestionsThemeFilter extends BooleanFilter
{
public $name = 'filter by theme';
public function apply(Request $request, $query, $value) {
// This is what I'm missing...
}
public function options(Request $request) {
$themes = Themes::all();
$themesArray = array();
foreach($themes as $item) {
$themesArray[$item['title']] = strval($item['id']);
}
return $themesArray;
}
}
So, how exactly should I do this?
Other question: Since I am a beginner in Laravel, how exactly should I start debugging this? Using dd() doesn't work (the filter just breaks) and I don't know how I can debug this. Is there a way to dump some values from the apply method (for example the $value)?
Thanks in advance for any help, highly appreciated :-D
Check the comments in the code
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
class QuestionsThemeFilter extends BooleanFilter
{
public function apply(Request $request, $query, $value) {
// Since you are using BooleanFilter $value will be an associate array with true/false value
$selectedThemes = Arr::where($value, function ($v, $k) {
return $v === true;
});
$selectedThemeIds = array_keys($selectedThemes)
// For debugging print some logs and check
Log::info($value)
Log::info($selectedThemeIds);
return $query->join('themes', 'questions.id', '=', 'themes.question_id')
->whereIn('themes.theme_id', $selectedThemeIds);
// If you are using normal filter then below code will be enough
/*
return $query->join('themes', 'questions.id', '=', 'themes.question_id')
->where('themes.theme_id', $value);
*/
}
public function options(Request $request) {
// You can use Laravel collection method pluck
return Themes::pluck('id', 'title')->all();
}
}
References:
Pluck
Boolean Filter
Arr::where

Having difficulties displaying all content on my wishlist table

I am trying to retrieve the data on my wishlist table, for a particular user, so far it only retrieves the first data on the table, just returning one array instead of the three in the table with same user id
public function getWishlistByUserId($id){
$wishlists = Wishlist::where('userId', $id)->get();
foreach($wishlists as $wishlist){
$products = Product::where('id', $wishlist->productId)->get();
return $products;
}
}
It happens because the foreach loop returns a value during the first iteration. Place your return statement outside the loop. Also you could improve your performence by making use of relationships.
An example could be:
// Product.php
public function wishlists()
{
return $this->hasMany(Wishlist::class);
}
// Your method
public function getWishlistByUserId($id)
{
return Product::whereHas('wishlists', function ($query) use ($id) {
$query->where('userId', $id);
});
}
Ideally this is n+1 situation
So i will suggest to use laravel relationship like:
in your whishlist model
public function product(){
return $this->hasMany(Product::class,'productId','id');
}
get data with relationship
public function getWishlistByUserId($id){
$wishlists = Wishlist::with('product')->where('userId', $id)->get();
}
I was finally able to get it working this way, i just pushed the result into an array, and then returned it outside the loop, thanks everyone for your help
public function getWishlistByUserId($id){
$wishlists = Wishlist::where('userId', $id)->get();
$wishlist = [];
foreach($wishlists as $wish){
$product = Product::where('id', $wish->productId)->get();
array_push($wishlist, $product);
}
return $wishlist;
}

Laravel Query Builder returning all rows despite 'where' statement

I'm making a search service using the following blog post:https://m.dotdev.co/writing-advanced-eloquent-search-query-filters-de8b6c2598db
This seems to work except for the fact that my queries are returning every row in the table rather than specific ones.
For example, I have a filter such as this:
public static function apply(Builder $builder, $value)
{
return $builder->whereHas('items', function ($q) use ($value) {
$q->where('item_id', $value);
});
}
This works on the items relationship on my model. Running this query conventionally seems to work, but it fails in relation to the code in the above blog post.
The same is true for an even simpler query:
public static function apply(Builder $builder, $value)
{
return $builder->where('name', $value);
}
When I run my test it just gives me every single item in the table rather than those matching my condition.
My search code looks like this and I can't see any obvious errors:
public static function search(Request $filters)
{
$query =
static::applyDecoratorsFromRequest(
$filters,
(new User)->newQuery()
);
return static::getResults($query);
}
private static function applyDecoratorsFromRequest(Request $request, Builder $query)
{
foreach ($request->all() as $filterName => $value) {
$decorator = static::createFilterDecorator($filterName);
if (static::isValidDecorator($decorator)) {
$query = $decorator::apply($query, $value);
}
}
return $query;
}
Any help appreciated!
it's because you should use local scopes instead : https://laravel.com/docs/5.8/eloquent#local-scopes
public static function scopeWhereItem(Builder $query, $value)
{
return $query->whereHas('items', function (query) use ($value) {
$query->where('item_id', $value);
});
}
Then in your controller :
// Initiate the queryBuilder
$query = YourModel::query();
// your request is like : ['item' => '2'];
foreach($request->all()sas $filterName => $value) {
// Build the scope Name (whereItem())
$scope_name = 'where' . ucFirst($filterName);
$query->$scopeName($value);
}
$results = $query->get();
you can add some checks if the method 'scope' . ucFirst($scopeName) exists if you want
it will generate a query like this : YourModel::query()->whereItem(2)->get()'

get many to many with where clause in laravel

I Have this 3 tables like below :
Tools
Parts
Part_details
it is my the table structure :
Tool -> has many -> parts. part -> has many->part_details.
Tool : id*, name; Parts : id*, name, tool_id; part_details: id, part_id, total;
Question :
Using laravel Model, how can I get Tool with One part that has biggest total on parts_details ??
// Tool Model
public function parts(){
return $this->hasMany(Part::class);
}
// Part Model
public function part(){
return $this->belongsTo(Tool::class);
}
public function part_details(){
return $this->hasMany(PartDetail::class);
}
// PartDetail Model
public function part(){
return $this->belongsTo(Part::class);
}
Now query the Tool model
$tools = Tool::with('parts')->withCount('parts.part_details')->get();
$toolWithMaxCount = $tools->filter(function($tool) use ($tools){
return $tool->parts->max('par_details_count') === $tools->max('parts.part_details_count');
})->first();
You can improve this with adding some raw bindings to optimise it. I think you got the idea.
Tool model
public function parts() {
return $this->hasMany('App\Part');
}
Part Model
public function details() {
return $this->hasMany('App\PartDetail');
}
public function tool() {
return $this->belongsToMany('App\Tool');
}
Detail Model
public function part() {
return $this->belongsToMany('App\Part');
}
Controller
$tools = Tool::with('parts', 'parts.details')
->find($id)
->max('parts.part_details');
Use the the hasManyThrough Relationship to get the all part details related to tool and then you can check the one by one record and get the highest total of the tool part.
// Tool Model
public function partsdetails()
{
return $this->hasManyThrough('App\PartDetail', 'App\Part','tool_id','part_id');
}
In Your controller
$data = Tool::all();
$array = [];
if(isset($data) && !empty($data)) {
foreach ($data as $key => $value) {
$array[$value->id] = Tool::find($value->id)->partsdetails()->sum('total');
}
}
if(is_array($array) && !empty($array)) {
$maxs = array_keys($array, max($array));
print_r($maxs);
}
else{
echo "No Data Available";
}

Unable to assign variable value in model constructor

I am playing with Laravel models and I need one to return a value that is not in the db table but it comes by running a model method. This method runs a query that groups and count grouped results.
The model method works just fine but I don't seem to be able to pre-fill the $quantity variable within the constructor with something different than 0.
So this is an excerpt of the model:
public $quantity;
function __construct($attributes = array(), $exists = false) {
parent::__construct($attributes, $exists);
$this->quantity = $this->quantity();
}
public function quantity()
{
$query = DB::table('carts_shopping')
->select('cart_id', DB::raw('COUNT(*) AS quantity'))
->where('cart_id',$this->cart_id)
->groupBy('cart_id')
->first();
return ($query) ? $query->quantity : 0;
}
While this is how I am trying to retrieve the results from controller:
$cartitems = Auth::user()->cartshopping;
foreach ($cartitems as $cartitem)
{
echo $cartitem->name;
echo $cartitem->quantity;
}
As you may guess 'cartshopping' comes from the user model being related with the model excerpt I pasted.
I also noticed that quantity() method gets called and it returns 0 all the time as if $this->cart_id was empty and, changing $this-cart_id with a real value the query itself doesn't even get executed.
Thanks a lot for any suggestion you guys can share.
Have you tried accessing the properties using $this->attributes?
public $quantity;
function __construct($attributes = array(), $exists = false) {
parent::__construct($attributes, $exists);
$this->quantity = $this->quantity();
}
public function quantity() {
$query = DB::table('carts_shopping')
->select('cart_id', DB::raw('COUNT(*) AS quantity'))
->where('cart_id', $this->attributes['cart_id'])
->groupBy('cart_id')
->first();
return ($query) ? $query->quantity : 0;
}
Failing that, you could try using the Eloquent accessors, which would be the best way to do it. This would make it dynamic as well, which could be useful.
class YourModel {
// Normal model data here
public function getQuantityAttribute() {
$query = DB::table('carts_shopping')
->select('cart_id', DB::raw('COUNT(*) AS quantity'))
->where('cart_id', $this->attributes['cart_id'])
->groupBy('cart_id')
->first();
return ($query) ? $query->quantity : 0;
}
}

Categories