Lithium: how to get layout/template path value from Helper - lithium

I have a helper class which extends \lithium\template\Helper. How can I know which layout file/path are used to render?
Thank you.
update:
The reason I need this is because I want the site support multiple template packs.
The template layout will support render by block modules (likes Joomla template), so in the layout file I can do this:
<?php if($this->Block->countModule('slider')){ ?>
<div id="slider">
<?php echo $this->Block->renderBlock('slider'); ?>
</div>
<?php } ?>
To add a module to a block I do this:
$this->Block->addModule('slider', array('element'=>'slider'));
........................
I have to overwrite the renderer object
in bootstrap/media.php
Media::type('html', 'text/html', array(
'view' => 'app\extensions\template\View'
));
I created new file /app/extensions/template/View.php
class View extends \lithium\template\View {
public function __construct(array $config = array()) {
$defaults = array(
'renderer' => 'app\extensions\template\view\adapter\File'
);
parent::__construct($config + $defaults);
}
}
And finally the /app/extensions/template/adapter/File.php
class File extends \lithium\template\view\adapter\File {
public function getTemplatePath(){
$path = $this->_paths['layout'][0];
$path = preg_replace('/\/\{:layout\}.*$/', '', $path);
return $path;
}
}
Now I can get the path.

Taking a step back and interpreting your question as "How do I replicate Joomla! template module positions in Lithium PHP?", I came up with this solution.
See https://gist.github.com/rmarscher/10020347
Create a view helper at app\extensions\helper\Module with the following content:
<?php
namespace app\extensions\helper;
use lithium\core\Libraries;
use lithium\template\view\TemplateException;
use lithium\template\View;
/**
* An implementation of Joomla! template module positions for Lithium.
*
* Here is how you can render to a module position from one of your inner templates:
* {{{
* $this->modules->bottom("element", 'bottomTest');
* $this->modules->top("simple", "<p>Maybe we can just put some html in there...</p>");
* }}}
*
* To do the same from inside another helper, use `$this->_context->modules()`.
*
* Then in your layout file, output the module in the desired location:
* {{{
* <body>
* <?php echo $this->modules->top(); ?>
* <?php echo $this->content(); ?>
* <?php echo $this->modules->bottom(); ?>
* </body>
* }}}
*
* #see http://docs.joomla.org/Creating_a_basic_Joomla!_template#Body_Section
*/
class Modules extends \lithium\template\Helper {
protected $_rendered = array();
protected $_simpleView = null;
public function __call($name, $params) {
return $this->position($name, $params);
}
public function position($name, $params) {
if (empty($this->_rendered[$name])) {
$this->_rendered[$name] = "";
}
switch (count($params)) {
case 0:
return $this->_rendered[$name];
case 1:
return $this->_rendered[$name] .= $this->render($params[0]);
case 2:
return $this->_rendered[$name] .= $this->render($params[0], $params[1]);
case 3:
return $this->_rendered[$name] .= $this->render($params[0], $params[1], $params[2]);
case 4:
return $this->_rendered[$name] .= $this->render($params[0], $params[1], $params[2], $params[3]);
case 5:
return $this->_rendered[$name] .= $this->render($params[0], $params[1], $params[2], $params[3], $params[4]);
default:
return $this->_rendered[$name] .= call_user_func_array(array(&$this, $method), $params);
}
}
/**
* Shortcut method used to render elements and other nested templates for named module blocks.
*
* #see lithium\template\View::render()
* #param string $type The type of template to render, usually either `'element'` or
* `'template'`. Indicates the process used to render the content. See
* `lithium\template\View::$_processes` for more info.
* There's an additional special option here for the Modules helper.
* Use `"simple"` to render a string template rather than from a file.
* #param string $template The template file name. For example, if `'header'` is passed, and
* `$type` is set to `'element'`, then the template rendered will be
* `views/elements/header.html.php` (assuming the default configuration).
* If `$type === 'simple'`, this should be the template content.
* #param array $data An array of any other local variables that should be injected into the
* template. By default, only the values used to render the current template will
* be sent. If `$data` is non-empty, both sets of variables will be merged.
* #param array $options Any options accepted by `template\View::render()`.
* #return string Returns a the rendered template content as a string.
*/
public function render($type, $template, array $data = array(), array $options = array()) {
$view = $this->_context->view();
if ($type !== "simple") {
return $view->render($type, $data, compact('template') + $options);
}
if (!$this->_simpleView) {
$this->_simpleView = new View(array('loader' => 'Simple', 'renderer' => 'Simple'));
}
$element = $template;
return $this->_simpleView->render('element', $data, compact('element') + $options);
}
}
?>
Then you can do this in your templates to render to a module position:
<?=$this->_render("element", "elementTest"); ?>
<?php $this->modules->top("element", 'topTest'); ?>
<?php $this->modules->bottom("element", 'bottomTest'); ?>
<h1>Hi there. I'm the main content.</h1>
<?php $this->modules->top("simple", "<p>Maybe we can just put some html in there...</p>");
And then do this in your layout template:
<!doctype html>
<html>
<head>
<?php echo $this->html->charset();?>
<title><?php echo $this->title(); ?></title>
</head>
<body>
<div class="content">
<?php echo $this->modules->top(); ?>
<?php echo $this->content(); ?>
<?php echo $this->modules->bottom(); ?>
</div>
</body>
</html>

You could obtain the template path by passing __FILE__ in an argument to your helper function.
There also seems to be an internal $template__ variable available in your templates.
See http://li3.me/docs/lithium/template/view/adapter/File::render().
The Renderer object is also available in your helper as $this->_context. I don't think it stores state about which file is being rendered.

Related

Exception: Service 'voltService' wasn't found in the dependency injection container

I am trying to replicate the examples in the Volt tutorial here, using the basic example of phalcon here, so nothing complicated.
So I created this app/controllers/PostsControllers like this:
<?php
use Phalcon\Mvc\Controller;
class PostsController extends Controller
{
public function indexAction()
{
/* $post = Post::findFirst();
$menu = Menu::findFirst();*/
$post = array("title"=>"The titre");
$menu = "menu1";
$this->view->show_navigation = true;
$this->view->menu = $menu;
$this->view->title = $post["title"];
$this->view->post = $post;
// Or...
$this->view->setVar('show_navigation', true);
$this->view->setVar('menu', $menu);
$this->view->setVar('title', $post["title"]);
$this->view->setVar('post', $post);
}
}
And its corresponding app/views/posts/index.phtml like this:
{# app/views/posts/show.phtml #}
<!DOCTYPE html>
<html>
<head>
<title>{{ title }} - An example blog</title>
</head>
<body>
{% if show_navigation %}
<ul id='navigation'>
{% for item in menu %}
<li>
<a href='{{ item.href }}'>
{{ item.caption }}
</a>
</li>
{% endfor %}
</ul>
{% endif %}
<h1>{{ post.title }}</h1>
<div class='content'>
{{ post.content }}
</div>
</body>
</html>
I also registered volt in my bootstrap file (/public/index.php) which looks like that:
<?php
use Phalcon\Loader;
use Phalcon\Mvc\View;
use Phalcon\Mvc\Application;
use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Url as UrlProvider;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
use Phalcon\Mvc\View\Engine\Volt;
// Register an autoloader
$loader = new Loader();
$loader->registerDirs(
[
"../app/controllers/",
"../app/models/",
]
);
$loader->register();
// Create a DI
$di = new FactoryDefault();
// Setup the view component
$di->set(
"view",
function () {
$view = new View();
$view->setViewsDir("../app/views/");
$view->registerEngines(
[
'.volt' => 'voltService',
]
);
return $view;
}
);
// Setup a base URI so that all generated URIs include the "tutorial" folder
$di->set(
"url",
function () {
$url = new UrlProvider();
$url->setBaseUri("/care/");
return $url;
}
);
$application = new Application($di);
try {
// Handle the request
$response = $application->handle();
$response->send();
} catch (\Exception $e) {
echo "Exception: ", $e->getMessage();
}
But when I try to access to /posts directory (localhost/care/posts) I get the following error:
Exception: Service 'voltService' wasn't found in the dependency injection container
I checked if Volt service was not already declared in Services.php as it is said in a similar post here but it is not.
Thank you
The issue is with this block of code. You are telling your view that it should use the volt extension and process it using a service called voltService.
// Setup the view component
$di->set(
"view",
function () {
$view = new View();
$view->setViewsDir("../app/views/");
$view->registerEngines(
[
'.volt' => 'voltService',
]
);
return $view;
}
);
If you look at your snippet, there is no service called voltService defined.
However if you add this to your services, it should work:
// Register Volt as a service
$di->set(
'voltService',
function ($view, $di) {
$volt = new Volt($view, $di);
$volt->setOptions(
[
'compiledPath' => '../app/compiled-templates/',
'compiledExtension' => '.compiled',
]
);
return $volt;
}
);
Reference: https://docs.phalconphp.com/en/3.2/volt#setup

Is it possible to assert text in a repeated div?

I am using behat/mink to create some BDD tests. I would like to know if it's possible to get a text inside a div that is repeated in the page. For example:
<div class="message">Text 1</div>
<div class="message">Text 2</div>
<div class="message">Text 3</div>
The class is repeated but the text is different. I would like to assert the text that is displayed in the second div.
You can clean/modify iReadContentOfDiv() method as you wish.
Gherkin
Scenario: Iterate classes
Given I am on "about"
Then I should see "Welcome to About page"
And The content of repeated ".message" div should be:
| content |
| Text 1 |
| Text 2 |
| Text 3 |
FeatureContext.php
namespace MyProject\ApiBundle\Features\Context;
use Behat\Gherkin\Node\TableNode;
use Behat\MinkExtension\Context\MinkContext;
class FeatureContext extends MinkContext
{
/**
* #When /^The content of repeated "([^"]*)" div should be:$/
*/
public function iReadContentOfDiv($class, TableNode $table)
{
$session = $this->getSession();
$page = $session->getPage();
$element = $page->findAll('css', $class);
if (null === $element) {
throw new \InvalidArgumentException(sprintf('Could not evaluate CSS: "%s"', $class));
}
$found = [];
foreach ($element as $e) {
$found[] = $e->getText();
}
foreach ($table->getHash() as $element) {
if (!in_array($element['content'], $found)) {
throw new Exception(sprintf('Data "%s" not found in DOM element "%s".', $element['content'], $class));
}
}
}
}
ABOUT page content:
<div class="message">Text 1</div>
<div class="message">Text 2</div>
<div class="message">Text 3</div>
Based on #BentCoder answer, I did a small changes to solve the problem:
/**
* #Then /^The content of repeated "([^"]*)" div should contain "([^"]*)"$/
*/
public function iReadContentOfDiv($class, $text)
{
$session = $this->getSession();
$page = $session->getPage();
$element = $page->findAll('css', $class);
if (null === $element) {
throw new \InvalidArgumentException(sprintf('Could not evaluate CSS: "%s"', $class));
}
foreach ($element as $e) {
if (strpos($e->getText(), $text)){
print 'opa';
return;
}
}
throw new Exception(sprintf('Data "%s" not found in DOM element "%s".', $text, $class));
}
http://casperjs.readthedocs.org/en/latest/modules/tester.html
This is a javascript testing API that allows you to assert anything in the dom

How to Redirects with a Drop Down?

I have parent page and there are two child view _sectionhead.php and _classteacher.php i need to renderPartial to those child view when user select from dropdwon how can do this
this is my create from
IF there is any other way i like to know it.i need quick help
In view:
<?php Yii::app()->clientScript->registerScript('some-name', "
$('select').on('change', function (event) {
var url = $(event.currentTarget).val();
if (url != 0)
$.get(url, function (data) {
$('#result').html(data);
});
});", CClientScript::POS_READY) ?>
<?php echo
CHtml::dropDownList("param", "select here", [
'Select here',
$this->createUrl('/testing/action1') => "Add class teacher",
$this->createUrl('/testing/action2') => "Add class techer"
]) ?>
<div id="result"></div>
Assuming you are doing in HTML ,Add below in HTML code
<option onClick="fnCallPage('classteacher')">class teacher</option>
<option onClick="fnCallPage('Section')">Section</option>
Add below in Javascript tag :
function fnCallPage(param){
//Javascript code for sending
}
Based on #Fraz solution:
HTML:
<option onClick="fnCallPage('_classteacher')">class teacher</option>
<option onClick="fnCallPage('_sectionhead')">Section</option>
<div id="divContainerPartial"></div> <!-- View rendered container -->
Javascript:
function fnCallPage(param){
$.ajax({
url: '<?php echo Yii::app()->createUrl('yourModel/renderPageByAjax');?>/' + param,
type: 'GET',
success: function(html){
$('#divContainerPartial').html(html);
},
error: function(data){
alert('Error loading a '+param+' view.');
}
});
}
Controller:
/**
* #param $view String : View name to render.
*/
public function actionRenderPageByAjax($view)
{
$params = array(); // Variables to view.
$this->renderPartial('//myFolderView/'.$view, array(
'params' => $params,
), false, true);
}

Layout redirect in zend Framework 2

Is it possible to redirect to a route in Layout.phtml in ZF2. I want to redirect to login page if the user is not logged in from layout.phtml
So far i have tried:
<?php $auth = new AuthenticationService();
if ($auth->hasIdentity()) {?>
<li class="active"><a href="<?php echo $this->url('home') ?>">
<?php echo $this->translate('Home') ?></a></li>
<li class="active"><?php echo $this->translate('Logout') ?></li>
<?php
}
else
{
$this->_forward('login/process');
} ?>
its giving me error "get was unable to fetch or create an instance for _forward"
BOOTSTRAP CODE:
public function onBootstrap(MvcEvent $e)
{
$e->getApplication()->getServiceManager()->get('translator');
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
$eventManager = $e->getApplication()->getEventManager();
//nothing's available for non logged user, so redirect him to login page
$eventManager->attach("dispatch", function($e) {
$match = $e->getRouteMatch();
$list = $this->whitelist;
// Route is whitelisted
$name = $match->getMatchedRouteName();
if (in_array($name, $list)) {
return;
}
$sm = $e->getApplication()->getServiceManager();
$controller = $e->getTarget();
$auth = $sm->get('AuthService');
if (!$auth->hasIdentity() && $e->getRouteMatch()->getMatchedRouteName() !== 'login/process') {
$application = $e->getTarget();
$e->stopPropagation();
$response = $e->getResponse();
$response->setStatusCode(302);
$response->getHeaders()->addHeaderLine('Location', $e->getRouter()->assemble(array(), array('name' => 'login/process')));
//returning response will cause zf2 to stop further dispatch loop
return $response;
}
}, 100);
}
This is not something that you wanna be doing inside your layout.phtml. Typically you want to hook in to an event that happens before the rendering. In ZF2, the earliest event to hook into that kind of stuff, where it makes sense to hook into, would be the route event. A good diagram of the process that's used in the Authorization-Module BjyAuthorize explains it quite well:
If you don't want to use the Module, you can minify what's happening there, too, like this:
//class Module
public function onBootstrap(MvcEvent $mvcEvent)
{
$eventManager = $mvcEvent->getApplication()->getEventManager();
$eventManager->attach(MvcEvent::EVENT_ROUTE, array($this, 'onRoute'), -1000);
}
public function onRoute(MvcEvent $event)
{
$serviceLocator = $mvcEvent->getApplication()->getServiceLocator();
// From this point onwards you have access to the ServiceLocator and can check
// for an authenticated user and if the user is not logged in, you return a
// Response object with the appropriate ResponseCode redirected and that's it :)
}

How to add a new ZF2' Zend\Form\Element within jQuery ajax

I want to add a new ZF2' Zend\Form\Element within jQuery ajax. But while I use the Zend Form , I don't know how to make it. This is the add.phtml file.
<script type="text/javascript">
$(document).ready(function(){
$(".pid").change(function(){
var id = $('.pid').val();
var $_this = $(this);
$.ajax({
type:"POST",
url:"<?php echo $this->url('Element/default',array('action'=>'change'));?>",
data:"pid="+id,
dataType:'json',
async:false,
success:function(data){
if(data.response){
//here I want to add a new select component after select conponent "pid" using like "$this->formRow($form->get('mid'))" or else .
}
}
});
});
});
</script>
the following is the remaining part of the html.
<?php
$title = 'add';
$this->headTitle($title);
?>
<h1><?php echo $this->escapeHtml($title); ?></h1>
<?php
$form = $this->form;
$form->setAttribute('action', $this->url(
'Element/default',
array(
'action' => 'add'
)
));
$form->prepare();
echo $this->form()->openTag($form);
echo $this->formRow($form->get('pid'));
echo $this->formRow($form->get('name'));
echo $this->formRow($form->get('desc'));
echo $this->formSubmit($form->get('submit'));
echo $this->form()->closeTag();
How do I add a new zend form element within jquery ajax ? Thanks.
You have script to receive data using ajax and view/html should be received by this script. You need controller/action to rendering data and return as response.
use Zend\View\Model\JsonModel;
//some controller
public function changeAction(){ // your requested action
//1. get partial helper to rendering html;
$partial = $this->getServiceLocator()->get('ViewHelperManager')->get('partial');
$form = new Form();// your form
//2. render html
$html = $partial('path/to/your/file/phtml',['form'=>$form]);
//3. return data as JSON because in your ajax configuration dataType: 'json'
return new JsonModel([
'html' => $html,
]);
}
in your js success function should be:
success:function(data){
if(data.html){
$_this.find('blockToAppend').append(data.html);
}
}