I am showing data to back end users in a tabular format. I am using Laravel 5 and pagination can be handled with ease.
There is a small requirement when it comes to where to place those links of pages: I want to float them right. Considering that Laravel is using Bootstrap 3 to render the layout, I know I can simply add class "pull-right" into the element.
So I constructed a custom pagination presenter like so:
namespace App\Http\Presenters;
use Illuminate\Pagination\BootstrapThreePresenter;
class DatatablePaginationPresenter extends BootstrapThreePresenter{
public function render()
{
if ($this->hasPages())
{
return sprintf(
'<ul class="pagination pull-right">%s %s %s</ul>',
$this->getPreviousButton(),
$this->getLinks(),
$this->getNextButton()
);
}
return '';
}
}
And the code in the template file:
<div class="row">
<div class="col-md-4">Some text</div>
<div class="col-md-8">
{!! with(new App\Http\Presenters\DatatablePaginationPresenter($articles))->render() !!}
</div>
</div>
Laravel works without errors until I add some parameters in those links by calling appends(), for example:
{!! with(new App\Http\Presenters\DatatablePaginationPresenter($articles))->appends(['sort' => $column,'order' => $order,'term' => $term])->render() !!}
This time I got a FatalException saying Call to undefined method App\Http\Presenters\DatatablePaginationPresenter::appends()
I walked through some source code to find out how appends() works. It is declared in the \Illuminate\Contracts\Pagination\Paginator interface, and any class implements this interface should define it. Given that my Article class extends Eloquent, getting a paginated collection should get a paginator which already implements appends().
So it is really weird that appends() is not defined.
Here is the code of my repo/service layer returning paginated data to my controller.
$articles = Article::with('category')
->select($columns)
->orderBy($column,$order)
->paginate($itemPerPage);
return $articles;
I checked the Laravel source again and found out what's going wrong.
It was my mistake that thinking BootstrapThreePresenter implements the Paginator Interface, but it does not. So it is wrong to call appends() on Presenter object.
{!! with(new MyPresenter($paginatorObject))->appends(array())->render() !!}
Instead, I have to call appends() on a Paginator instance first, in my case the $articles, then pass it to custom presenter constructor.
{!! with(new MyPresenter($paginatorObject->appends(array())))->render() !!}
Related
I found several ways to do what I need to do, the first way was using the rounting using the web.php file. But according to serveral posts this creates vulnerabilities in the application. So I found out the correct usage is with a controller that manages the database queries.
I created a controller, named EventsController and put this into it:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class EventsController extends Controller
{
public function index()
{
$events = DB::table('eventaries')->select('id','coursname','start', 'end', 'category')->get();
return view('components.course-list')->with('eventaries', $events);
}
}
the blade is inside the folder: /resources/views/components/course-list.blade.php
Inside the blade I use this code:
<div class="px-6 py-20">
<div class="max-w-7xl mx-auto">
<!-- Course List -->
{{ $events->coursname}}
</div>
</div>
But I get the error:
Undefined variable $events (View: D:\laragon\www\censored\resources\views\components\course-list.blade.php)
When using the with method on a view the first argument (key) becomes the name of the variable in the view and the second argument (value) becomes it's value.
This means you need to use $eventaries in your view instead of $events or rename the key in your controller return view('components.course-list')->with('events', $events);.
Also, I'm not sure about defining the action directly in the routes file causes vulnerabilities. I just think that the routes file, which is often the first entry point for developers when exploring a Laravel app, becomes hard to read/manage.
->with('eventaries', $events) means that you are passing the value of $events as eventaries. So in the blade you need to access it using $eventaries instead. So now blade code would be:
<div class="px-6 py-20">
<div class="max-w-7xl mx-auto">
<!-- Course List -->
{{ $eventaries->coursname}}
</div>
</div>
You have given 'eventaries' as the name for events. So you can only access it with $eventaries within the view, not as events.
you are passing to the view the value using the "with" method, and it does it like a value/key pair (->with($key, $value)). In your case you declare it like
return view('components.course-list')->with('eventaries', $events);
so, in the view you can access the value through the $eventaries, not the $events. Also, the query result is a collection and you will need to loop it to get each item
<div class="px-6 py-20">
<div class="max-w-7xl mx-auto">
<!-- Course List -->
#foreach($eventaries as $event)
{{ $event->coursename }}
#endforeach
</div>
</div>
What caused the issue?
The issue of this question was created because the router was never accessing the controller I created. I added the following code to my router to access the controller:
Route::get('/kursangebote/{course}', ['App\Http\Controllers\EventaryController', 'index'])->name('course.list-list');
In there I added the logic I wanted.
['App\Http\Controllers\EventaryController', 'index']
App\Http\Controllers\EventaryController is the controller I use, and index the function inside the controller I need to call. It might be a better Idea to use Eloquent for this https://laravel.com/docs/8.x/eloquent
This is my helper function one which render input field in blade
{!! Helpers::render_input('settings[companyname]','Company Name',Helpers::get_option('companyname'),'text',array('autofocus'=>true)) !!}
I also tried this way, but it is not working.
{!! Helpers::render_input('settings[companyname]','Company Name',self::get_option('companyname'),'text',array('autofocus'=>true)) !!}
I am calling other function Helpers::get_option('companyname') in above function.Both function individually working fine.So i am finding a way to call one helper function within another helper function in laravel blade.
Is there anyway to call function this way?
Here is my situation. I have a layout.blade.php which most of my pages use. Within this file, I have some partial pieces that I include, like #include('partials.header'). I am trying to use a controller to send data to my header.blade.php file, but I'm confused as to exactly how this will work since it is included in every view that extends layout.blade.php.
What I am trying to do is retrieve a record in my database of any Game that has a date of today's date, if it exists, and display the details using blade within the header.
How can I make this work?
I think to define those Game as globally shared is way to go.
In your AppServiceProvider boot method
public function boot()
{
view()->composer('partials.header', function ($view) {
view()->share('todayGames', \App\Game::whereDay('created_at', date('d')->get());
});
// or event view()->composer('*', Closure) to share $todayGames accross whole blade
}
Render your blade as usual, partial.header blade
#foreach ($todayGames as $game)
// dostuffs
#endforeach
In Laravel you can create a service class method that acts like a controller and use #inject directive to access this in your partial view. This means you do not need to create global variables in boot(), or pass variables into every controller, or pass through the base view layout.blade.php.
resources/views/header.blade.php:
#inject('gamesToday', 'App\Services\GamesTodayService')
#foreach ($gamesToday->getTodayGames() as $game)
// display game details
#endforeach
While it's different value you retrieved belong of the game chosen, you can do something like that:
Controller
$data = Game::select('id', 'name', 'published_date')->first();
return view('game')->with(compact('data'));
layout.blade.php
<html><head></head><body>
{{ $date }}
</body></html>
game.blade.php
#extend('layout')
#section('date', $data->date)
#section('content')
#endsection
The better solution would be this
Under your app folder make a class named yourClassNameFacade. Your class would look like this.
class yourClassNameFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'keyNameYouDecide';
}
}
Then go to the file app/Providers/AppServiceProvider.php and add to the register function
public function register()
{
$this->app->bind('keyNameYouDecide', function (){
//below your logic, in my case a call to the eloquent database model to retrieve all items.
//but you can return whatever you want and its available in your whole application.
return \App\MyEloquentClassName::all();
});
}
Then in your view or any other place you want it in your application you do this to reference it.
view is the following code:
{{ resolve('keyNameYouDecide') }}
if you want to check what is in it do this:
{{ ddd(resolve('keyNameYouDecide')) }}
anywhere else in your code you can just do:
resolve('keyNameYouDecide'))
I'm working with laravel pagination, however I wish to display the pagination links regardless of if there is only a single page, or multiple pages.
Currently, it is only displayed if there are multiple pages of results.
Eloquent Call
$products = Product::where('username', Sentry::getUser()->username)->paginate(25);
and then displayed in the view using
{!! $products->links() !!}
How can I force Laravel to display it when there is only a single page?
Publish pagination views:
php artisan vendor:publish --tag=laravel-pagination
This command will place the views in the resources/views/vendor/pagination directory.
Default view is bootstrap-4.blade.php and just delete the #if ($paginator->hasPages()) in this file.
Following Alexey Mezenin's answer, I extended the BootstrapThreePresenter class:
<?php namespace App\Extend;
use Illuminate\Pagination\BootstrapThreePresenter;
class CustomPaginationLinks extends BootstrapThreePresenter {
public function hasPages()
{
return true;
}
}
And was then able to render in the view like so:
{!! with(new App\Extend\CustomPaginationLinks($products))->render() !!}
There is no easy way, because it's hardcoded. However you could extend SimpleBootstrapThreePresenter and override hasPages() method:
public function hasPages()
{
return true;
}
Instead of:
public function hasPages()
{
return $this->paginator->hasPages() && count($this->paginator->items()) > 0;
}
In the past I've used a proprietary framework that kinda followed an Objective-C like View Controller scheme.
Basically I was able to in one controller instantiate another and pass it some values like an array of products and then inject the reference to the controller to my view and render it whenever I wanted by issuing: $controllerReference->render();
This could be useful in many cases, eg. if I had a controller responsible for rendering a catalog, I would just pass it an array with all the items I would like to see and it would take take of pagination and displaying the items by itself...
Example:
At \UI\Homepage\Controller.php (the controller responsible for the homepage):
// Instantiate a ProductDisplay Controller
$controllRef = new \UI\ProductDisplay\Controller();
$controllRef->setProducts( ... ); // Inject the product array
// Load the current view for this controller and pass it a reference for the ProductDisplay controller
$this->loadSelfView(["controllRef" => $controllRef]);
At \UI\Homepage\View.php (the view loaded before):
// some html of the view
$controllRef->render(); // Render the ProductDisplay view here!
// some other html
How should this functionality be accomplished in Laravel? From what I've been reading Laravel tries to avoid this kind of actions, why? What are the workarounds?
Thank you.
Here is how I will do this, it only work if the called controller method return a View object like return view('home');):
// Get the controller class from the IOC container
$myController= \App::make(MyController::class);
// Execute the controller method (which return a View object)
$view = $myController->myControllerMethod($someParams);
// Return the View html content
$html = $view->render();
you can use the Controller.php class which is extended by all other controller to make a generic method in it to:
Get a controller instance
Call the right method with x parameters
Return the rendered content if it's a view class OR throw an exception (for exemple)
In recent versions of Laravel, it's possible to use Blade's #inject directive. It seems its main purpose is to inject services but I successfully injected controller actions.
Here is a snippet on what you have to do:
#inject('productController', 'App\Http\Controllers\ProductController')
{!! $productController->index() !!}
Just remember: since you're calling the controller method directly, and not through the router, you'll have to pass all required params. If that action requires a request instance, you may call it this way:
{!! $productController->index(request()) !!}
Probably the view returned by the called action contains HTML code. It's important to wrap the method call within {!! and !!}. Using regular {{ }} tags will cause the HTML code be escaped by the template engine.