Filter items by category in Laravel October - laravel

I have a document model with a $belongsTo categories relationship, everything is working well and I'm able to assign categories to documents and list them all on the frontend, but what I'm struggling with is filtering the results by category.
I have 3 categories and 3 col-md-4 columns, in each column, the documents should be listed and filtered via their category, how do I do this with twig using components?
My documents.default component file looks like this:
{% set documents = __SELF__.documents %}
<ul class="record-list list-unstyled ">
{% for document in documents %}
<li class="ul-text-black">
{{document.name }}
</li>
{% endfor %}
</ul>
My documents component code:
<?php namespace Myplugin\Documents\Components;
use Cms\Classes\ComponentBase;
use Myplugin\Documents\Models\Document;
class Documents extends ComponentBase
{
public function componentDetails(){
return [
'name' => 'Documents List',
'description' => 'Custom Component to list documents by category'
];
}
public function defineProperties(){
return [
'results' => [
'title' => 'Number of Documents',
'description' => 'How many documents do you want to display?',
'default' => 24,
'validationPattern' => '^[0-9]+$',
'validationMessage' => 'Only numbers allowed'
],
'sortOrder' => [
'title' => 'Sort Documents',
'description' => 'Sort documents',
'type' => 'dropdown',
'default' => 'name asc',
]];
}
public function getSortOrderOptions(){
return [
'name asc' => 'Name (ascending)',
'name desc' => 'Name (descending)',
];
}
public function onRun()
{
$this->documents = $this->loadDocuments();
}
protected function loadDocuments(){
$query = Document::all();
if ($this->property('sortOrder') == 'name asc') {
$query = $query->sortBy('name');
}
if ($this->property('sortOrder') == 'name desc') {
$query = $query->sortByDesc('name');
}
if ($this->property('results') > 0) {
$query = $query->take($this->property('results'));
}
return $query;
}
public $documents;
}
My page looks like this
<div class="row">
<div class="col-md-4">
<p class="text-black">
<strong>FINANCIAL</strong>
</p>
{% component 'documents' %} // Only documents from financial category
</div>
<div class="col-md-4">
<p class="text-black">
<strong>ANALYTICS</strong>
</p>
{% component 'documents' %} // Only documents from analytics category
</div>
<div class="col-md-4">
<p class="text-black">
<strong>INVESTMENT</strong>
</p>
{% component 'documents' %} // Only documents from investment category
</div>
How do I display the documents list but filter them by category? Something like this?
{% partial "documents-financials" category="Financials" %}

You should be able to access the properties in your Documents component using $category = $this->property('category');
There's documentation on accessing component properties on the OctoberCMS website: https://octobercms.com/docs/plugin/components#component-properties
I can then see that you're loading all documents and filtering them using the Laravel Collection. I would suggest changing this and doing it on the database first. It'll be far more efficient.
$category = $this->property('category');
$results = $this->property('results');
$documents = Document::whereHas('category', function ($query) use ($category) {
return $query->where('name', $category);
})
->orderBy('name', 'ASC')
->take($results)
->get();
If you want to group your documents and then output them, you could do the following:
$this->documents = Document::with('category')
->orderBy('name', 'ASC')
->take($results)
->get()
->groupBy('category.name');
See https://laravel.com/docs/5.3/collections#method-groupby
Then in your component template:
<div class="row">
{% for group in documents %}
<div class="col-md-4">
<p class="text-black">
<strong>FINANCIAL</strong>
</p>
<ul class="record-list list-unstyled">
{% for document in group %}
<li class="ul-text-black">{{document.name }}</li>
{% endfor %}
</ul>
</div>
{% endfor %}
</div>

Related

Problemes in retrieving completed courses

I'm new on Laravel 6 and build an application for students. The tables of my database look as follows:
$courses
-program_id
-title
$projects
-user_id
-course_id
-title
-completed
-comments
I have two users with different rights (Admin and Member). The Admin user can decide if a project is completed or not (checkbox). Each project belongs to a course (course_id).
I have a success.blade.php which looks as follows:
#extends('layouts/app')
#section('content')
<div class="row justify-content-center">
<div class="jumbotron col-8">
<h4 class="display-4">{{ __('Finished Projects') }}</h4>
<ol>
#foreach(Auth::user()->projects as $project)
#if($project->comments)
#if($project->completed === 1)
<li>{{ $project->title }}</li>
#endif
#endif
#endforeach
</ol>
{{ __('Back')}}
</div>
</div>
#endsection
This file retrieves completed projects, but I would like to retrieve the courses of the completed projects instead. How can I solve this?
My Controller method looks like this:
public function success()
{
$programs = Program::orderBy('name')->get();
$courses = Course::orderBy('title')->get();
$projects = Project::orderBy('title')->get();
return view('/success', [
'programs' => $programs,
'courses' => $courses,
'projects' => $projects
]);
}
you can access to desire course with this query for each project that is completed:
$course = Course::find($project['course_id']);
Using relationships
https://laravel.com/docs/7.x/eloquent-relationships
// From controller you can do
$courses = Course::whereHas('project', function($q){
$q->where('completed', true);
})->get();
// Also this way
$completedProjects = Project::where('completed', true)->get();
// Blade view
#foreach($completedProjects as $project)
#foreach($project->courses as $course)
{{ $course->title }}
#endforeach
#endforeach

Problems with Laravel Pivot Table

I am working on a medical lab application in laravel where I have the following tables:
1. Test table: This is a table which stores all the information related to medical tests:
2: Checkup: This is a page which contains all the patient information along with the tests he/she takes.
This is the test page:
This is the Checkup page where the tests and their results are selected:
Here can be many tests and user can check any number of them and will write the result of the test in the textfield below the checkbox.
I get this data in the controller like below code and save it to the database:
$this->validate($request,
[
'patient_name' => 'required|max:50',
'patient_age' => 'required',
'gender' => 'required',
'patient_type' => 'required',
'technition_id' => 'required',
'result' => 'required',
'test' => 'required',
'amount' => 'required'
]);
if( ($request->patient_type == 2) && ($request->doctor_id==0) )
{
return redirect()->back()->withInput(Input::all())->withErrors(['message' => 'Please select a valid Doctor.']);
}
$checkup = new Checkup;
$checkup->patient_name = $request->patient_name;
$checkup->patient_age = $request->patient_age;
$checkup->gender = $request->gender;
$checkup->patienttype_id = $request->patient_type;
$checkup->technition_id = $request->technition_id;
if(isset($request->doctor_id))
{
$checkup->doctor_id = $request->doctor_id;
}
$checkup->amount = $request->amount;
// $checkup->result = $request->result;
$checkup->save();
$tests =[];
$tests = $request->test;
$results =[];
$results = $request->result;
//$checkup->tests()->attach($tests->id, ['result' => $result]);
$sync_data = [];
for($i = 0; $i < count($tests); $i++)
$sync_data[$tests[$i]] = ['result' => $results[$i]];
$checkup->tests()->sync($sync_data);
Session::flash('success', 'The record was successfully saved.');
return redirect()->route('checkups.index');
Now the problem is that when I check all the checkboxes and write the result of all the tests then it is fine but when I select some and leave some of them then it gives error and the error comes because the result textbox for the unchecked test is empty.
This is the case when I select one test and leave the others:
When I check on test and write the result of it and then var_dump both test and result arrays i get the below output:
In the above image we can see that the test array contains one item because only one checkbox was checked but the result array contains two items and the first one is NULL which belongs to the unchecked checkbox.
This is the view file of the checkboxes and the textfields:
{{ Form::label('tests', 'Tests Taken') }}
#foreach(App\Test::all() as $test)
<div class="checkbox checkbox-switchery">
{{ Form::label('test', $test->name) }}
<input name="test[]" value="{{ $test->id }}" type="checkbox" class="switchery-primary">
</div>
<div>
{{ Form::label('result', "Result") }}
<input name="result[]" type="text" class="form-control">
</div>
#endforeach
<div class="form-group">
{{ Form::label('amount', 'Amount') }}
{{ Form::text('amount', null, ['class' => 'form-control']) }}
</div>
<div class="form-group">
{{Form::button('<i class="fa fa-save"> Save</i>', ['type' => 'submit', 'class' => 'btn btn-success'])}}
</div>
{!! Form::close() !!}
Please help me on this and show me how to insert the pivot table data properly to the system.
Thanks in advance for any help.
Try this..
In your blade file :
#foreach(App\Test::all() as $index => $test)
<div class="checkbox checkbox-switchery">
{{ Form::label('test', $test->name) }}
<input name="test[{{ $index }}]" value="{{ $test->id }}" type="checkbox" class="switchery-primary">
</div>
<div>
{{ Form::label('result', "Result") }}
<input name="result[{{ $index }}]" type="text" class="form-control">
</div>
#endforeach
Instead of the for loop you can use foreach lopp.
$sync_data = [];
foreach($tests as $index => $value) {
if(!empty($results[$index]) {
$sync_data[$value] = ['result' => $results[$index]]
}
}
$checkup->tests()->sync($sync_data);

Laravel 5.0: Route with query string

I am using laravel 5.0, I am sending a query string on A tag with an id.
I am getting id but not the query string data
Below is the code:
View
<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4">
<div class="img-decor">
<a href="{{url('buycarddetail/'.$retailer->id)}}" class="">
<img src="{{ assetnew('uploads/client_image/'.$retailer->image) }}" alt="..." class="img-rounded" width="200">
</a>
<div class="deals-title">
{{ $retailer->name }}
<div class="sub-details">Save up to {{ $retailer->discount }}%</div>
</div>
</div>
</div>
Controller
public function buycarddetail($id = null, Request $request)
{
echo $id;
echo '<pre>'; $data = $request->all(); exit;
return view('buycarddetail');
}
Route
Route::get('buycarddetail/{id}', ['as' => 'buycarddetail', 'uses' => 'HomeController#buycarddetail']);
I want to use the query string data for further process on controller
Please help
Based on your code you're not actually appending any query string when generating the link {{url('buycarddetail/'.$retailer->id)}}.
As per your comments you can do this to generate a link to your route with the query string.
{{ route('buycarddetail', ['id' => $retailer->id, '_token' => csrf_token(), 'brand' => 'test', 'buybrand' => 'example']) }}
This example would generate a link like
http://example.com/buycarddetail/17?_token=QHE8va7stXUOPabwTjKmXyJxdsuPSZ9VbH3uThwx&brand=test&buybrand=example

Laravel 4 search - in view, show value submitted in form

Below is the beginnings of filter form I have built. It works ok but what I'd like to do is retrieve in my view, the values entered for. So, in this example I'd like to display "you searched by 'the keyword user entered'", and also display this within the keyword text field. This will be the same principle when I add select lists.
If the user wishes to change filter settings, or paginate through the results, the values are always stored.
My question is how to do this. I'm quite sure it's possible in laravel but only know how to do this in PHP
FORM
<div class="row">
{{ Form::open(array('url'=>'events/search', 'class'=>'form-search', 'role'=>'form')) }}
<div class="col-lg-6">
<div class="input-group">
{{ Form::text('search', '', array('class'=>'form-control', 'placeholder'=>'Search by keyword.'))}}
<span class="input-group-btn">
{{ Form::submit('Search', array('class'=>'btn btn-default'))}}
</span>
</div>
</div>
{{ Form::close() }}
</div>
SEARCH CONTROLLER
public function postSearch() {
$search = Input::get('search');
$events = DB::table('events')
->where(function($query) use ($search)
{
$query->where('title', 'LIKE', '%' . $search . '%')
->where('date','>=', DB::raw('CURDATE()'));
})
->orderBy('date', 'DESC')
->get();
$this->layout->content = View::make('events.results',
array(
'events' => $events
)
);
}
VIEW
#foreach($events as $event)
<div class="col-md-9">You search for ''</div>
{{-- filter form will again display here --}}
<h2>{{ HTML::link("events/$event->id/", "$event->title") }}</h2>
#endforeach
Controller:
public function postSearch() {
$search = Input::get('search');
$events = DB::table('events')
->where(function($query) use ($search)
{
$query->where('title', 'LIKE', '%' . $search . '%')
->where('date','>=', DB::raw('CURDATE()'));
})
->orderBy('date', 'DESC')
->get();
$this->layout->content = View::make('events.results',
array(
'events' => $events,
'search' => $search <-------- pass the search parameter to view
)
);
}
View:
#if(!empty($search))
<div class="col-md-9">You search for {{$search}}</div>
#endif
#foreach($events as $event)
{{-- filter form will again display here --}}
<h2>{{ HTML::link("events/$event->id/", "$event->title") }}</h2>
#endforeach
Two issues:
Generally search forms are GET and not POST. (easier to bookmark, give the links elsewhere)
put the search term outside the loop.

HasMany relationship old input

I have a model Category. Category has many Localization. When I store Category, I have these inputs:
{{ Form::text('title[en]', Input::old('title')) }}
{{ Form::text('title[ru]', Input::old('title')) }}
Which I store like this in my controler:
// Gett all inputs
$inputs = Input::all();
// Create resource
$item = Category::create([]);
// Create localization
foreach(Input::get('title') as $locale => $title)
{
$locale = new Localization(['locale' => $locale, 'title' => $title]);
$locale = $item->localization()->save($locale);
}
That works great but what is the best practise for updating such relationships? Currently I'm trying that with Form::model binding.
#foreach($locales as $key => $locale)
{{ Form::text('title['.$locale.']', $model->translate($locale)->title, ['class' => 'form-control']) }}
#endforeach
I have no idea how Input::old could work in this situation, so now I'm using $model->translate($locale)->title to get the correct value. Basically the updating/validation part doesn't really work. What you could suggest to change to validate such relationship and update it?
Today I found a working solution storing/updating relationships with validation. I hope it's the best/simplest way to do that. I created a new array with inputs for validation and changed in the view errors accordingly.
This is my update controller.
public function update($id)
{
// Find resource
$item = Category::find($id);
foreach(Input::get('title') as $locale => $title)
{
$v['title_'.$locale] = $title;
}
// Attempt validation
if($item->validate($v))
{
foreach(Input::get('title') as $locale => $title)
{
$localization = $item->translate($locale);
$localization->title = $title;
$localization->save();
}
return Redirect::action('AdminCategoryController#edit', [$item->id]);
}
else
{
// Failure, get errors
$errors = $item->errors();
return Redirect::back()
->withInput()
->with('errors', $errors);
}
}
And this is the update view;
{{ Form::model($model, ['action' => ['AdminCategoryController#update', $model->id], 'method' => 'PUT']) }}
#foreach($locales as $key => $locale)
<div id="{{ $locale }}">
<div class="form-group">
{{ Form::label('title['.$locale.']', _('admin.title_'.$locale)) }}
{{ Form::text('title['.$locale.']', $model->translate($locale)->title, ['class' => 'form-control']) }}
#if($errors->has('title_'.$locale))
<div class="help-block alert alert-danger">{{ $errors->first('title_'.$locale) }}</div>
#endif
</div>
</div>
#endforeach
{{ Form::close() }}
This way you can easily CRUD, validate all types of relationships (input arrays) in Laravel.

Resources