Creating a new collection from another collection - php

im creating a collection of specific data from a query that i made, but i need to create a new collection with only some data with custom names properties, i was using arrays, but i need to make it in collections since is easyer to format the data and access some collections methods.
My current code is like:
$activity = [];
$temp = [];
$calculations = collect($user->calculations()
->withTrashed()
->orderBy('updated_at', 'desc')
->get());
foreach($calculations as $calculation){
$temp['type'] = "calculation";
$temp['name'] = $calculation->name;
$user = $this->getUserById($calculation->pivot->user_id);
$temp['user'] = $user->name ." ".$user->surname;
if($calculation->created_at == $calculation->updated_at && $calculation->deleted_at == null)
{
$temp['operation'] = "saved";
$temp['date'] = $calculation->created_at;
$temp['diff'] = Carbon::parse($calculation->created_at)->diffForHumans();
}elseif($calculation->created_at != $calculation->updated_at && $calculation->deleted_at != null)
{
$temp['operation'] = "changed";
$temp['date'] = $calculation->updated_at;
$temp['diff'] = Carbon::parse($calculation->updated_at)->diffForHumans();
}else{
$temp['operation'] = "delete";
$temp['date'] = $calculation->deleted_at;
$temp['diff'] = Carbon::parse($calculation->deleted_at)->diffForHumans();
}
array_push($activity,$temp);
}
$conditions = collect($user->conditions()
->withTrashed()
->orderBy('updated_at', 'desc')
->get());
foreach($conditions as $condition){
$temp['type'] = "condition";
$temp['name'] = $condition->name;
$user = $this->getUserById($condition->user_id);
$temp['user'] = $user->name ." ".$user->surname;
if($condition->created_at == $condition->updated_at && $condition->deleted_at == null)
{
$temp['operation'] = "saved";
$temp['date'] = $condition->created_at;
$temp['diff'] = Carbon::parse($condition->created_at)->diffForHumans();
}elseif($condition->created_at != $condition->updated_at && $condition->deleted_at != null)
{
$temp['operation'] = "alterado";
$temp['date'] = $condition->updated_at;
$temp['diff'] = Carbon::parse($condition->updated_at)->diffForHumans();
}else{
$temp['operation'] = "delete it";
$temp['date'] = $condition->deleted_at;
$temp['diff'] = Carbon::parse($condition->deleted_at)->diffForHumans();
}
array_push($activity,$temp);
I already convert the eloquent query to "collect", but how i cant createa new collections, i need to instead using the array methods, i should use the collection methods to create them.
Basically my main reason is that i need to merge the "conditions" and "calculations" for than be able to order the dataTime the collections.

How about something like this.
I've used transform method on collections (in order to transform the key names). I've replicated your logic and then merged both collections.
$calculations = $user->calculations()
->withTrashed()
->orderBy('updated_at', 'desc')
->get();
$transformed = $calculations->transform(function($item, $key) use($user) {
$toReturn = [];
$toReturn['type'] = "calculation";
$toReturn['name'] = $item->name;
$toReturn['user'] = $user->name;
if($item->created_at == $item->updated_at && $item->deleted_at == null) {
$toReturn['operation'] = "saved";
$toReturn['date'] = $item->created_at;
$toReturn['diff'] = Carbon::parse($item->created_at)->diffForHumans();
} elseif($item->created_at != $item->updated_at && $item->deleted_at != null){
$toReturn['operation'] = "changed";
$toReturn['date'] = $item->updated_at;
$toReturn['diff'] = Carbon::parse($item->updated_at)->diffForHumans();
} else {
$toReturn['operation'] = "delete";
$toReturn['date'] = $item->deleted_at;
$toReturn['diff'] = Carbon::parse($item->deleted_at)->diffForHumans();
}
return $toReturn;
});
$conditions = $user->conditions()
->withTrashed()
->orderBy('updated_at', 'desc')
->get();
$transformed2 = $conditions->transform(function($item, $key) use($user) {
$toReturn = [];
$toReturn['type'] = "calculation";
$toReturn['name'] = $item->name;
$toReturn['user'] = $this->getUserById($item->user_id);
if($item->created_at == $item->updated_at && $item->deleted_at == null) {
$toReturn['operation'] = "saved";
$toReturn['date'] = $item->created_at;
$toReturn['diff'] = Carbon::parse($item->created_at)->diffForHumans();
} elseif($condition->created_at != $condition->updated_at && $condition->deleted_at != null){
$toReturn['operation'] = "changed";
$toReturn['date'] = $item->updated_at;
$toReturn['diff'] = Carbon::parse($item->updated_at)->diffForHumans();
} else {
$toReturn['operation'] = "delete";
$toReturn['date'] = $item->deleted_at;
$toReturn['diff'] = Carbon::parse($item->deleted_at)->diffForHumans();
}
return $toReturn
});
$merged = $transform->merge($transform2);

Building on #devk 's answer here is a neater version without so much repetitive code:
/**
* Transform a collction with a given callback
*
* #param Collection $collection A laravel collection
* #param User $user A User object
* #return Collection
**/
private function transformCollection(Collect $collection, User $user) {
return $collection->transform(function($item, $key) use ($user) {
$toReturn = [
'type' => 'calculation',
'name' => $item->name,
'user' => $user->name
];
if ($item->created_at == $item->updated_at && $item->deleted_at == null) {
$toReturn['operation'] = "saved";
$toReturn['date'] = $item->created_at;
$toReturn['diff'] = Carbon::parse($item->created_at)->diffForHumans();
} elseif ($item->created_at != $item->updated_at && $item->deleted_at != null) {
$toReturn['operation'] = "changed";
$toReturn['date'] = $item->updated_at;
$toReturn['diff'] = Carbon::parse($item->updated_at)->diffForHumans();
} else {
$toReturn['operation'] = "delete";
$toReturn['date'] = $item->deleted_at;
$toReturn['diff'] = Carbon::parse($item->deleted_at)->diffForHumans();
}
return $toReturn;
});
}
// Return all user calculations ordered by when they were updated including deleted
$calculations = $user->calculations()->withTrashed()->orderBy('updated_at', 'desc')->get();
$conditions = $user->conditions()->withTrashed()->orderBy('updated_at', 'desc')->get();
// Transform both collections
$transformed = transformCollection($calculations, $user);
$transformed2 = transformCollection($conditions, $user);
// Merge the resulting collections into a single collection
$merged = $transform->merge($transform2);
Edit
If your Calculation object has a model you can also make sure that the dates are returned as Carbon dates by adding them to the protected $dates = [] array
protected $dates = [
'deleted_at',
'created_at',
'updated_at'
];
I think that created_at and updated_at are included in this by default as part of BaseModel, thought i could well be wrong.

Related

filtering and sorting with pagination in laravel

Hi I'm using Laravel and I have a sorting and filtering system it works via url like this
http://localhost:8000/halehule/category/103?type=all&minprice=+10+&maxprice=+10000000000+&color=&sortBy%5Bfield%5D=price&sortBy%5BorderBy%5D=desc
so when I use pagination it does not work and refresh to original page like this :
http://localhost:8000/halehule/category/103?page=2
How can I use pagination with sorting and filtering like this
here is my method
public function brandProduct($shop, $id, Request $request) {
$colors = Color::all();
$shop = Shop::where('english_name', $shop)->first();
$shopTags = $shop->tags;
$shopCategories = $shop->ProductCategories()->get();
$categories = Shop::where('english_name', $shop->english_name)->first()->ProductCategories()->get()->where('parent_id', null);
$brand = Brand::where('id', $id)->get()->first();
$brands = $shop->brands;
$shopProducts = $shop->products;
$minPriceProduct = $shopProducts->min('price');
$maxPriceProduct = $shopProducts->max('price');
//color product and category product merging
if($request->color == null){
$colorAndBrandProducts = $brand->products->sortByDesc('created_at');
}
else{
$colorProducts = Color::where('code', $request->color)->get()->first()->products;
$brandProducts = $brand->products;
$colorAndBrandProducts = collect();
foreach($colorProducts->toBase()->merge($brandProducts)->groupBy('id') as $allProducts){
if($allProducts->count() > 1){
$colorAndBrandProducts[] = $allProducts;
}
}
$colorAndBrandProducts = $colorAndBrandProducts->first();
}
if ($request->has('type') and $request->has('sortBy') and $request->has('minprice') and $request->has('maxprice') and $request->has('color')) {
if($colorAndBrandProducts != null){
$minPrice = $request->minprice;
$maxPrice = $request->maxprice;
$filterBy = $request->type;
$sortBy = $request->sortBy['field'];
$perPage = 16;
if($shop->template->folderName == 2){
$sortBy_array = explode('|', $request->sortBy['field']);
$sortBy = $sortBy_array[0];
$orderBy = $sortBy_array[1];
}
else{
$orderBy = $request->sortBy['orderBy'];
}
if ($request->type == 'all') {
if ($orderBy == 'desc') {
$products = $colorAndBrandProducts->whereBetween('price', [$minPrice, $maxPrice])->sortByDesc($sortBy)->unique('id');
} else {
$products = $colorAndBrandProducts->whereBetween('price', [$minPrice, $maxPrice])->sortBy($sortBy)->unique('id');
}
} else {
if ($orderBy == 'desc') {
$products = $colorAndBrandProducts->where('type', $filterBy)->whereBetween('price', [$minPrice, $maxPrice])->sortByDesc($sortBy)->unique('id');
} else {
$products = $colorAndBrandProducts->where('type', $filterBy)->whereBetween('price', [$minPrice, $maxPrice])->sortBy($sortBy)->unique('id');
}
}
}
else{
$products = collect();
}
}
else {
$products = $colorAndBrandProducts;
}
$total = $products->count();
$perPage = 16; // How many items do you want to display.
$currentPage = request()->page; // The index page.
$productsPaginate = new LengthAwarePaginator($products->forPage($currentPage, $perPage), $total, $perPage, $currentPage);
$template_folderName = $shop->template->folderName;
SEOTools::setTitle($shop->name . ' | ' . $brand->name);
SEOTools::setDescription($shop->description);
SEOTools::opengraph()->addProperty('type', 'website');
return view("app.shop.$template_folderName.layouts.partials.products", compact('products','minPriceProduct', 'maxPriceProduct', 'shopCategories', 'brand', 'shop', 'categories', 'productsPaginate', 'brands', 'shopTags','colors'));
}
I use this method for sorting and filtering and use pagination works great but without sorting and filtering
just apply ->append($_GET) to your pagination

Api Pagination in Symfony

I am working on API, I have a controller that query for results to a framework7 app. (first, last and both). I, however, want to add pagination from API to framework but I have not paginated in Symfony before, what is the best practice?
I tried paginator but there are not many examples of it. Below is my controller function.
public function getEventSessionAttendeeAction(request $request, $eventSessionId)
{
$searchFields = [
'o.email',
'a.email',
'a.firstName',
'a.lastName',
'a.barcode1',
'a.barcode2',
'a.id',
'o.id'
];
/** #var \KCM\ApiBundle\Entity\Api\EventSession $eventSession */
$eventSession = $this->get('doctrine')->getRepository('KCMApiBundle:EventSession')->findOneBy(
[
'id' => $eventSessionId
]
);
/** #var ApiEntity\Event $event */
$event = $eventSession->getEvent();
$childSafe = $event->getChildSafe();
$filter = $request->get('filter');
$match_level = 0;
//Searches by email address
if ( filter_var($filter, FILTER_VALIDATE_EMAIL)) {
$searchFields = [
'a.email'
];
$match_level = 1;
//Searches for first or last name
}elseif(preg_match('/^[a-zA-Z\-]*$/', $filter)){
$searchFields = [
'a.lastName',
'a.firstName'
];
$match_level = 2;
//Searches by barcode
}elseif (preg_match('/^[0-9]+/', $filter)){
if ($childSafe == 2) {
$searchFields = [
'a.barcode3'
];
} else {
$searchFields = [
'a.barcode1'
];
}
$match_level = 4;
}
//Searches for first and last name(must have at least first characters for each
if(preg_match('/^([a-z|A-Z]+)\s{1}([a-z|A-Z]+)/', $filter)){
$match_level = 3;
}elseif (preg_match('/^\s*$/', $filter)){
$match_level = 5;
}
try {
/** #var ApiEntity\EventSession $eventSession */
$em = $this->getDoctrine()->getManager();
$qb = $em->createQueryBuilder();
$qb->select(array('a', 'o'))
->from('KCMApiBundle:EventAttendee', 'a')
->join('a.eventOrder', 'o')
->join('o.event', 'e')
->join('e.eventSessions', 'es')
->where($qb->expr()->andX(
$qb->expr()->eq('es.id', $qb->expr()->literal($eventSessionId))
))
->andWhere('a.sessionCheckedIn = 1');
if ($match_level === 3){
$expr = $qb->expr()->andX();
list($first, $last) = explode(' ', $filter);
$last = $last. '%';
$expr->add($qb->expr()->like('a.lastName', $qb->expr()->literal($last)));
$first = $first. '%';
$expr->add($qb->expr()->like('a.firstName',$qb->expr()->literal($first)));
}elseif ($match_level === 5){
$expr = $qb->expr()->andX();
$paginator = new Paginator($qb);
$paginator->getQuery()
->setFirstResult(0)
->setMaxResults(10);
}else {
$expr = $qb->expr()->orX();
foreach ($searchFields as $field) {
if ($match_level === 1) {
$literalFilter = $filter;
$expr->add($qb->expr()->like($field, $qb->expr()->literal($literalFilter)));
} elseif ($match_level === 2) {
$literalFilter = $filter;
$expr->add($qb->expr()->like($field, $qb->expr()->literal($literalFilter)));
} elseif ($match_level === 4) {
$literalFilter = $filter;
$expr->add($qb->expr()->eq($field, $qb->expr()->literal($literalFilter)));
}
}
}
$qb->andWhere($expr);
$results = $qb->getQuery()->getResult();
if ($results) {
return $this->getApi()->serialize($results);
}
return new Response(null, Response::HTTP_NOT_FOUND);
} catch (\Exception $e) {
$this->get('logger')->error($e->getMessage());
}
}
What I am trying to eventually do is to be able to use this query to paginate to the framework7 app. should I create a new public function to paginate or is there a way to do it within this function?
Did you try to use knppagination bundle?
https://github.com/KnpLabs/KnpPaginatorBundle

Writing a function in laravel

I have the following function which fetch some data related to jobs from database. The user can search for jobs with job title / keyword, city and/or category. The user can either choose one option, e.g. searching jobs only by title, or by category. or he can use all options for deep search. Below is my function:
public function jobsearch(Request $request)
{
$keyword = htmlspecialchars($request->input('keyword'));
$city_id = $request->input('city_id');
$category_id = $request->input('category_id');
if($keyword !== '' && $city_id != 0 && $category_id == 0)
{
$data = DB::table('job_details')->where('job_title', 'like', '%'.$keyword.'%')->where('city_id', $city_id)->get();
}
elseif($keyword !== '' && $city_id == 0 && $category_id != 0)
{
$data = DB::table('job_details')->where('job_title', 'like', '%'.$keyword.'%')->where('category_id', $category_id)->get();
}
elseif($keyword == '' && $city_id != 0 && $category_id != 0)
{
$data = DB::table('job_details')->where('category_id', $category_id)->where('city_id', $city_id)->get();
}
elseif($keyword !== '' && $city_id == 0 && $category_id == 0)
{
$data = DB::table('job_details')->where('job_title', 'like', '%'.$keyword.'%')->get();
}
elseif($keyword == '' && $city_id == 0 && $category_id != 0)
{
$data = DB::table('job_details')->where('category_id', $category_id)->get();
}
elseif($keyword == '' && $city_id != 0 && $category_id == 0)
{
$data = DB::table('job_details')->where('city_id', $city_id)->get();
}
else
{
$data = DB::table('job_details')->where('job_title', 'like', '%'.$keyword.'%')->where('category_id', $category_id)->where('city_id', $city_id)->get();
}
foreach($data as $data)
{
echo $data->job_title.'<br>';
}
}
As you can see the function is too much messy with many if and elseif statements. My question is if there is any way to write the given function in clean way? How would you write the given function in your style? Please Help.
You're really missing out on the best parts of Laravel's query builder.
public function jobsearch(Request $request) {
// htmlspecialchars makes no sense here
$keyword = $request->input('keyword');
$city_id = $request->input('city_id');
$category_id = $request->input('category_id');
$query = DB::table('job_details');
if($keyword) {
$query->where('job_title', 'like', '%'.$keyword.'%');
}
if($city_id) {
$query->where('city_id', $city_id);
}
if($category_id) {
$query->where('category_id', $category_id);
}
$results = $query->get();
foreach($data as $data) { ... }
}

Query in Api Laravel

I'm trying to make APIs showing data from two tables, but I'm stuck at this point.
This is my ApiController:
public function postDetaillog(Request $request)
{
$response = array();
$validator = Validator::make(
$request->all(),
[
'id'=> 'required',
]
);
if ($validator->fails()) {
$message = $validator->errors()->all();
$result['api_status'] = 0;
$result['api_message'] = implode(', ',$message);
$res = response()->json($result);
$res->send();
exit;
}
$data = DB::table('log_patrols')
->where('id', $request->input('id'))
->first();
$site = asset("uploads").'/';
$result = DB::table('log_patrol_details')
->select("*",DB::raw("concat('$site',photo1) as photo1"),DB::raw("concat('$site',photo2) as photo2"),DB::raw("concat('$site',photo3) as photo3"))
->where('id', $request->input('id'))
->first();
if (count($result) == 0) {
$response['api_status'] = count($result);
$response['api_message'] = "No data";
} else {
$response['api_status'] = 1;
$response['api_message'] = "success";
$response['data'] = $data;
$response['result'] = $result;
}
return response()->json($response);
}
first table
second table
Whenever I try to get the results, it always gives me 0 = no data
Could you please help me?
If what you get is a collection you may use if ($result->count() == 0) to check if it is empty.
Change as follows:
if ($result->count() == 0) {
$response['api_status'] = 0; // Don't use useless logic
$response['api_message'] = "No data";
} else {
$response['api_status'] = 1;
$response['api_message'] = "success";
$response['data'] = $data;
$response['result'] = $result;
}

Laravel : search or filter the collection

I have this issue while filtering or searching through a collection
http://laravel.io/bin/vj115 check the url for code.
What i am trying to do is filter a collection by get method (from url ofcourse)
But only it only works when Input::get('category') has value else nothing works.
Could you please check the code and let me know what need to be fixed?
Thanks.
===== Real Code just incase the link is broken in future (edited)=============
public function anyIndex() {
$id = Input::get('id');
$brand = Brand::firstOrNew(array('id' => $id));
$paginate = Misc::getSettings('admin-pagination');
$page_no = isset($_GET['page']) ? $_GET['page'] : 1;
$i = ($paginate * $page_no) - ($paginate - 1);
$appends = false;
$newBrands = new Brand;
if (Input::get('category')) {
$brandCat = BrandCategory::find(Input::get('category'));
$newBrands = $brandCat->brands();
$appends['category'] = Input::get('category');
}
if (Input::get('status')) {
$status = Input::get('status') == 'published' ? 1 : 0;
$newBrands->where('is_active', '=', $status);
$appends['status'] = Input::get('status');
}
if (Input::get('order_by') || Input::get('order')) {
if (Input::get('order_by')) {
$order_by = Input::get('order_by');
$appends['order_by'] = Input::get('order_by');
} else {
$order_by = 'name';
}
if (Input::get('order')) {
$order = Input::get('order');
$appends['order'] = Input::get('order');
} else {
$order = 'asc';
}
$order = Input::get('order') ? Input::get('order') : 'asc';
$newBrands->orderBy($order_by, $order);
}
$brands = $newBrands->paginate($paginate);
$brand_categories_list = new BrandCategory;
$selected_cats = array();
if ($id != "") {
$selected_cats = $brand->categories->lists('id');
}
return View::make('admin.brands.index')
->with(array(
'selected_cats' => $selected_cats,
'brand' => $brand,
'brands' => $brands,
'brand_categories_list' => $brand_categories_list->lists('name', 'id'),
'appends' => $appends,
'i' => $i
));
}
Thanks to Dave.. I solved it as :
public function anyIndex() {
$id = Input::get('id');
$brand = Brand::firstOrNew(array('id' => $id));
$paginate = Misc::getSettings('admin-pagination');
$page_no = isset($_GET['page']) ? $_GET['page'] : 1;
$i = ($paginate * $page_no) - ($paginate - 1);
$appends = false;
if (Input::has('category')) {
$brandCat = BrandCategory::find(Input::get('category'));
$newBrands = $brandCat->brands();
$appends['category'] = Input::get('category');
} else {
$newBrands = Brand::limit(-1);
}
if (Input::has('status')) {
$status = Input::get('status') == 'published' ? 1 : 0;
$newBrands->where('is_active', '=', $status);
$appends['status'] = Input::get('status');
}
if (Input::has('order_by') || Input::has('order')) {
if (Input::has('order_by')) {
$order_by = Input::get('order_by');
$appends['order_by'] = Input::get('order_by');
} else {
$order_by = 'name';
}
if (Input::has('order')) {
$order = Input::get('order');
$appends['order'] = Input::get('order');
} else {
$order = 'asc';
}
$order = Input::get('order') ? Input::get('order') : 'asc';
$newBrands->orderBy($order_by, $order);
}else{
$newBrands->orderBy('name', 'asc');
}
$brands = $newBrands->paginate($paginate);
/* $queries = DB::getQueryLog();
$last_query = end($queries);
dd($last_query); */
$brand_categories_list = new BrandCategory;
$selected_cats = array();
if ($id != "") {
$selected_cats = $brand->categories->lists('id');
}
return View::make('admin.brands.index')
->with(
array(
'selected_cats' => $selected_cats,
'brand' => $brand,
'brands' => $brands,
'brand_categories_list' => $brand_categories_list->lists('name', 'id'),
'appends' => $appends,
'i' => $i)
);
}
I suspect it has to do with how you are using Eloquent. You can't simply apply methods to the object if it was created using the "new" keyword.
$newBrands = new Brand;
// This won't work
$newBrands->where('is_active', '=', $status);
// This will work
$newBrands = $newBrands->where('is_active', '=', $status);
It will work if you create it statically along with a method.
$newBrands = Brand::limit(100);
// This will work
$newBrands->where('is_active', '=', $status);
Fluent (DB) works the same way.
$newBrands = DB::table('brands');
// This wil work
$newBrands->where('is_active', '=', $status);
here I am searching the username(s) based on the displayname or fullname or email. therefore, the $request->filled('name of your input') is the solution.
$usernames = (new User())->newQuery(); //where User is the model
if($request->filled('email')){
$usernames->orWhere('email',$request->email);
}
if($request->filled('full_name')){
$usernames->orWhere('full_name',$request->full_name);
} if($request->filled('display_name')){
$usernames->orWhere('display_name',$request->display_name);
}
$usernames = $usernames->pluck('username')->toArray();

Categories