Newbie to PHP/Laravel here so please be patient.
I have a webpage that is searching based on 3 criteria for dogs , breed, sex and radius.
here is the relevant code:
search page
<div class="col-md-12 zero-pad-left zero-pad-right">
{{ Form::open(array('action' => array('DogsController#index'), 'class'=>'form width88', 'role'=>'search', 'method' => 'GET')) }}
<div id="prefetch">
{{ Form::text('search-breed', null, array('class' => 'typeahead form-group form-control', 'placeholder' => 'Search by breed here...')) }}
{{ Form::text('sex', null, array('class' => 'form-group form-control', 'placeholder' => 'Search by sex here...')) }}
{{ Form::text('miles', null, array('class' => 'form-group form-control', 'placeholder' => 'Search by distance here...')) }}
</div>
{{ Form::submit('Search', array('class' => 'btn btn-default search-bar-btn')) }}
{{ Form::close() }}
ControllerPage
class DogsController extends \BaseController {
public function __construct()
{
// call base controller constructor
parent::__construct();
// run auth filter before all methods on this controller except index and show
$this->beforeFilter('auth', array('except' => array('show')));
}
/**
* Display a listing of the resource.
*
* #return Response
*/
public function index()
{
if (Input::has('search')) {
$queryString = Input::get('search');
$dogs = Dog::where('name', 'LIKE', "%$queryString%")->orderBy('name')->paginate(5);
}
elseif (Input::has('search-breed'))
{
$dogs = Dog::whereHas('breed', function($q)
{
$queryString = Input::get('search-breed');
$q->where('name', 'LIKE', "%$queryString%");
})->orderBy('name')->paginate(5);
} //end elseif
else {
$dogs = Dog::orderBy('name')->paginate(5);
} //end else
return View::make('dogs.index')->with(array('dogs' => $dogs));
} //end function index()
when i enter a search for poodle, male, within 20 miles, the url shows as follows:
http://ruff-love.dev/dogs?search-breed=poodle&sex=M&miles=20
The search currently works ok when searching for just breed.
I cant seem to figure out the syntax to add the SEX and RADIUS criteria also.
it should allow for those criteria to be null and still perform the query.
any advice would be greatly apprecaited
You can use query scopes http://laravel.com/docs/eloquent#query-scopes to make it verbose and easier in your controller (or wherever you will be doing it in future) then chain them according to your needs:
// Dog model
public function scopeSearchBreed($query, $breed)
{
$query->whereHas('breed', function ($q) use ($breed) {
$q->where('name', 'like', "%{$breed}%");
});
}
public function scopeWithinRadius($query, $radius)
{
$query->where(...); // do math here
}
Then all you need is this:
public function index()
{
$q = Dog::query();
if (Input::has('search'))
{
// simple where here or another scope, whatever you like
$q->where('name','like',Input::get('search'));
}
if (Input::has('search-breed'))
{
$q->searchBreed(Input::get('search-breed'));
}
if (Input::has('sex'))
{
$q->where('sex', Input::get('sex'));
}
if (Input::has('radius'))
{
$q->withinRadius(Input::get('radius'));
}
$dogs = $q->orderBy(..)->paginate(5);
// ...
Here's one possible solution, I think there are probably others. Create an empty query builder with the query() function and add the non-null clauses to it, then call the paginate() function at the end.
$builder = Dogs::query();
if (Input::has('search')) {
$queryString = Input::get('search');
$builder->where('name', 'LIKE', "%$queryString%");
}
// ... more clauses from the querystring
$dogs = $builder->orderBy('name')->paginate(5);
$builder = Dogs::query();
$term = Request::all();
if(!empty($term['breed'])){
$builder->where('breed','=',$term['breed']);
}
if(!empty($term['sex'])){
$builder->where('sex','=',$term['sex']);
}
if(!empty($term['radius'])){
$builder->where('radius','=',$term['radius']);
}
$result = $builder->orderBy('id')->get();
$area = Area::query();
if (Input::has('search')) {
$queryString = Input::get('search');
$area->where('name', 'LIKE', "%" . $queryString . "%");
}
$result = $area->orderBy('name')->paginate(5);
Related
I am working on a blogging application in Laravel 8.
The FrontendController controller contains the data that is common to all the theme's views:
namespace App\Http\Controllers;
use App\Models\Settings;
use App\Models\ArticleCategory;
use App\Models\Page;
class FrontendController extends Controller
{
protected $data;
protected $site_settings;
protected $theme_directory;
protected $site_name;
protected $tagline;
protected $owner_name;
protected $owner_email;
protected $twitter;
protected $facebook;
protected $instagram;
protected $is_cookieconsent;
protected $is_infinitescroll;
protected $pages;
protected $article_categories;
public function __construct()
{
$this->site_settings = Settings::first();
$this->theme_directory = $this->site_settings['theme_directory'] ?? null;
$this->site_name = $this->site_settings['site_name'] ?? null;
$this->tagline = $this->site_settings['tagline'] ?? null;
$this->owner_name = $this->site_settings['owner_name'] ?? null;
$this->owner_email = $this->site_settings['owner_email'] ?? null;
$this->twitter = $this->site_settings['twitter'] ?? null;
$this->facebook = $this->site_settings['facebook'] ?? null;
$this->instagram = $this->site_settings['instagram'] ?? null;
$this->is_cookieconsent = $this->site_settings['is_cookieconsent'] ?? null;
$this->is_infinitescroll = $this->site_settings['is_infinitescroll'] ?? null;
// Article categories
$this->article_categories = ArticleCategory::all();
// Pages
$this->pages = Page::all();
$this->data = [
'theme_directory' => $this->theme_directory,
'site_name' => $this->site_name,
'tagline' => $this->tagline,
'owner_name' => $this->owner_name,
'owner_email' => $this->owner_email,
'twitter' => $this->twitter,
'facebook' => $this->facebook,
'instagram' => $this->instagram,
'is_cookieconsent' => $this->is_cookieconsent,
'is_infinitescroll' => $this->is_infinitescroll,
'pages' => $this->pages,
'categories' => $this->article_categories,
];
}
}
The ArticlesController controller extends the one above:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\ArticleCategory;
use App\Models\Article;
class ArticlesController extends FrontendController {
// Articles per page
protected $per_page = 12;
public function index(Request $request) {
// Search query
$qry = $request->input('search');
$articlesQuery = Article::where('title', 'like', '%' . $qry . '%')
->orWhere('short_description', 'like', '%' . $qry . '%')
->orWhere('content', 'like', '%' . $qry . '%');
$articles = $articlesQuery->orderBy('id', 'desc')->paginate($this->per_page);
// Search results count
if ($request->input('search')) {
$article_count = $articlesQuery->count();
}
return view('themes/' . $this->theme_directory . '/templates/index',
array_merge($this->data, [
'search_query' => $qry,
'articles' => $articles,
'article_count' => $article_count ?? null
])
);
}
}
The posts list view (index.blade.php):
<div class="col-lg-8 col-md-10 mx-auto">
#if (isset($search_query))
<p class="mt-0 text-muted">We found {{ $article_count }} posts containing <span class="quote-inline">{{ $search_query }}</span>:</p>
#endif
#if (count($articles))
#foreach ($articles as $article)
<div class="post-preview">
<a href="{{ url('/show/' . $article->slug) }}">
<h2 class="post-title">
{{ $article->title }}
</h2>
<h3 class="post-subtitle">
{{ $article->short_description }}
</h3>
</a>
<p class="post-meta">Posted by
{{ $article->user->first_name }} {{ $article->user->last_name }}
on {{ date('j F, Y', strtotime($article->created_at)) }}
</p>
</div>
#if(!$loop->last)<hr>#endif
#endforeach
#endif
<!-- Pager -->
#if($articles->hasPages())
<div class="clearfix">
<ul class="pagination">
<li class="next">
<a class="btn btn-primary {{ $articles->onFirstPage() ? 'disabled' : '' }}" href="{{ $articles->withQueryString()->previousPageUrl() }}">← Newer Posts</a>
</li>
<li class="prev">
<a class="btn btn-primary {{ $articles->onLastPage() ? 'disabled' : '' }}" href="{{ $articles->withQueryString()->nextPageUrl() }}">Older Posts →</a>
</li>
</ul>
</div>
#endif
</div>
The problem
Whenever there are paginated search results, the $article_count variable displays the total article count only on the first page. On all the others, it shows 0.
Questions
What causes this bug?
What is the easiest fix?
You need to use the search query above the articles variable. Like this way.
// Search results count
if ($request->input('search')) {
$article_count = $articlesQuery->count();
}
$articles = $articlesQuery->orderBy('id', 'desc')->paginate($this->per_page);
Because every time it will paginate for page wise. If you paginate for the second page it may not contain any data. That's why you are getting the 0 value for the other page. Please use this way, I think the problem will be solved.
I've ran into this earlier this month. It seems that once the the query is executed ->paginate($this->per_page) or even ->get() the objects are dumped in the query (perhaps memory management) which also means that the count also does not work as expected. What you can do is get the count prior to the query if you do not want to use laravel's pagination wrapper
$articlesQuery = Article::where('title', 'like', '%' . $qry . '%')
->orWhere('short_description', 'like', '%' . $qry . '%')
->orWhere('content', 'like', '%' . $qry . '%');
// Search results count
if ($request->input('search')) {
$article_count = $articlesQuery->count();
}
$articles = $articlesQuery->orderBy('id', 'desc')->paginate($this->per_page);
I also found this to happen while having an offset which would mean that only not on the main page would the result be 0.
Luckily setting the count prior to the query will help.
if you need total count of result in pagination, there is a variable exist named:"meta" inside it a variable "total" this is what you need.
pagination response like this:
{
"products": {
"data": [ YOUR DATA ],
"links": { LINKS OF PAGES},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 11,
"links": [ ALL LINKS OF ALL PAGES ],
"path": "",
"per_page": 20,
"to": 20,
----> "total": 210 <---- THIS IS WHAT YOU NEED ----------
}
}
}
response image:
I have multiple forms where I need to pass through the id. In the example bellow I have 2 controllers one is for Courses and one is for the Exams. I'm trying to create a course and then pass through the course id to the exam form.
Here is what I've tried but the value is not passing through.
Course Controller:
public function store(StoreCoursesRequest $request)
{
if (! Gate::allows('course_create')) {
return abort(401);
}
$request = $this->saveFiles($request);
$course = Course::create($request->all()
// $status = array('assigned' => 'assigned', 'canceled'=>'canceled');
+ ['position' => Course::where('curriculum_id', $request->curriculum_id)->max('position') + 1]);
$trainers = \Auth::user()->isAdmin() ? array_filter((array)$request->input('trainers')) : [\Auth::user()->id];
$course->trainers()->sync($trainers);
$course->roles()->sync(array_filter((array)$request->input('roles')));
$course->assigned_user()->sync(array_filter((array)$request->input('assigned_user')));
$curriculum = Curriculum::get(array('id' => 'id'));
$exam = Exam::get(array('id' => 'id'));
foreach ($request->input('course_materials_id', []) as $index => $id) {
$model = config('medialibrary.media_model');
$file = $model::find($id);
$file->model_id = $course->id;
$file->save();
}
session('id', 'id');
return redirect()->route('admin.exams.create');
}
Here is the exams controller
public function create()
{
if (! Gate::allows('exam_create')) {
return abort(401);
}
$exam_assigneds = \App\Exam::get()->pluck('title', 'id')->prepend(trans('global.app_please_select'), '');
$questions = \App\ExamQuestion::get()->pluck('question', 'id');
$in_classes = \App\InClassCourse::get()->pluck('title', 'id')->prepend(trans('global.app_please_select'), '');
$reoccurance_type = \App\ReoccuranceType::get()->pluck('type', 'id')->prepend(trans('global.app_please_select'), '');
$courses = session('id');
return view('admin.exams.create', compact('courses', 'exam_assigneds', 'questions', 'in_classes', 'reoccurance_type'));
}
Here is the view
<div class="row">
<div class="col-xs-12 form-group">
{!! Form::label('course_id', trans('global.exam.fields.course').'', ['class' => 'control-label']) !!}
{!! Form::text('id', $courses, old('id'), ['class' => 'form-control', 'placeholder' => '']) !!}
<p class="help-block"></p>
#if($errors->has('course_id'))
<p class="help-block">
{{ $errors->first('course_id') }}
</p>
#endif
</div>
</div>
All I'm getting is just text value of id. It doesn't pull the actual id.
In Course Controller modify
session('id', 'id');
to
session('id', $course->id);
I need to pass a value from a form(dropdwon) and append this value to a url.
My Routes are:
Route::get('menues/{city?}', 'PagesController#menue');
Route::post('/', 'PagesController#menue');
I have a simple form:
{!!Form::open(array('action' => 'PagesController#menue', 'method' => 'POST'))!!}
{!! Form::select('city', array('heilbronn' => 'Heilbronn', 'stuttgart' => 'Stuttgart')) !!}
{!!Form::submit('Senden')!!}
{!!Form::close()!!}
And this Controller:
public function menue(Request $request, $city = null) {
$searchinput = $request->input('city');
$restaurants = User::with(['articles' => function ($q){
$q->nowpublished();
}]);
if(!is_null($city) && !is_null(User::where('city', $city)->first())) {
$restaurants->where('city', '=', $city);
}
$restaurants = $restaurants->get();
return view('pages.menues')->withRestaurants($restaurants)
//->withArticles($articles)
->withCity($city)
->withSearchinput($searchinput);
}
I need to append the value ($searchinput) from the previous page to show only entries for a particular city.
You need to change your form method attribute to GET, then in your controller you can do follow:
public function menue(Request $request) {
$city = $request->city;
// bla-bla-bla
if ( ! is_null($city) && && ! is_null(User::where('city', $city)->first()) {
// bla-bla
}
// return
}
I have a company table and an attributes table with all sorts of value in it.
One company hasMany attributes and an attribute belongsTo a company.
Now I have a value inside the attributes table with a 'account_nr_start' (for example, when a new user is added to a company its account_id starts counting up from 1000).
Controller:
public function __construct(Company $company, User $user)
{
if(Auth::user()->usertype_id == 7)
{
$this->company = $company;
}
else
{
$this->company_id = Auth::user()->company_id;
$this->company = $company->Where(function($query)
{
$query->where('id', '=', $this->company_id )
->orWhere('parent_id','=', $this->company_id);
}) ;
}
$this->user = $user;
$this->middleware('auth');
}
public function edit(Company $company, CompaniesController $companies)
{
$companies = $companies->getCompaniesName(Auth::user()->company_id);
$attributes = $company->attributes('company')
->where('attribute', '=', 'account_nr_start')
->get();
foreach ($attributes as $k => $v) {
$nr_start[] = $v->value;
}
return view('company.edit', ['company' => $company, 'id' => 'edit', 'companies' => $companies, 'nr_start' => $nr_start]);
}
public function update(UpdateCompanyRequest $request, $company, Attribute $attributes)
{
$company->fill($request->input())->save();
$attributes->fill($request->only('company_id', 'attribute_nr', 'value'))->save();
return redirect('company');
}
HTML/Blade:
<div class="form-group {{ $errors->has('_nr_') ? 'has-error' : '' }}">
{!! HTML::decode (Form::label('account_nr_start', trans('common.account_nr_start').'<span class="asterisk"> *</span>', ['class' => 'form-label col-sm-3 control-label text-capitalize'])) !!}
<div class="col-sm-6">
{!! Form::text('value', $nr_start[0], ["class"=>"form-control text-uppercase"]) !!}
{!! $errors->first('account_nr_start', '<span class="help-block">:message</span>') !!}
</div>
</div>
When I update a company now, it will upload like the last input here: :
So it makes a new rule, while it needs to edit the current attribute rule instead of making a new rule with an empty company_id/attribute.
If I understand what you are trying to do, I think this will fix your problem. The issue you have is the Attribute model is a new instance of the model rather than retrieving the model you need.
before running fill() from the attributes method try this
$new_attribute = $attributes->where('company_id', '=', $company->id)->where('attribute', '=', 'account_nr_start')->first();
Then run the fill()
$new_attribute->fill($request->only('company_id', 'attribute_nr', 'value'))->save();
I am trying to pre-populate some fields in a form and I'm new to relationships.
My controller:
public function index($supplierId) {
$Supplier = new Supplier;
$supplierData = Supplier::find($supplierId);
$supplierData->countryId = ($supplierData->countryId == 0 ? 258 : $supplierData->countryId);
$supplierData->writtenLanguageId = ($supplierData->writtenLanguageId == 0 ? 1 : $supplierData->writtenLanguageId);
$supplierData->paymentTermsId = ($supplierData->paymentTermsId == 0 ? 5 : $supplierData->paymentTermsId);
$countries = Countries::lists('country', 'id');
$languages = Languages::lists('language', 'id');
$paymentTerms = PaymentTerms::lists('term', 'id');
$leadTimes = Leadtimes::lists('leadtime', 'id');
return View::make('supplier.supplier', array(
'supplierData' => $supplierData,
'countries' => $countries,
'languages' => $languages,
'paymentsTerms' => $paymentTerms,
'leadtimes' => $leadTimes
));
}
My model:
class Supplier extends Eloquent {
protected $table = 'suppliers';
public function email() {
return $this->hasOne('SupplierEmail', 'supplierId');
}
public function creditLimits() {
return $this->hasOne('SupplierCreditLimits', 'supplierId');
}
public function website() {
return $this->hasOne('SupplierWebsite', 'supplierId');
}
}
The problem:
<div class='col-xs-12 col-md-6'>{{Form::text('website', $supplierData->website->website, array('class' => 'form-control input-sm'))}}</div>
When there is no row (there is no record), I get:
Trying to get property of non-object (View: C:\wamp\vhosts\view\laravel\app\views\supplier\supplier.blade.php)
How do I get this to work properly?
In your view, use isset to check the value first:
<div class='col-xs-12 col-md-6'>
{{Form::text('website',
isset($supplierData->website->website) ? $supplierData->website->website : '',
array('class' => 'form-control input-sm'))
}}
</div>
Or, better yet, handle this logic in your controller and pass the result to the view:
$supplierData->URL = isset($supplierData->website->website) ? $supplierData->website->website : '';