I'm writing a website using Slim Framework and Twig.
The sidebar on the website will have dynamically created links and i want to get the links from the database/cache every time a page is rendered, i can do this in each controller action but i would like to do this in my base template so i don't have to get and render the data manually in every controller action.
I have looked through the twig documentation and I haven't seen anything that could be of use besides the include function/tag but i don't see how i could get the data easily.
Is my only option to write an twig extension to do this or is there an easier way?
First of all: templates usually shouldn't contain any type of bussines logic but only render the data you provide it.
However you could write a custom twig function and use that to aquire the menu data from the DB in order to render it in your base template.
Alternativeley you could write some Slim middleware that aquires the data which might be able to inject the data into the template.
Hope that helps.
After reading Anticoms answer i was able to do it by writing a Twig extension.
public function getFunctions()
{
return array(
new \Twig_SimpleFunction('render', array($this, 'render'))
);
}
public function render($template, $controller, $action) {
$app = Slim::getInstance();
return $app->$controller->$action($template);
}
Now i can simply write
{{ render('Shared/sidebar.twig', 'Controller', 'Index') }}
Into my twig template to render the template with the data i want.
Note that my render() function uses slim dependency injection to instanciate the controller at runtime.
Related
I'm trying to build a page in Slim that will bring up a subscribers details. I've worked out how to create the route and the relevant method in the controller which all works correctly. I'm using Twig for the views and can't work out how I would access the subscriber from the view.
Route
$app->get('/subscriber/{id}', 'SubscriberController:getSubscriber');
Subscriber controller
public function getSubscriber($request, $response, $args)
{
$subscriber = Subscriber::where('id', $args['id'])->first();
}
I've been using the below in my controller to render my Twig templates
return $this->container->view->render($response, 'subscriber.twig');
How would I pass in or access my subscriber variable in the Twig template? I can't work out how to pass it through?
On the render method the 3. parameter is data where you can give the twig template variables.
$data = ['subscriber' => $subscriber];
return $this->container->view->render($response, 'subscriber.twig', $data);
now you can access this variable inside twig.
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.
i want to use custom code in blade template engine such as custom function for use into that
my function:
public function viewCurrentDate( $arg=0 ){
return 'date is'.date('y');
}
in Blade template use like with this code
#< viewCurrentDate >#
how to develop blade for custom actions?
Add in the filters.php file
Blade::extend(function ($view) {
return str_replace("#dateY", 'date is'.date('y'), $view);
});
in template :
<h1>#dateY</h1>
Full tutorial about blade extension here : http://blog.zerilliworks.net/blog/2013/04/03/blade-extensions-in-laravel/
This is possible (see markcial's answer) but I think there is a much better way to do it.
Why not just set up a HTML helper class.
class HTMLHelper {
public static function viewCurrentDate($arg = 0){
return 'date is'.date('y');
}
}
You can then add this to echo the date in your blade file:
{{ HTMLHelper::viewCurrentDate() }}
It is slightly more characters (compared to what you wanted), but will be so much more flexible for you as you can add as many helper methods to your class as you like and use them anywhere, not just in blade.
Edit: Whilst markcial's answer is what you are after (tells you how to create a new template string in blade) I'd don't think that is the simplest way to do things. The helper file is much more flexible and reusable. For example, you can use this helper file ANYWHERE in your app. With markcial's answer, you are only allowing blade to use what you have written. To me, it doesn't seem worth it when a more flexible, easier solutions is available.
I have created my own view helper according to this example. The view helper calls my model to create a form. The view Helper returns a form object.
My question is wether it is possible to assign a custom view script to the View Helper for the form. Or should i just use a partial for the script?
Thanks very much
View helpers should be used to help construct HTML that requires anything more that the normal control logic, the <?php if ($foo) : and <? foreach($foo....
You will want to avoid cases where you view logic becomes too complex or repetitive, as this results in hard to maintain code.
The example you posted, a <span> tag is returned based on the the number of days ($numberOfDays) arguments passed to it. This is something that is most likely repetitive to check every time you wish to output the 'new' item, hence the need for a view helper.
In your case, what would be ideal, would be to fetch the form via the FormElementManager from within the controller.
class FooController {
function someAction() {
$serviceManager = $this-getServiceLocator();
$formElementManager = $serviceManager->get('FormElementManager');
$myForm = $formElementManager->get('My\Form\Class\Name\Or\Alias');
return new \Zend\View\Model\Model(array(
'form' => $myForm
);
}
}
Calling the form from the FormElementManager will ensure its dependencies are correctly injected and init() called.
In the view you would then render the form using Zend's built in ViewHelpers (Like FormRow taking our complex form object and return all the required HTML)
With the above in place the need for you to 'assign view scripts to the form' disappears as the form can be injected, via the controller, into any view script.
i am using laravel's blade template and i have a master template for all my pages. In the master template i have a top bar and a sidebar. I want to load something in the sidebar. But i don't know how do it in a simpler way. Now i am calling that method (which i want in to display in my sidebar) in every controller i have like this:
View::make()->with('data_to_load_in_sidebar',$data_to_load_in_sidebar)
How can i load this only once, not every time i generate a view?
This is what view composers are for, any view that is loaded will automatically have it's composer run alongside providing the view with any extra data it may require.
View::composer(array('partials.sidebar'), function($view)
{
$news = News::all();
$view->with('news', $news);
});
I typically put this in my routes.php file in both L3 and L4.
In the view views\partials\sidebar.blade.php you now always have access to the variable $news that will contain all models from the News collection.
I would share top bar & sidebar data in constructor (prefferably in some BaseController's contructor, that other controllers extends).
public function __construct()
{
// if needed, call parent's contructor method as well
parent::__construct()
$data_to_load_in_sidebar = loadDataForSidebar();
View::share('data_to_load_in_sidebar',$data_to_load_in_sidebar)
}