I'm trying to load a template in PhalconPHP (v 2.0.13), but even the simplest example doesn't seem to work. I'm trying to access http://www.mysite.dev.fb/forms/ in this example. Here is my router:
$router->add(
'/forms/',
[
"namespace" => "Render\\Controller",
"controller" => "index",
"action" => "forms",
],
['GET']
);
The routing works, or at least the code in the action is reached (vardumps, etc).
Here's my Controller action variants.
Variant 1
public function formsAction()
{
}
In this case, the template located at app/views/index/forms.volt (I have a copy of the file with an .phtml extension, for debugging purposes) should be loaded, right? Wrong, an empty screen is displayed, no errors in errorlog.
Variant 2
Then, I tried picking the view, like that:
$this->view->setViewsDir(__DIR__ . '/../views/');
$this->view->pick('forms/contact');
The file, app/views/forms/contact.volt, also exists, with full permissions. Vardumping $this->view->getContent() returns null and the result is again an empty white screen without any errors.
Variant 3
Desperately, I tried directly rendering the template (for this example I'm using the default Phalcon index/index template) like this:
$this->view->start();
$this->view->render('index', 'index'); //Pass a controller/action as parameters if required
$this->view->finish();
The only difference is that now vardumping $this->view->getContent() returns an empty string, instead of null.
It's like automatic rendering is disabled, but the following line returns false (as it should):
var_dump($this->view->isDisabled());
I'm out of ideas, can anyone help? If I forgot to include something, respond and I'll include it.
You should definitely check your PHP logs for PHP errors. Also I suspect that your volt declaration might be wrong. Here is a working example of declaring a dependency injectable view component in services that I use:
$di->setShared('view', function () use ($di,$config) {
$view = new View();
$view->setViewsDir($config->application->viewsDir); // path to directory with views, loaded from config in this case
$view->registerEngines(array(
'.volt' => function ($view, $di) use ($di, $config) {
$volt = new VoltEngine($view, $di);
$volt->setOptions(array(
'compiledPath' => $config->application->cacheDir, // path to cache dir, loaded from config in this case
'compiledSeparator' => '_'
));
return $volt;
},
'.phtml' => 'Phalcon\Mvc\View\Engine\Php'
));
return $view;
});
Ensure that your webserver has rights to read views and R/W rights for cache directory. Hope it will help you
Related
I'm trying to send a variable to a twig file which is not in the typical location, Usually I'm loading views by specifying their path through the Bundle but the file I want to send a variable to is not, hierarchically, on the same level as the other twig templates.
I've a controller which looks like the following:
public function fooAction(Request $request)
{
*//Query*
return $this->render('Bundle:file.html.twig', array('varToSend' => $queryResult));
}
I'm pretty sure the Bundle:file.html.twig is wrong but I don't know how else to specify the relevant path in twig.
Twig you would get from container would not work with arbitrary paths, but you can initialize your own twig:
$twig = new \Twig_Environment(new \Twig_Loader_String());
$rendered = $twig->render(
file_get_contents('/path/to/your/file.html.twig'),
array('varToSend' => $queryResult)
);
If you need this in more than one place, consider making it a Symfony service in order to not initialize Twig Environment every time.
Note that renderer in this case won't have any of Symfony's Twig Extensions, you'll have to add them manually.
If possible, try to avoid this, and put templates into app/Resources/views or src/AppBundle/Resources/views directories.
You have to use a path like that :
return $this->render('Bundle:Something:file.html.twig', array(
'varToSend' => $queryResult
));
And put your file in this folder :
src/Bundle/Resources/views/Something/file.html.twig
With any regular page I set up a Zend\Cache\Pattern\CaptureCache, catch the onFinish event, and send the rendered version to a message queue for later processing. So far, so good...
Problem: sometimes I need to render two versions of the same action in the same request; one for mobile and one for desktop and I'm not sure how to do that.
If it helps, the actions that I need to "double render" actually create two discrete ViewModel objects so that I can have full control over that.
Ended up creating a service that given these two view models would figure out which one is mobile and which one is desktop. Then it would grab the layout and render each view model separately. Finally it would bypass any caching and generate both files manually.
With the setTemplate method :)
First you create your phtml view file (already done I suppose).
then you declare it in your view manager config / template_map :
In the Module.config.php file (you create the alias to call it later in your controller) :
return array(
//[...],
'view_manager' => array(
'template_map' => array(
// [...],
'index/test' => __DIR__ . '/../view/mymodule/index/test.phtml',
),
//here your template_path_stack as usual
),
// [...],
);
(of course, put your own path ;) )
Then in your controller :
public function indexAction(){
$view = new ViewModel();
if (/*here your tests*/) {
$view->setTemplate('index/test'); //here the name declared in the template_map
}
return $view;
}
you can learn a lot here about views (and layouts): http://framework.zend.com/manual/2.2/en/modules/zend.view.quick-start.html
The default zend framework 2 configuration relies on phtml files for view rendering. However, for security reasons I want to change that to php.
From this link I understand that I need to create a custom view helper in order to do that or is there a setting I can change to change the suffix from phtml to php and how is this done exactly?
Update: I got it working, but not the way I want. If possible I would like to get the answer from guessimtoolate working. So I prefer something like this in my module.config.php:
'view_manager' => array(
'default_suffix' => 'php',
//etc...
)
If my memory serves my well, you can define that in default_suffix key in your module's configuration file under view_manager, e.g.:
return array(
// ...
'view_manager' => array(
'default_template_suffix' => 'php',
// ...
),
// ...
);
This should make template file resolvers to look for .php files instead of .phtml.
Not entirely sure how's that an improvement, but it can be done.
UPDATE:
Sorry, I've wrote the wrong configuration key name -- it should be default_template_suffix and not default_suffix. It is used, e.g.: in Zend\Mvc\Service\ViewTemplatePathStackFactory where path stack resolvers are born :).
Try this in your module.php:
//module.php
public function onBootstrap(MvcEvent $e)
{
$application = $e->getApplication();
$sm = $application->getServiceManager();
$sm->get('ViewTemplatePathStack')->setDefaultSuffix('php');
}
Then change all .phtml files to .php in your project.
In your Application module, the Module.php file:
public function onBootstrap($e)
{
$app = $e->getApplication();
$sl = $app->getServiceManager();
$resolver = $sl->get('ViewTemplatePathStack');
$resolver->setDefaultSuffix('php');
}
What happens here, is during bootstrap you grab the path stack and sets the suffix on the resolver.
If placed in protected/views/layouts/main.php ,
Yii::app()->language = $_SESSION['lang'];
will not affect modules (because most of the contents is generated earlier).
For instance: Yii-user module.
What is the best file to place the Yii::app()->language = $lang; in the Yii flow of includes, to affect all the modules and their language settings ?
You can set up a "base" controller to extend your controllers (if you don't already have such a set-up) and put your language settings there as described here: http://www.yiiframework.com/wiki/26/setting-and-maintaining-the-language-in-application-i18n/
However, if you do have the value in a regular PHP session and want to set a global default, you should also be able to set it in your main config file with something like:
return array(
'language' => $_SESSION['lang'],
'name' => 'My Web Application',
... rest of your config settings...
I've modified protected/components/Controller.php, adding
function init()
{
parent::init();
Yii::app()->language = $_SESSION['lang']; //or some more code;
}
It works very well.
I've also tried making MyController.php in the same directory and extending the Controller.php, and it also works, but it slows down the whole application (most probably the loader tries hard until it loads the class, or because the operation was performed every single time the class was called ;) ).
When reading $_SESSION in the config/main.php we have to remember, that if Yii handles sessions, the second session_start() will result in a PHP E_Notice.
Yii can handle sessions :
link,
and it's supposed to have them turned on by default, but when adding $_SESSION code to the config.php I needed to add a 'manual' session_start() myself.
i am new to zend and i could not find a way to implement Ajax in zend.
In general php, its pretty easy to make an ajax request and show the response in the desired part of our page. But coming to zend, i have no clue how to do it.
Suppose in my index controller's index.phtml file, i have a button, and when i click on it, i have to make an ajax request to a particular controller and action, and load the related controller action's view in my page.
But what i could not understand is how to specify the urls for the ajax request and how the routing works.
Currently, i made ajax request to load the view statically like this:
xmlhttp.open("GET","../application/views/scripts/register/register.phtml",true);
FYI, i am using regex routing in my application, so would it be better to use curl to route the requests?
First things first, you don't request the view directly. You need to request the specific controller action, eg
/register/register
Zend comes with a great action helper called AjaxContext. This helper lets you respond with a different view based on the type of request (XmlHttpRequest) and a format parameter, disabling any layouts normally present.
To set it up, place something like this in your controller's init() method
public function init()
{
$this->_helper->ajaxContext->addActionContext('register', 'html')
->initContext();
}
Then, add a view script with the ajax suffix, eg register/register.ajax.phtml.
Construct your AJAX GET request to include the format=html parameter, eg
xmlhttp.open('GET', '/register/register/format/html', true);
or
xmlhttp.open('GET', '/register/register?format=html', true);
What will be returned is the rendered contents of register.ajax.phtml, without any layouts.
Apart from what the other answers stated, there's also a URL view helper function that can be useful to call a specific action on a controller. So you could just use $this->url(array('controller' => 'your_controller', 'action' => 'your_action'), 'default', true); to get the link to "your_action" action on the "your_controller" controller (using the default route). You could also specify a specific route instead of 'default' if you have one defined.
So for your example you would use something like the following in your view phtml file (if you're using the default routing) :
xmlhttp.open("GET","<?php echo $this->url(array('controller' => 'register', 'action' => 'register'), 'default', true);?>");
For more information refer to Zend Framework - View Helpers.
You should never be requesting the view directly. That's just wrong. Request URI like this:
xmlhttp.open("GET","/register/register");
Which means "I am looking for default module, register controller and register action", or in other words RegisterController::registerAction().
It's the same as:
xmlhttp.open("GET","/default/register/register");
Which is the same, the default module can be omitted.
Zend Framework knows where to look for the view script (unless you are using some unusual directory structure).
You can just create a blank layout and use it for your ajax controller actions (or what Phil suggested, AjaxContent is probably better for this).
I'll write here an almost complete "how to" guide to implement AJAX calls in Zendframework 3.
We need:
A route declaration
A controller
Some javaScript (is out of skope, perhaps I'll show it in other place)
The route declaration:
<?php
// editing a module.config.php in your project
// typical lines:
namespace Ajax2l; // my ajax module name
use Zend\Router\Http\Segment;
// ...
'router' => [
// ... other routes
'ajax2lsajaxcall' => [
'type' => Segment::class,
'options' => [
'route' => '/ajax2l/ajaxrequest[/:action][/:garbage]',
// the :action wildcard is a place to have extra parameters
// the :garbage wildcard is a place to send random strings
// to ensure you break cache to get real process for
// all your calls, since every call will be different
'defaults' => [
'controller' => Controller\AjaxController::class,
'action' => 'ajaxrequest'
]
],
'may_terminate' => true,
'child_routes' => [
// other ajax routes if needed
]
],
// I only use one ajax route and one controller for all my sites' ajax
// calls because they fire small db actions and reflect them on small
// parts of my pages. So I think I do not need a route and a controller
// for each ajax call. Instead, I use a Library and some services to get
// sets of elementary components and to perform tasks.
The Controller
My Ajax2l module is located under "myzend_project/module" directory.
<?php
// Filename: /module/Ajax2l/src/Controller/AjaxController.php
namespace Ajax2l\Controller
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
// No more components are needed
class AjaxController extends AbstractActionController {
public function ajaxrequestAction(){
$request = $this->getRequest();
$content = $request->getContent();
$isHttpRequest = $this->ifIsValidHttpRequest();
// if you have a real ajax call you must disable the normal output
$viewmodel = new ViewModel();
$viewmodel->setTerminal($is_xmlhttprequest);
// If not an Ajax call (perhaps from untrusted eyes) serve a forgiven
// page message
if(!$isHttpRequest){
return $this->forgivenPage();
}
// Now prepare a response and responds
$requestParams = $this->preProcessRequest($content);
// call the logics to process your params
$output = $this->processRequestParams($requestParams);
// and send a response
$response = $this->getResponse();
$response->setContent($output);
return $response;
}
private function ifIsValidHttpRequest($content){
// I use a small token string to verify if posted data matches
// perhaps not the proper way but is fast and works
$token = 'my_secure_visitor_session_token_identifier';
return (strpos($content, $token) > 2) ? 1 : 0;
// the validation is simplified here it has some more
// complex logics. To ensure validation of requesting source
}
private function preProcessRequest($content){
// The logics to know what to do
// ...
// here you can identify and set properly the post params
}
function processRequestParams($requestParams){
// some logics to process your data
// ...
// some logics to create a Json output
// ...
return $jsonObject;
}
protected function forgivenPage(){
$view = new ViewModel([]);
// set a forgiven message page as output
$view->setTemplate('ajax2l/messages/forgiven.phtml');
// note: the views directory uses lowercase for module names
return $view;
}
}
Hope it helps. I lost a lot of time reading on zend ajax without results. So I hope I was the last losing his time on this topic.
Luis