Creating a filtered search based on different parameters - laravel

i need to create a filtered search based on different paramnters chosen by a user. So, for example, my app is a property app. I want them to be able to define the county, town, max,min bedrooms ect from a dropdown list and press search, and this returns all the properties that match the criteria.
How do I go about doing this? I can't find any tutorials online, but maybe I'm not phrasing it right.
Here is an image of what I'm after from a UI point of view.
https://imgur.com/a/YEEqt

The following is an easy to go solution considering your experience.
Create a new controller or a method in an existing one.
First create a simple form (method GET) in blade that will return predefined values from simple hidden fields
Create a new GET route in which the form must be submitted and link it to the controller method that you created
In your controller method get the submitted form data from your request, make the correct queries and return the blade template file that contains the form with the results
Modify blade template to show results
Finally replace the hidden fields with selects drop-downs and modify your controller in order to populate them
You can make the form submission process and the select drop-down fields population asynchronous but based on your experience with Laravel it should be hard. Following the steps above will do your job.
Always take a look to the official documentation. You will ge a lot of help from there.

You can try like this for filter options in your controller
public function filter(Request $request, Property $property)
{
$property = $property->newQuery();
// Search for a property based on country
if ($request->has('country')) {
return $property->where('country', $request->input('country'));
}
// Search for a property based on their area.
if ($request->has('areas')) {
return $property->where('areas', $request->input('areas'));
}
// Search for a property based on max_price
if ($request->has('max_price')) {
return $property->where('price','<=', $request->input('max_price'));
}
// Continue for all of the filters.
return $property->get();
}
For more info refer the link

Related

Spring boot + JPA(Hibernate) Edit partial entity fields

all.
I have following simple form in which I want to edit the entity. The problem is that I have some fields which I don't want to be edited. For example (Image file path).
As it is now, I have the service method -
public void addOrModifyLayout(Layout layout){
if(layout.getId() == null){
layoutRepository.save(layout);
}
else {
Layout modifiedLayout = new Layout();
modifiedLayout.setId(layout.getId());
modifiedLayout.setName(layout.getName());
modifiedLayout.setStatus(layout.getStatus());
modifiedLayout.setExhibitor(layout.getExhibitor());
layoutRepository.save(modifiedLayout);
}
}
As you can see, every field that I want to be able to be edited, I should explicitly put it in the service. Can I use some mapper or trick to update only some fields that are in the view (form) ? How you handle this kind of issues?
You can either
store all the entity fields in hidden inputs (e.g. imageFilePath hidden input). So you can store on UI all the entity fields and get them back to assign to the entity.
OR
Avoid new entity creation but retrieve existing one and fill only necessary fields.
Layout modifiedLayout = layoutRepository.getById(layout.getId());
modifiedLayout.setName(layout.getName());
modifiedLayout.setStatus(layout.getStatus());
modifiedLayout.setExhibitor(layout.getExhibitor());
layoutRepository.save(modifiedLayout);

Yii2: How to avoid required fields in a view?

I have a view about holidays where a user uses a form to choose a place to travel and a hotel. It has two models: HolidaysPlaces and HolidaysHotels.
The user have to fill the form in this order using the view:
The user completes the fields called Place and City (related with the HolidaysPlaces model).
The user checked a checkbox if he/she wants to choose a hotel. It able a field called Hotel (related with HolidaysHotels model).
The user completes that field.
The user press a Create button.
The controller receives and saves both models.
But the problem is when the user doesn't select the checkbox (number 2 of the list): The Hotel fieldis still required (with the red asterisk as defined in its model file). So the Create button doesn't work in this case.
How can I disabled the required feature?
Add a scenario for this case in your HolidaysHotels model, and include only the fields that you want checked.
Example: If you have 3 fields name, date and age that are required, create a scenario for two only, and set the scenario in the controller. Only those two fields will be checked.
In model:
public function scenarios(){
$scenarios = parent::scenarios();
$scenarios['create'] = ['name', 'date'];
return $scenarios;
}
In controller:
$holiday = new HolidayHotels();
$holiday->scenario = 'create';
To know more about scenarios: http://www.yiiframework.com/doc-2.0/guide-structure-models.html#scenarios
You can add some condition based validation in your model rules. Here is the snippet for both client and server validation. You can many conditions inside the function block.
['field-1', 'required', 'when' => function ($model) {
return $model->check_box == '1';
}, 'whenClient' => "function (attribute, value) {
return $('#checkbox-id').is(':checked') ';
}"],
The easiest way to solve it is to send the model with empty strings. Then the controller checks if the strings are empty. If so, the model is not saved. Else, it is saved.
It was the only way that works for me.

Laravel Backpack : Storing Belongs To Many relationships using custom view

I have a flight class and this flight has a custom view field like so:
This represents a belongs to many relationship which stores website_id / flight_id and pricing as pivot data in a pivot table.
The custom view uses JS to send this data back to the controller in this format:
{"1":{"price_adult":"434","price_child":"545"},"2":{"price_adult":"323","price_child":"324"},"3":{"price_adult":"434","price_child":"43"}}
Trying to send this data with the request doesn't create the relations fields, and because I do not have a flight ID at the point of creating this within the controller I can not loop this JSON to make the relations manually.
Can anyone point out what the best course of action is or if there is support for this? I took a look at the docs but they are woefully short and patchy in terms of being much help.
EDIT:
I should have said I can probably make this work using a custom name attribute on the model for the relation, then add a set mutator to loop this data and update the prices relation but I don't want to go down this route if there is support for this I am missing out of the box in backpack.
EDIT2:
Someone asked about the relation:
$this->belongsToMany(Website::class, 'website_pricing')->withPivot('price_adult', 'price_child');
This is working fine its not a problem with the relation working its how can I get backpack to store the data as a relation when the flight has no ID yet, or how can I pass the data I posted above in such a way that the backpack crud controller can handle it?
You may need to create a flight first, if no flight id is being provided. Can you explain the database relational structure more?
Basically thought I should post what I did because no one could provide an answer to this.
So basically you have to copy the store / update functions from the parent, changing a few lines.
$this->crud->hasAccessOrFail('create');
// fallback to global request instance
if (is_null($request)) {
$request = \Request::instance();
}
// replace empty values with NULL, so that it will work with MySQL strict mode on
foreach ($request->input() as $key => $value) {
if (empty($value) && $value !== '0') {
$request->request->set($key, null);
}
}
// insert item in the db
$item = $this->crud->create($request->except(['save_action', '_token', '_method']));
$this->data['entry'] = $this->crud->entry = $item;
// show a success message
\Alert::success(trans('backpack::crud.insert_success'))->flash();
// save the redirect choice for next time
parent::setSaveAction();
return parent::performSaveAction($item->getKey());
Basically any line which references a function in the parent class using $this->method needs to be changed to parent::
This line is what I used to submit the relations JSON string passed to the controller as relations $item->prices()->sync(json_decode($request->input('prices'), true));
This is done after the line containing $item = $this->crud->create as the item id that just got stored will be available at that point.

How do I bypass the limitations of what MVC-CORE controllers can pass to the view?

From what I've read, I'm supposed to be using ViewModels to populate my views in MVC, rather than the model directly. This should allow me to pass not just the contents of the model, but also other information such as login state, etc. to the view instead of using ViewBag or ViewData. I've followed the tutorials and I've had both a model and a viewmodel successfully sent to the view. The original problem I had was that I needed a paginated view, which is simple to do when passing a model alone, but becomes difficult when passing a viewmodel.
With a model of
public class Instructor {
public string forename { get; set; }
public string surname { get; set; }
}
and a viewmodel of
public class InstructorVM {
public Instructor Instructors { get; set; }
public string LoggedIn { get; set; }
}
I can create a paginated list of the instructors using the pure model Instructor but I can't pass InstructorVM to the view and paginate it as there are other properties that aren't required in the pagination LoggedIn cause issues. If I pass InstructorVM.Instructors to the view, I get the pagination, but don't get the LoggedIn and as this is just the model, I may has well have passed that through directly.
An alternative that was suggested was to convert/expand the viewmodel into a list or somesuch which would produce an object like this that gets passed to the view
instructor.forename = "dave", instructor.surname = "smith", LoggedIn="Hello brian"
instructor.forename = "alan", instructor.surname = "jones", LoggedIn="Hello brian"
instructor.forename = "paul", instructor.surname = "barns", LoggedIn="Hello brian"
where the LoggedIn value is repeated in every row and then retrieved in the row using Model[0].LoggedIn
Obviously, this problem is caused because you can only pass one object back from a method, either Instructor, InstructorVM, List<InstructorVM>, etc.
I'm trying to find out the best option to give me pagination (on part of the returned object) from a viewmodel while not replicating everything else in the viewmodel.
One suggestion was to use a JavaScript framework like React/Angular to break up the page into a more MVVM way of doing things, the problem with that being that despite looking for suggestions and reading 1001 "Best JS framework" lists via Google, they all assume I have already learned all of the frameworks and can thus pick the most suitable one from the options available.
When all I want to do is show a string and a paginated list from a viewmodel on a view. At this point I don't care how, I don't care if I have to learn a JS framework or if I can do it just using MVC core, but can someone tell me how to do this thing I could do quite simply in ASP.NET? If it's "use a JS framework" which one?
Thanks
I'm not exactly sure what the difficulty is here, as pagination and using a view model aren't factors that play on one another. Pagination is all about selecting a subset of items from a data store, which happens entirely in your initial query. For example, whereas you might originally have done something like:
var widgets = db.Widgets.ToList();
Instead you would do something like:
var widgets = db.Widgets.Skip((pageNumber - 1) * itemsPerPage).Take(itemsPerPage).ToList();
Using a view model is just a layer on top of this, where you then just map the queried data, no matter what it is onto instances of your view model:
var widgetViewModels = widgets.Select(w => new WidgetViewModel
{
...
});
If you're using a library like PagedList or similar, this behavior may not be immediately obvious, since the default implementation depends on having access to the queryset (in order to do the skip/take logic for you). However, PagedList, for example has StaticPagedList which allows you to create an IPagedList instance with an existing dataset:
var pagedWidgets = new StaticPagedList<WidgetViewModel>(widgetViewModels, pageNumber, itemsPerPage, totalItems);
There, the only part you'd be missing is totalItems, which is going to require an additional count query on the unfiltered queryset.
If you're using a different library, there should be some sort of similar functionality available. You'll just need to confer with the documentation.

Laravel 5 - generic document management

I have a system where you can create different types of unique documents. For instance, one document is called Project Identified and this expects certain inputs. Originally, I had a database table for each unique document type, but this was getting messy fast. So, I created a database structure that was more generic, and came up with the following
So, I create a project. Within the projects show page, I can select the type of document I want to create e.g.
<li>{!! link_to_route('projects.documents.create', 'Project Identified', array($project->id, 'documentType' => 'projectIdentified')) !!}</li>
Now if I select to create a Project Identified document, it uses the generic Document Controller to handle things. Because the link to route has a documentType param, I can grab the value of this from the url. As such, in my Document Controllers create function, I am doing the following to display the correct view for the document
public function create(Project $project)
{
$documentType = $_GET["documentType"];
if($documentType == "projectIdentified") {
return View::make('projectIdentifiedDoc.create', compact('project'));
}
}
This view has a form which is binded
{!! Form::model(new App\Document, [
'class'=>'form-horizontal',
'route' => ['projects.documents.store', $project->id]
]) !!}
However, within the document controllers store function, I once again need to get the documentType. How can I pass this within the forms model? Also, is this the correct way to do this or is there a more efficient way?
Thanks
Have you read the documentation on relationships?
https://laravel.com/docs/5.2/eloquent-relationships
You need to define the relationship within your model.
So if a document only has one documentType, within your document model, you would define
public function documentType()
{
return $this->hasOne('App\documentType');
}
The different types of relationship, how to define them, and then how to access that data, is all very well documented.

Resources