I would like display a link using a route name (home) into my template.
How can I do with Slim Framework
Thanks
My route
<?php
// index : home
$app->get('/home', function () use ($app){
$app->render('home.php');
})->name('home');
My template
<div>
my home link
</div>
or with urlFor()
<div>
my home link
</div>
I got this message
=> Call to undefined method Slim\View::urlFor()
The Slim instance is accessible through a Singleton and its getInstance method
my home link
You can also specify a name if you have multiple instances of Slim
my home link
If you want to access the urlFor method using $this
my home link
Then you should create a Custom View by adding a subclass of Slim\View containing a urlFor method and link it to Slim
Custom class :
<?php
class CustomView extends \Slim\View
{
public function urlFor($name, $params = array(), $appName = 'default')
{
return Slim::getInstance($appName)->urlFor($name, $params);
}
}
Linking :
<?php
require 'CustomView.php';
$app = new \Slim\Slim(array(
'view' => new CustomView()
));
I found the solution
just add this
$app->hook('slim.before.router', function () use ($app) {
// Pass in the App so we can use urlFor() to generate routes
$app->view()->setData('app', $app);
});
An then into your template you can use this (with app not this):
<div>
my home link
</div>
OR:
echo 'home';
Related
I want to write a plugin in ZF2,
An example of the plugin is a like button that shows in every post. It should for example print in PostsAction,
I know I can use:
$like = $this->forward()->dispatch('Application\Controller\Index', array(
'action' => 'like',
'postId' => $Id
));
$like variable returns a button that users can click on.
But I want to echo this in the view. In forward the view is not defined.
Also if I use
return $this->getView()->render('application/index/like', array('postId' => $Id));
I don't have access to postId in likeController, because it is set in the view. How I can implement these type of plugins that need a dynamic variables?
Looks like you only need partials. A partial in ZF2 is only a view which you print in another view and give some params to it.
So you could define a View:
// application/partials/button.phtml
<button data-postId="<?php echo $this->postId ?>">Like It!</button>
And use it in other View:
echo $this->partial('application/partials/button.phtml', array(
'postId' => $thePostId
));
Official Documentation
Nice Answer on SO to implement with template_map
Solution using view helper
I think what you are looking for is a custom view helper. You can read on this in the official ZF2 documentation.
You have to write your custom button view helper, register it and then you can use it in your view.
The helper class:
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
class LikeButtonHelper extends AbstractHelper
{
public function __invoke($post)
{
//return here your button logic, you will have access to $post
}
}
Register your helper within a configuration file:
'view_helpers' => array(
'invokables' => array(
'likeButtonHelper' => 'Application\View\Helper\LikeButtonHelper',
),
)
And finally in the view you can use it like this:
foreach($posts as $post){
echo( ... your code to show the post ...);
echo $this->likeButtonHelper($post);
}
UPDATE - Solution using forward plugin
I think I get what you mean now. I also think the example you are talking about is what in the ZF2 forward plugin documentation is referred to as “widgetized” content.
I think you are doing it correctly. You can attach the return value $like as a child to the view of the original controller (from where you forwarded in the first place).
So in your WidgetController:
use Zend\View\Model\ViewModel;
class WidgetController extends AbstractActionController
{
public function likeAction()
{
$post= $this->params()->fromRoute('post');
$viewModel = new ViewModel(array('post' => $post));
$viewModel->setTemplate('view/widgets/like');
return $viewModel;
}
}
So in your PostController:
use Zend\View\Model\ViewModel;
class PostController extends AbstractActionController
{
public function postsAction()
{
$likeWidget = $this->forward()->dispatch('Application\Controller\WidgetController', array(
'action' => 'like',
'post' => $post
));
$viewModel = new ViewModel();
$viewModel->setTemplate('view/posts/post');
$viewModel = new ViewModel(array(
//...add your other view variables...
));
// Add the result from the forward plugin as child to the view model
if ($likeWidget instanceof ViewModel)
{
$viewModel->addChild($likeWidget , 'likeWidget');
}
return $view;
}
}
And finally in your post view template add:
echo($this->likeWidget);
That is where the widget will eventually output.
The problem remains that you can not do this inside a foreach loop (a loop for printing your posts) in the view. That is why I suggested using a view helper and #copynpaste suggests using a partial, those are more suitable for adding additional logic inside a view.
Note:
Personally I don't like this forward solution for something so simple as a like button. There is hardly any logic in the controller and it seems overly complicated. This is more suitable for reusing a whole view/page that will be both rendered by itself as well as nested in another view.
The partials or view helpers seem much more suitable for what you want to do and those are very proper ZF2 solutions.
I found it ,developed by Mohammad Rostami,Special thanks to him :
Plugin In ZF2
I need to compose a web page of several view templates (the view template rendering page content and a view template rendering sidebar). In my layout.phtml, I have two variable placeholders: $content and $sidebar:
......
<?php echo $this->sidebar; ?>
......
<?php echo $this->content; ?>
......
In my controller's action, I pass the data to these view templates through the ViewModels chained in a tree:
public function indexAction() {
// Preparing my data
// $form = ...
// $menuItems =
// $activeItem =
// Create sidebar view model
$sidebarViewModel = new ViewModel(array('menuItems'=>$menuItems, 'activeItem'=>$activeItem));
// Add it as a child to layout view model
$this->layout()->addChild($sidebarViewModel, 'sidebar');
// Page content view model
$viewModel = new ViewModel(array('form'=>$form));
return $viewModel;
}
But, because I have the sidebar on every page, I will have to copy and paste this code for every action of every controller. Is there any recommended way of reusing the code that populates the ViewModel for sidebar?
One approach would be to achieve this with a controller plugin.
Assuming you have wired it up with appropriate config, and you're in the Application module.
In module/Application/src/Application/Controller/Plugin/AddSidebar.php:
namespace Application\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class addSidebar extends AbstractPlugin {
public function __invoke($menu, $active) {
// create new view model
$sidebarVM = new ViewModel(array(
'menuItems' => $menu,
'activeItem' => $active
));
// add it to the layout
$this->getController()->layout()->addChild($sidebarVM, 'sidebar');
}
}
Then in each of your controllers:
$this->addSidebar($menuItems, $activeItem);
Another (probably better) option would be to hook into the render MvcEvent and add the sidebar there. You'd have to work out how to generate $menuItems and $activeItem in that context however.
So I've been creating my first client website with cakePHP, and have run into a problem.
I'm trying to create a system similar to WordPress where you can create new pages (simply title, slug and content), and they are served up to their slug address (i.e. About will be available at mysite.com/about).
I've created my own controller & model for 'Pages' (overwriting the core pages controller), and have set up simple functions (view, admin_add, admin_delete). My model is simple, just the $name so it can connect to the db.
I'm pretty sure my problem lies in config/routes.php. Here is the code I'm currently using:
App::import('model', 'Page');
$Page = new Page();
$pages = $Page->find('list', array('fields' => array('id', 'slug')));
Router::connect('/:pages', array('controller' => 'pages'), array('Page' => implode($pages, '|')));
It just doesn't work though. When I visit an page I have (i.e. mysite.com/newpage), it tells me the newpage controller can't be found.
PLEASE HELP! I'm on a tight deadline :)
Thanks,
~harley
You need to extend the Class CakeRoute. Put your custom model code in there, and then pass that class name to your route definition in routes.php
routes.php would look something like this.
App::import('Lib', 'routes/MyCustomRoute');
Router::connect('/:page', array('controller'=>'pages', 'action'=>'display'), array('routeClass' => 'MyCustomRoute'));
Then over in libs/routes/my_custom_route.php
class MyCustomRoute extends CakeRoute {
function parse($url) {
$params = parent::parse($url);
//import your model
App::import('Model','Page');
//create model object
$Page = new Page();
//find using $params['page'];
if($Page->find('first', array('conditions'=>array('page.slug'=>$params['page'])))){
//return $params if successfull match
return $params
} else
return false;
//return false to fall through to next route.
}
I currently have a search form in the search controller, so the only way I can get to it is through /search/. I have to refactor my code so that this search form appears not only in the Search Controller but also globally throughout the site.
( The code isnt exact as I had to retype some of it )
My class that extends Zend_Form is located in application/forms/forms/SearchForm.php:
class Form_SearchForm extends Zend_Form {
public function init() {};
}
My search controller is something like..
class SearchController extends Zend_Controller_Action
{
public function search() {
$searchForm = new Form_SearchForm();
$this->view->form = $searchForm;
}
}
In my Bootstrap.php I have an autoloader for models:
protected function _initAutoload() {
$autoLoader = Zend_Loader_Autoloader::getInstance();
$resourceLoader = new Zend_Loader_Autoloader_Resource(
array(
'basePath' => APPLICATION_PATH,
'namespace' => '',
'resourceTypes' => array(
'form' => array(
'path' => 'forms',
'namespace' => 'Form_',
),
'model' => array(
'path' => 'models/',
'namespace' => 'Model_',
),
),
)
);
return $autoLoader;
}
I'm wondering where I can store my code so that globally the search form is generated in the view.
My global layout file is located in application/layouts/scripts/layout.phtml and currently spits out a dynamic content area:
<div id="main">
<?php echo $this->layout()->content;?>
</div>
Should I just add the form to this layout.phtml or is there some generic controller I should use?
Edit: Sorry for not specifying this too, but what if for example I wanted to not include it for 1-2 special pages ( maybe an admin section ).. if I hardcoded it into layout.phtml it would still appear.. or should I serve a different layout file to say, an admin area?
Creating a searchAction() is not good for performance because it requires a brand new dispatch cycle. If, and only if, you have very complex logic that justifies a separate action, you could create a Controller Plugin and add searchAction() to the ActionStack. If you are only instantiating/assigning the form or if you don't need the search form for every request, it's not an optimal solution.
Another possibility would be to instantiate and assign the form in the bootstrap. This kind-of breaks separation of concerns, but provides better performance.
protected function _initSearchForm()
{
$this->bootstrap('view');
$view = $this->getResource('view');
$searchForm = new Form_SearchForm();
$view->searchForm = $searchForm;
return $searchForm;
}
Finally, my preferred solution would be a custom view helper:
<?php
class My_View_Helper_SearchForm extends Zend_View_Helper_Abstract
{
public function searchForm()
{
$searchForm = new Form_SearchForm();
return $searchForm;
}
}
For either of these solutions, you'd ideally output the form in your layout file to minimise duplication.
layout.phtml:
<?php echo $this->searchForm() ?>
And create an alternate layout admin.phtml for admin area pages. This gives you the flexibility to change the admin pages significantly when new requirements pop up.
You can create your Form in a Controller Plugin and add it to view vars somehow (by Zend_Controller_Front?), which are accessible in layout, too. But it's too complicated in current ZF version (or I'm too dumb)
You can make Form_SearchForm a singleton
class Form_SearchForm ... {
static function getInstance() {
static $instance;
if (!$instance)
$instance = new Form_SearchForm();
return $instance;
}
}
Now instead of creating new Form_SearchForm() just get it as
$form = Form_SearchForm::getInstance();
You can put an instance of Form_SearchForm to the registry
I probably have missed a very cool a simple way :)
I would split it into a partial and a place holder.
in layout.phtml:
<?php if($searchForm = $this->placeHolder('searchForm'): ?>
<?php echo $searchForm; ?>
<?php endif; ?>
then in your views you can call:
<?php $this->placeHolder('searchForm')->set($this->partial('search-from.phtml', 'search')); ?>
IF you wanted you could even make a search view helper that basically does the place holder call.
The Controller plugin would be better if you have more pages that dont need it than d though. I would still probably use placeholder though to accomplish it. That way you can easily override or append to it later on a view-by-view basis without calling anything on the front controller.
How to build modular web site with Zend framework. I have pages in db, every page is represented as url. Every page has 1toN contents. Every content has controller, action and position (+other now not important columns). So, one request is one page and multiple contents (multiple actions). How can I build all actions before the output? I would like to have layout design like example bellow, where contents are put in there containers (actions are run before layout print-out).
<div id="left">
<?= $this->layout()->left_container ?>
</div>
<div id="center">
<?= $this->layout()->center_container ?>
</div>
<div id="right">
<?= $this->layout()->right_container ?>
</div>
Until now I called actions from layout view, but I do not like this approach:
foreach ($contents as $item) {
echo $this->action($item['action'], $item['controller'], null, array('content' => $item));
}
Thanks.
p.s.
adepretis's code is similar to my, views of my actions are run inside layout, which means that when error occurres it is printed in layout where the action is called. Is there no whey that actions are build before layout output? Another bad thing is that in every action I must run ...->setResponseSegment, I would like this to be automated.
p.s. #2
I have found answer, it is listed bellow as answer. If there is a whey I can do this easier please write it down.
You can use the ActionStack helper. For example:
class MyController_Action extends Zend_Controller_Action {
function init() {
/** you might not want to add to the stack if it's a XmlHttpRequest */
if(!$this->getRequest()->isXmlHttpRequest()) {
$this->_helper->actionStack('left', 'somecontroller', 'somemodule');
$this->_helper->actionStack('center', 'somecontroller', 'somemodule');
$this->_helper->actionStack('right', 'somecontroller', 'somemodule');
}
}
class MyController extends MyController_Action {
function indexAction() {
// do something
}
}
class SomecontrollerController extends MyController_Action {
function leftAction() {
// do something
$this->_helper->viewRenderer->setResponseSegment('left_container');
}
function centerAction() {
// do something
$this->_helper->viewRenderer->setResponseSegment('center_container');
}
function rightAction() {
// do something
$this->_helper->viewRenderer->setResponseSegment('right_container');
}
}
A request for /somemodule/my/index results in executing /somemodule/somecontroller/left. /somemodule/somecontroller/right, /somemodule/somecontroller/center which end up in the correspondig layout segments.
I found my answer on other forum. Here is the asnwer:
MyPlugin
class MyPlugin extends Zend_Controller_Plugin_Abstract
{
public function routeStartup(Zend_Controller_Request_Abstract $request)
{
$action_stack = new Zend_Controller_Action_Helper_ActionStack();
// here I will read actions from db and run it in loop, but for example few are staticly added bellow
$action_stack->actionToStack('index', 'content', 'default', array('position' => 'left'));
$action_stack->actionToStack('index', 'content', 'default', array('position' => 'center'));
$action_stack->actionToStack('index', 'edo', 'default', array('position' => 'center'));
$action_stack->actionToStack('left', 'edo', 'default', array('position' => 'left'));
$action_stack->actionToStack('right', 'edo', 'default', array('position' => 'right'));
}
}
BaseController, that every controller extends
class BaseController extends Zend_Controller_Action
{
public function preDispatch()
{
$position = $this->_request->getParam('position', false);
if ($position) {
$this->_helper->viewRenderer->setResponseSegment($position);
}
}
}
Layout.phtml
<div>
<h2><u>LEFT:</u></h2>
<?=$this->layout()->left?>
</div>
<div>
<h2><u>CENTER:</u></h2>
<?=$this->layout()->center?>
</div>
<div>
<h2><u>RIGHT:</u></h2>
<?=$this->layout()->right?>
</div>
This is what I wanted, if anyone has a better solution please answer the question and I will accept his answer.
hi i also encounter the same problem. The solution you suggest work fine. But my baseController is in module base .The code work smooth with baseController but when i extended with controllers in another module error occure as base Controller cannot identify in other controller
For eg:
modules/ base/Controller/baseController
modules/ user/Controller/userController
Any Solutions ?