Secure and clean code in laravel 5.1 - php

In fact i have a question about the clean of code
i try to get some value in blade file , I Am confused between two approaches
i think both are right but i need to know who's clean and secure more with the reason
First approach in my blade directly using Eloquent
#foreach
(Auth::user()->company->country->cities as $city) {{$city->name}}
#endforeach
Second approach using Injecting Services by create this method in my model and use it in my blade using laravel 5.1 Injecting Services
public function getCity()
{
foreach(Auth::user()->company->country->cities as $city) {
return $city->name ;
// OR
return $city ;
// i think this is one of benefits to use this approach
// because in my view i can use getCity()->id or getCity()->name
}
}
Thanks For Your Time .

Your second approach wouldn't work, because the function will finish while returning the name of the first city (or the first city itself). To make it work you could rewrite it, so that it returns all cities and loop through them in blade.
So if you use that function your code might look like:
#foreach($serviceName->getCities() as $city)
{{ $city->name }}
#endforeach
which is a nice thing, because the view doesn't have to care about where the cities will come from. If you use such a service on different views, it will be much easier to update.
Regarding security: There is no difference between those two approaches. As long as you print your output using the '{{ }}' operator. It'll prevent possible XSS attacks.

I think The best way that achieves MVC Design pattern whatever your code
public function getCities()
{
//in your model model
return $cities = Auth::user()->company->country->cities;
}
public function index()
{
//call return getCities();
}
//finally in your view loop over $cities
#foreach ($cities as $city)
{{$city->name}}
#endforeach

The best place to get your data from the model is in the controller, and then pass the data to the view:
This is a key-point of any MVC architecture that brings separation of concerns: your controller's purpose is to get the data from the model and to pass it to the views. The purpose of the view is to get the data from the controller and to present it. So, the only thing a view needs is a variable passed from the controller
This way the app logic is kept in the controller and it will be easy for you to mantain your application. So:
In your controller:
public function index()
{
//get data from model
$cities = Auth::user()->company->country->cities;
//pass the data to the view
return View::make('your_view', ['cities' => $cities] );
}
Then, in your view:
#foreach ($cities as $city)
{{$city->name}}
#endforeach

If you have setup eloquent relationship correctly then you should get the cities by using the following code
foreach(Auth::user()->cities as $city)
{
{!! $city->whatever !!}
}

Related

How to paginate in laravel 8?

I've followed this documnetation
(https://laravel.com/docs/8.x/pagination)
and made changes accordingly but still I am not able to paginate the required page.
This is my controller code:
public function showManageCourierAddress()
{
$viewdata = [];
$addressRepoObj = new \App\Repositories\Mongo\CourierAddressRepository();
$addressData = $addressRepoObj->getAddressList(0,(int)Session::get('organisation_id'));
$viewdata['addresslist'] = $addressData;
unset($addressData);
return view('frontend.admin.managecourieraddress', ['viewdata' => DB::table('viewdata')->paginate(15)]);
}
On the view laravel, I've added this :
{{ $viewdata->links() }}
Can anyone tell me where I'm going wrong? And what I should do?
DB::table('viewdata')->paginate(15)
returns LengthAwarePaginator instance, which implements these methods.
It is enought to call {{ $viewdata->links() }}, and it should return whole html with pagination buttons and links. You just write some styles for existing classes, or use methods as mentioned above to create your own html with your own structure.
If I did not understand your problem, please reply in comment.

Is there a better way to pass the variables inside nested for loop from the controller to the view?

I have a running code below using Laravel 7 (latest version) and PHP 7.4.4 (latest version) but I want to ask if there is a better way to implement.
So basically, the problem lies inside the nested for loop. I want to control the variables 'semesters' and 'subjects' in the controller and pass them to the view (index.blade.php). However, 'subjects' is dependent to the 'semesters', thus, I was forcibly written down the logic inside the blade template such as:
$subjects = $semester->subjects()->where(SOME QUERY HERE)->get()
See below for the code snippet:
index.blade.php
#foreach($semesters as $semester)
#if($subjects = $semester->subjects()->where(SOME QUERY HERE)->get())
#if($subjects->isNotEmpty())
//SOME CODE HERE
#foreach($subjects as $subject)
//SOME CODE HERE
#endforeach
#endif
#endif
#foreach
Is there a best way to implement this one?
Thanks in advance.
Edit
I am also worried about the query since it is inside the loop. However, I'll just change my design specs to limit the number of 'semesters' to be shown in the view. This is also to limit the query inside the loop. But, if you have a better implementation, please suggest. Thank you very much.
I think what you want is eager load some particular subjects with their respective semester.
$semesters = Semester::with([
'subjects' => function ($query) {
$query->where() // SOME QUERY HERE.
},
])
->get();
Now when you call $semester->subjects it returns only those filtered subjects.
Example Code
#foreach($semesters as $semester)
#if($semester->subjects->isNotEmpty())
//SOME CODE HERE
#foreach($semester->subjects as $subject)
//SOME CODE HERE
#endforeach
#endif
#foreach
Edit
Now you don't have to worry about querying in a loop. As you see we have already done loading. Which is called eager loading

Laravel 5 - Where should I write this function, and how?

Goodevening,
I have an overview page where I display all my project items.
I have a model (Project.php) a controller (ProjectController) where I send the variable $project (this includes all the information for each project) to the specific view.
Note: Each project has a own row in the database. (Quit obvious I guess)
Now I also have a table 'tasks' related to a specific project. In my view I wanna display how much of the total tasks are 'done'. (This is doing with the column 'done' (true/false, boolean)).
Now because I have a foreach function in my view (to display each individuele project) I can make the function in the view. But the Laravel framework is there for reasons. And writing out a lot of php in a view isn't the right way.
But, where should I make this function? And how can I use it in my foreach (in the view). Ofcourse I can make a new foreach in my model or controller and send that variable to my view. But then I can't use that one in my view-foreach as things will get mixed up.
I don't know how/where I can set up a function like this on a clean way.
Kinds regards,
Dylan
You can create a function in app directory(forexample app/Helpers/), or wherever you want and name it yourHelperFunction.php.
After creating that file, Laravel won’t recognize the file until it is registered inside composer.json file. Add files array inside autoload section.
.
.
.
"autoload": {
"files":[
"app/Helpers/yourHelperFunction.php"
]
}
.
.
.
then do composer dump autoload and you are ready to use the function inside the blade
Use Blade engine, not Core PHP loops.
It is wise to use blade engine then core php codes.
You can see the documentation
Laravel 5 Blade Template
Thanks for the help. I've figured it out (I guess?).
I have this function in my Project Model.
public function getTaskDonePercentage($id) {
$tasks = Task::where('project_id', $id)->count();
$tasks_done = Task::where([
['project_id', $id],
['status', 'done']
])->count();
if ($tasks_done > 0) {
$calc = ($tasks_done / $tasks) * 100;
}
else {
$calc = '100';
}
return round($calc) . '%';
}
Then in my view I just call the function in the foreach like:
#foreach
{{ $project_item->getTaskDonePercentage($project_item->id) }}
#endforeach
Tbh I still wanna know if this approach is a good one. (Or, if not, why it isnt?).
Thanks!

Two Controllers and 1 View in Laravel

I have one issue to solve about some calculations in Laravel 5.1, and until now the best solution that I found is to create Two different controllers, one to handle calculation for a specific item:
Route::get('company/convert/{note}','ScenarioController#NoteConvert');
And one for all items:
Route::get('company/convert','ScenarioController#AllNotesConvert');
Both will use render the same view.
My question is: Is a good practice to do this ?
In my head one good solution is to use just one route and receive 1 specific note or all of them in some variable through the request.
Something like:
$http.get('/company/convert/',data)
Where data will receive 1 or all notes that will be converted.
P.S.: I'm using AngularJS to call this routes.
If you prefer having one method in your controller you have to change your route a bit:
Route::get('company/convert/{note?}','ScenarioController#NoteConvert');
And your method would be something like
public function NoteConvert($note=null)
{
if ($note == null) {
// do all convertions
return view()
}
// single convertion
...
}
This way NoteConvert method will be the one that will handle multiple and single convertions.
Don't forget to remove
Route::get('company/convert','ScenarioController#AllNotesConvert');
It won't be necessary anymore
Edit:
https://laravel.com/docs/5.2/routing#parameters-optional-parameters
the best way for me, will be to passe an optional parameter in the url and check it on the controller.
i think your task is to produce the data of all items and specific data with filter using note argument in the view.
i reccomend you to create the route like this
Route::controller('company', 'ScenarioController');
then create a controller with two function like this
public function getIndex()
{
return view('convert');
}
here convert is name view blade .
public function postFilter($note)
{
$x= // do what you want
return view('convert', compact('x'));
}
then add a filter in the blade using a checkbox and make the form action url as
"company/filter/{note}".
this is the better practice i think.
refer implicit routing here. https://laravel.com/docs/5.1/controllers

Passing data to views without "with()" in view composers

I love the way of passing data to views in Laravel. But I don't use the "with" methode, I prefer to pass all my data as the second argument in the view helper function:
$data = [
'name' => Auth::User() -> name
]
return view('dashboard', $data);
Now it's very easy to use my data in the view:
Hello {{ $name }}
There's no need to do
Hello {{ $data['name'] }}
But here is my problem:
I want to do the same in a view composer. But the only way I have seen to pass data to views with view composers is this:
public function compose(View $view)
{
$data = [
'name' => Auth::User() -> name
]
$view -> with('data', $data);
}
But this requires me to do
Hello {{ $data['name'] }}
in my view, which I don't want. I want to use the short syntax. So is there a way to pass it like I described above? As second argument of the view function?
Thanks
Just step through each part of your array with a foreach loop:
foreach($data as $key => $value) { $view->with($key, $value); }
In answer to your question about just calling the view function an passing values, the answer is no, you can't do it that way.
Think about what you're doing in your first example. When you call view('template', $data), you're calling a helper function defined in the Laravel core. What is that function doing? It's instantiating a view, probably by calling View::make()->with(). In other words, behind the scenes it's doing the thing you want to avoid.
Now how would that work with a view composer? I imagine it would go something like this:
In your controller, you call view('template', $somedata).
You now have a view object with $somedata included.
On the way to rendering the HTML page, Laravel calls your view composer, passing along the view object you created a moment ago.
Then you call view($newdata) (or something like that - I'm not clear on what the syntax would be) and it would attach the new data to the existing view object. But this is not something that the Laravel developers have done. That's not to say it couldn't be done, it is just not a use case that they considered.
What you can do is step through your new data in the view composer and add the individual values to the existing view, like this:
foreach ($newdata as $key => $value) {
$view->with($key, $value);
}

Categories