cannot filter eloquent collection with variable - php

I can't filter a collection with a variable:
$sections = Section::all();
$courses = array("MATH282", "MATH201" , "GEOM202");
foreach ($courses as $course)
{
$sections1 = $sections->filter(function($foo)
{
if ($foo->course == $course ) {
return true;
}
});
}
The filter works if the condition is a string. Everything else works.

You are missing use() function in filter closure function. Your code should be as:
$sections = Section::all(); $courses = array("MATH282", "MATH201" , "GEOM202");
foreach ($courses as $course) {
$sections1 = $sections->filter(function($foo) use($course) {
if ($foo->course == $course ) {
return true;
}
});
}

Related

Create Multi level menu php Laravel

I am doing the function of creating dynamic menu in laravel and I have the tbl_menu table as below:
menu_id parent_id menu_name link order
1 0 Level_1 url_1 1
2 0 Level_1 url_2 1
3 2 Level_2 url_3 2
4 2 Level_2 url_4 3
5 4 Level_3 url_5 3
I want the result to be an array that looks like this:
-Level_1
-Level_2
-Level_2
-Level_1
_Level_2
_Level_2
_Level_3
My code is as follows:
public function SelectAllChildeLv1ByParentId($id){
$result = DB::table('tbl_menu')->where('parent_id', $id)
->orderBy('order', 'asc')->get();
return $result;
}
public function SelectAllMenuParent(){
$result = DB::table('tbl_menu')->where('parent_id', 0)
->orderBy('order', 'asc')->get();
return $result;
}
public function getMenuChildren($listParent, $step = 3)
{
$results = [];
if ($step > 0) {
$step--;
if($listParent) {
foreach($listParent as $index => $parent) {
$listChild = $this->SelectAllChildeLv1ByParentId($parent->menu_id);
$listChild1 = $this->getMenuChildren($listChild, $step);
$results[$index] = $parent;
$results[$index]->menu_child = $listChild1;
}
}
}
return $results;
}
public function getAllMenus() {
$allMenuParent = $this->SelectAllMenuParent();
$results = $this->getMenuChildren($allMenuParent);
return $results;
}
The results are correct but are running too many queries. I want to optimize it but haven't figured it out yet.
Thanks for any help.
try :
public function get()
{
$menu = DB::table('tbl_menu')
->orderBy('order', 'asc')->get();
$parents = $menu->where('parent', 0);
$items = self::tree($parents, $menu);
return $items;
}
public function tree($items, $all_items)
{
$data_arr = array();
foreach ($items as $i => $item) {
$data_arr[$i] = $item->toArray(); //all column attributes
$find = $all_items->where('parent', $item->id);
//$data_arr[$i]['tree'] = array(); empty array or remove if you dont need it
if ($find->count()) {
$data_arr[$i]['tree'] = self::tree($find, $all_items);
}
}
return $data_arr;
}
Use eloquent.
First, add this to the 'tbl_menu' model:
protected $with = ['children'];
public function children()
{
return $this->hasMany(YOUR_CLASS_NAME::class, 'parent_id', 'id')->orderBy('order');
}
Now if you call the main menu, and all children.
etc: YOUR_CLASS_NAME::where('parent_id', 0)->get().
Then you can use recursion when calling
public $menus = [];
public $level = 0;
public function getMenus($request){
$menus = YOUR_CLASS_NAME::where('parent_id', 0)
->orderBy('order')
->get();
$this->recursiveMenu($menus);
return $this->menus;
}
public function recursiveMenu($menus, $lvl = 0){
foreach ($menus as $key => $menu) {
$this->menus[$menu->id] = str_repeat('—', $lvl).' '.$menu->title;
if($menu->children){
$this->level++;
$this->recursiveMenu($menu->children, $this->level);
}
if (!isset($menu[$key+1])) {
$this->level--;
}
}
}

How to call a named function as a callback in laravel?

I got two functions in my model:
function getPersonsByGroup($groupId, $callback) {
$group = StutGroup::where('stg_id', $groupId)->get();
$persons = [];
foreach($group as $gr) {
foreach($gr->students as $stud) {
$persons[] = $stud->person;
}
}
return $callback(collect($persons));
}
function joinStudentsToPersons($person) {
return $person->each(function ($pers) {
$pers->student = \DB::connection('pgsql2')->table('students')->where('stud_pers_id', $pers->pers_id)->get();
});
}
I'm trying to call the function getPersonsByGroup in my controller passing the reference to the callback as follows:
$students = $studGroup->getPersonsByGroup($request->group, $studGroup->joinStudentsToPersons);
But if I pass an anonymous function to the getPersonsByGroup everything works well:
$students = $studGroup->getPersonsByGroup($request->group, function($person) {
return $person->each(function ($pers) {
$pers->student = \DB::connection('pgsql2')->table('students')->where('stud_pers_id', $pers->pers_id)->get();
});
});
What am I doing wrong?
The solution to your problem, if you want to keep this kind of structure, is to make the method return the closure like so:
function joinStudentsToPersons() {
return function ($person) {
$person->each(function ($pers) {
$pers->student = \DB::connection('pgsql2')->table('students')
->where('stud_pers_id', $pers->pers_id)
->get();
});
};
}
And then call it like:
$students = $studGroup->getPersonsByGroup($request->group, $studGroup->joinStudentsToPersons());

how to add custom(new) column in laravel pagination collection result

I am creating an API and I want to add extra column in the result of pagination query. For example I have price and discount in my database. I want to send discounted_price column with result set.
Here is what I have tried so far:
Controller:
$products = Products::latest()->paginate(10);
if (! empty($products)) {
$final_prod = [];
foreach ($products as $product) {
$final_prod[] = $product->asFilterJson();
}
$data['products'] = $final_prod;
$data['status'] = 200;
} else {
$data['error'] = "No product available";
}
and in my Products model I have
public function asFilterJson() {
$json = [];
$json['id'] = $this->id;
$json['title'] = $this->title;
$json['category_id'] = $this->category_id;
$json['price'] = $this->price;
$json['description'] = $this->description;
$json['quantity'] = $this->quantity;
$json['discount'] = $this->discount;
$json['type_id'] = $this->type_id;
$json['created_by_id'] = $this->created_by_id;
$json['created_at'] = $this->created_at;
$json['updated_at'] = $this->updated_at;
if($this->type_id == self::ITEM_SPECIAL) {
$json['discounted_price'] = ($this->discount * $this->price) / 100; }
return $json;
}
It works fine but it removes the pagination.
you can add key and value in collection object by using map method
$products = Products::latest()->paginate(10);
$itemSpecial = self::ITEM_SPECIAL; //pass variable in closure by using use
$products->map(function($item) use ($itemSpecial) {
if($item->type_id == $itemSpecial) {
$item->discounted_price = ($item->discount * $item->price) / 100;
}
return $item;
});
you can used condition also in clourse
In Controller
public function index() {
$products = Products::latest()->paginate(10);
if (! empty($products)) {
$final_prod = [];
foreach ($products as $product) {
$final_prod[] = $this->asFilterJson($product);
}
return response()->json(['status'=>'200','message'=>'Product list ','data'=>$final_prod]);
} else {
return response()->json(['status'=>'200','message'=>'No product available','data'=>[]]);
}
}
// function for extra column add
static function asFilterJson($product){
$value['discounted_price'] = ($value['discount'] * $value['price']) / 100;
return $value;
}
You can define new mutator in your model.
public function getDiscountedPriceAttribute()
{
return ($this->discount * $this->price) / 100;
}
After than, you can use it as $this->discountedPrice

How to pass helper data to all views in Laravel 5 using helper in AppServiceProvider?

I would like to move a helper to be displayed in all views. The helper is ->
helperFunctions::getPageInfo($cart, $total);
At this moment I have to define in every controller that information, as an example:
public function show($id, Request $request)
{
$category = Category::find($id);
if (strtoupper($request->sort) == 'NEWEST') {
$products = $category->products()->orderBy('created_at', 'desc')->paginate(40);
} elseif (strtoupper($request->sort) == 'HIGHEST') {
$products = $category->products()->orderBy('price', 'desc')->paginate(40);
} elseif (strtoupper($request->sort) == 'LOWEST') {
$products = $category->products()->orderBy('price', 'asc')->paginate(40);
} else {
$products = $category->products()->paginate(40);
}
helperFunctions::getPageInfo($sections, $cart, $total);
return view('site.category', compact('cart', 'total', 'category', 'products'));
}
I read and tried to move that helper to AppServiceProvider.php, inside the Boot() function.
public function boot()
{
helperFunctions::getPageInfo($cart,$total);
View::share('cart','total');
}
But im receiving error info:
Undefined variable: total
-----UPDATE--------
My class helper with getPageInfo
class helperFunctions
{
public static function getPageInfo(&$cart,&$total)
{
if (Auth::user()) {
$cart = Auth::user()->cart;
} else {
$cart = new Collection;
if (Session::has('cart')) {
foreach (Session::get('cart') as $item) {
$elem = new Cart;
$elem->product_id = $item['product_id'];
$elem->amount = $item['qty'];
if (isset($item['options'])) {
$elem->options = $item['options'];
}
$cart->add($elem);
}
}
}
$total = 0;
foreach ($cart as $item) {
$total += $item->product->price*$item->amount;
}
}
}
Since you pass the variable by reference in your helper function, you need to define them before calling. Change your view share code to this.
public function boot()
{
$cart = null;
$total = 0;
helperFunctions::getPageInfo($cart, $total);
$data = [
'cart' => $cart,
'total' => $total,
];
View::share($data);
}
You can then access $cart and $total in all your views.
Alternatively if you want to make things cleaner, make the helper function return the array of data and pass it to the view.

In Yii framework how can I Combine columns and show as display string in dropdownlist

I have a dropDownList in my view, it is populating from clients table, the table contains columns like first_name, last_name,id etc., Now I want to show the first_name and last_name as display text and id as value in drop down list, I'm done with id as value and first_name as display text, but here I want to combine those columns (first_name and last_name) and use as display text.
in model
function getClients()
{
$Clients = Client::model()->findAll();
$list = CHtml::listData($Clients , 'client_id', 'first_name');
return $list;
}
in view
echo $form->dropDownList($model,'client_id',$model->getClients());
Heres another method
In model
function getFullName()
{
return $this->first_name.' '.$this->last_name;
}
and
function getClients()
{
$Clients = Client::model()->findAll();
$list = CHtml::listData($Clients , 'client_id', 'fullName');
return $list;
}
I think this is kinda reusable method since you can use the fullName virtual attribute not only in dropdownlist but everywhere a full name is needed.
1st variant (Easy):
$list = array();
foreach ($Clients as $c) {
$list[$c->id] = $c->first_name . ' ' . $c->last_name;
}
2nd variant (Universal):
class ExtHtml extends CHtml {
public static function listData($models,$valueField,$textField,$groupField='')
{
$listData=array();
if($groupField==='')
{
foreach($models as $model)
{
$value=self::value($model,$valueField);
if (is_array($textField)) {
$t = array();
foreach ($textField as $field) {
$t[]=self::value($model,$field,$field);
}
$text=implode(' ', $t);
} else {
$text=self::value($model,$textField, null);
if ($text == null) {
if (is_callable($textField)) $text=call_user_func($textField, $model);
else $text = $textField;
}
}
$listData[$value]=$text;
}
}
else
{
foreach($models as $model)
{
$group=self::value($model,$groupField);
$value=self::value($model,$valueField);
if (is_array($textField)) {
$t = array();
foreach ($textField as $field) {
$t[]=self::value($model,$field,$field);
}
$text=implode(' ', $t);
} else {
$text=self::value($model,$textField, null);
if ($text == null) {
if (is_callable($textField)) $text=call_user_func($textField, $model);
else $text = $textField;
}
}
$listData[$group][$value]=$text;
}
}
return $listData;
}
public static function value($model,$attribute,$defaultValue=null)
{
foreach(explode('.',$attribute) as $name)
{
if(is_object($model) && ($model->hasAttribute($name) || isset($model->{$name})))
$model=$model->$name;
else if(is_array($model) && isset($model[$name]))
$model=$model[$name];
else
return $defaultValue;
}
return $model;
}
}
// in model
function getClients()
{
$Clients = Client::model()->findAll();
$list = ExtHtml::listData($Clients , 'client_id', array('first_name', 'last_name'));
return $list;
}
3rd variant (Mysql)
function getClients()
{
$Clients = Client::model()->findAll(array('select' => 'concat(first_name, " ", last_name) as first_name'));
$list = CHtml::listData($Clients , 'client_id', 'first_name');
return $list;
}
Try this compact mode using "anonymous function" feature of PHP:
function getClients()
{
return CHtml::listData(Client::model()->findAll(), 'id', function($client) { return $client->first_name . ' ' . $client->last_name; });
}
Previous comment with "compact mode" with anonymous function has an error!
Right code is:
function getClients()
{
$clients = Client::model()->findAll();
return CHtml::listData($clients, 'id', function($clients) { return $client->first_name . ' ' . $client->last_name; });
}

Categories