How does one add a 'plain text node' to a zend form? - zend-form

I'm trying to add a plain text node in a zend form - the purpose is to only dispay some static text.
The problem is - im not aware of any such way to do it.
I have used 'description' but that HAS to be attached to a form element.
Is there any way to simply display some text as part of a form? Zend considers everything as a form element so I cannot just print it out.
Eg:
The following will test your ability on so and so.
.
.
.
etc...
Any thoughts?

Zend has a form note view helper (Zend_View_Helper_FormNote), which you can use to add text.
Just create a new form element (/application/forms/Element/Note.php):
class Application_Form_Element_Note extends Zend_Form_Element_Xhtml
{
public $helper = 'formNote';
}
In your form:
$note = new Application_Form_Element_Note(
'test',
array('value' => 'This is a <b>test</b>')
);
$this->addElement($note);

Adding a hidden element with non-escaped description does the thing.
$form->addElement('hidden', 'plaintext', array(
'description' => 'Hello world! Check it out',
'ignore' => true,
'decorators' => array(
array('Description', array('escape'=>false, 'tag'=>'')),
),
));
Works perfectly. It is still attached to an element, which is, however, not rendered this way.
Code taken from: http://paveldubinin.com/2011/04/7-quick-tips-on-zend-form/

There might be a better way, but I created a paragraph by using a custom form element and view helper. Seems like alot of code for something so simple. Please let me know if you've found a more simplistic way to do it.
//From your form, add the MyParagraph element
$this->addElement(new Zend_Form_Element_MyParagraph('myParagraph'));
class Zend_Form_Element_MyParagraph extends Zend_Form_Element
{
public $helper = 'myParagraph';
public function init()
{
$view = $this->getView();
}
}
class Zend_View_Helper_MyParagraph extends Zend_View_Helper_FormElement {
public function init() {
}
public function myParagraph() {
$html = '<p>hello world</p>';
return $html;
}
}

A little late but thought I'd throw it in anyway for the benefit of the community.
Aine has hit the nail on the head. FormNote is what you need if you want to use text in Zend_Form. However, you can use it without needing to extend Zend_Form_Element_Xhtml. See example below:
$text = new Zend_Form_Element_Text('myformnote');
$text->setValue("Text goes here")
->helper = 'formNote';
Note that you can use both text and html with the formNote helper.

This functionality is built into Zend via Zend_Form_Element_Note.
$note = new Zend_Form_Element_Note('forgot_password');
$note->setValue('Forgot Password?');

I faced the same problem and decided is better not to use Zend_Form at all, but to use directly view helpers (like Ruby on Rails does) and validate on the model.

This one-liner works for me:
$objectForm->addElement(new Zend_Form_Element_Note('note', array('value' => 'Hello World')));

Related

Phalcon\Mvc\View\Simple::render() in mailer causing WSOD

I have a simple controller action that creates a Guest record and renders a template.
// First bind the form to our Guest:
$form->bind( $_POST, $guest );
// Validate and save, or show error messages
if( $form->isValid($_POST, $guest) ) {
if( $guest->save($_POST) ) {
$this->view->setMainView( 'confirm' );
}
}
This works fine before I add any mailer stuff. However, when I add an event handler inside the Guest model which happens to render a template, the controller renders a WHITE SCREEN OF DEATH instead of my confirm template.
In Guest model:
public function afterCreate() {
return GuestMailer::sendEmailConfirmation( $this );
}
In GuestMailer class:
public static function sendEmailConfirmation( $guest ) {
// create/configure $email message
$view = $guest->getDI()->get('simpleView');
$view->render( // Works without this call...
'confirmation_email',
array( 'guest' => $guest )
);
$content = $view->getContent();
$email->content( $content );
return $email->send();
}
Note that when I remove the above call to render(), the confirm template is rendered successfully.
I thought components in Phalcon were supposed to be highly decoupled? Why is rendering a completely different template causing my controller's view to get messed up? How can I avoid this?
I think this problem is caused by a peculiar configuration of the templating service, in a normal workflow it doesn't causes issues, they appears when you need to render "manually" a template as in your case, you can refer to this PhalconPHP forum discussion linked, in particular the answer refered by the link anchor:
http://forum.phalconphp.com/discussion/109/manually-render-separate-file-template-#C12015

why using viewSimple renderer in Phalcon corrupts main renderer

First I declare simple view like this:
$di->set('viewSimple', function() {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir('../app/views/');
$view->registerEngines(array(
".volt" => 'volt'
));
return $view;
});
then to generate html email, I use it as following:
public function renderHTMLEmail($template_name, $template_params) {
$content = $this->viewSimple->render("emails/$template_name", $template_params);
return $this->viewSimple->render("emails/master", array( 'content' => $content) );
}
My emails are being generated just fine, but whenever I call my renderHTMLEmail function actual page rendering is somehow corrupted and page appears totally blank (I have to use redirect as workaround). This is a mystery to me as main view renderer is completely different object. Can I prevent this?
Or does anybody have recommended method of generating arbitrary pieces of html outside of main view rendering process which would not interfere with it? There is couple of similar questions on SO, but none of solutions work. They either don't generate my email or they corrupt main view.
Found a solution, when registering the "\Phalcon\Mvc\View\Simple" component into the DI container make sure to use a new volt instance otherwise it will join up with the application's \Phalcon\Mvc\View volt instance somehow. This is what lot (https://stackoverflow.com/users/1672165/lot) was suggesting in the comments.
Code sample:
public function getTemplate($name, $params)
{
$parameters = array_merge(array(
'publicUrl' => $this->getDI()->getApp()->url->host . $this->getDI()->getApp()->url->baseUri
), $params);
$app = $this->getDI()->getApp();
$this->getDI()->set('simpleView', function() use ($app) {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir(APP_DIR . $app->application->viewsDir);
$view->registerEngines(array(
".volt" => function ($view, $di) {
$volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
$volt->setOptions(array(
'compiledPath' => APP_DIR . '/cache/volt/',
'compiledSeparator' => '_',
'compiledExtension' => '.compiled'
));
$compiler = $volt->getCompiler();
$compiler->addFunction('is_a', 'is_a');
return $volt;
}
));
return $view;
});
/* #var $simpleView \Phalcon\Mvc\View\Simple */
$simpleView = $this->getDI()->get('simpleView');
foreach ($parameters as $key => $value) {
$simpleView->{$key} = $value;
}
$html = $simpleView->render('emails/' . $name, $parameters);
return $html;
}
Sample was pulled straight from our working app so may need some re-working but should help solve the original issue.
This works for me using \View as the application DI registered view component which renders controller action volt views and the above \View\Simple with fresh volt registration successfully emails and allows the original view with volt to carry on.
This was asked a while ago however i've not seen a working solution anywhere else.
For completeness I've registered a github issue with the findings: https://github.com/phalcon/cphalcon/issues/3096
I recently had to deal with a similar problem, I'm not certain where you're falling short, but one important thing was to use a separate view from the one used by the application – you're already doing this. See if the following works.
protected function renderView($view, $template, array $data = null)
{
return $view
->reset()
->pick('emails/' . $template)
->setVars($data)
->start()
->render(null, null)
->finish()
->getContent();
}
public function renderHTMLEmail($template_name, $template_params)
{
$content = $this->render($template_name, $template_params);
return $this->render('master', array('content' => $content));
}

I've to show menu bar with stats like count of messages and updates, also other counts like gifts and messages count

I want to show a menu bar with stats like count of messages and updates, also other counts like gifts, new friend request and messages count.
This menu will be displayed on the all the pages.
How can I write a single method to get all the stats and render partial into the layout and forget about it?
And in other action just concentrate on the main functionality of the page. Without bothering about the menu.
How can I achieve this in Yii?
You're probably looking for a widget. You could for example extend CMenu and do the queries in init() there:
<?php
Yii::import('zii.widgets.CMenu')
class MainMenu extends CMenu
{
public function init()
{
// Do some count queries here. This is just an example,
// your implementation will differ, of course:
$newMessages = Messages::model()->new()->count();
// Now add the menu items:
$this->items = array(
array(
'label' => "$newMessages New messages",
'url' => array('messages/list'),
),
// ...
);
parent::init();
}
}
You then can use this widget in your views/layouts/main.php:
<?php $this->widget('MainMenu'); ?>
You can use beforeAction to achieve this.
As the docs say "This method is invoked right before an action is to be executed (after all possible filters.) You may override this method to do last-minute preparation for the action."
Also you can define public variables in you main controller (Components/Controller.php) so every other controller has access to these. You can then use them in your layout using $this-variable...
Hope this helps :)
You need to create a class that extends CMenu in /protected/components/extendingclassname
<?php
Yii::import('zii.widgets.CMenu');
class Notifications extends CMenu
{
public function init()
{
//query
$requestor=Yii::app()->user->name;
$count = Requests::model()->count( 'requestor=:requestor', array('requestor' => $requestor));
// Now add the menu items:
$this->items = array(
array(
'label' => "$count New messages",
'url' => array('user/notifications'),
),
// ...
);
parent::init();
}
}
?>
Then include the following line within your /layouts.main.php.Hope this helps a beginner who is not sure where to use the class.That's something Michael Härtl forgot to mention.

Is it possible to render custom view (just custom .phtml) template with Phalcon\Mvc\View?

I need to render email templates in variable to send them later (which are stored in .phtml files), and i really don't want to implement my special class for handling this.
Is it possible to render not controller action view, but custom one?
I tried following code, but it outputs NULL :((
// Controller context
$view = new Phalcon\Mvc\View();
$view->setViewsDir('app/views/');
$view->setVar('var1', 'var2');
// Setting some vars...
$view->start();
$view->partial($emailTemplatePath);
$view->finish();
$result = $view->getContent();
var_dump($result); // Gives null
In addition to the response by Nikolaos, you can use $view->getRender() to render a single view returning its output.
$view->setViewsDir('apps/views/');
echo $view->getRender('partials', 'test'); // get apps/views/partials/test.phtml
You need to check the path of the $emailTemplatePath. It should point to the correct file i.e.
// points to app/views/partials/email.phtml
$view->partial('partials/email');
If you are using Volt and have registered that as your engine, then your file will need to be:
// app/views/partials/email.volt
I have a project where I use email and pdf templates and what I did was to have the rendering all take place within components.
Firstly, my folder structure contains (and I will only put here what is relevant) a cache, components and views directory. Let's look at the email setup rather than the PDF as this is more relevant to your situation.
/app
/cache
/email
/components
/views
/email
/elements
Of course there is public, controllers etc but let's not think about them for this.
I'm using Swift mailer for mine but I hope you will be able to use this all the same. In /app/components/Swift.php I have a __construct that calls for this->init_template_engine();
/**
* Create a volt templating engine for generating html
*/
private function init_template_engine() {
$this->_template = new \Phalcon\Mvc\View\Simple();
$di = new \Phalcon\DI\FactoryDefault();
$this->_template->setDI($di);
$this->_template->registerEngines([
'.volt' => function($view, $di) {
$volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
$volt->setOptions([
'compiledPath' => APP_DIR."cache".DS."email".DS, // render cache in /app/cache/email/
'compiledSeparator' => '_'
]);
return $volt;
// or use ".phtml" => 'Phalcon\Mvc\View\Engine\Php' if you want,
// both will accept PHP code if ya don't fancy it being a 100% volt.
},
]);
// tell it where your templates are
$this->_template->setViewsDir(APP_DIR.'views'.DS.'email'.DS);
return $this->_template;
}
The constants above (like APP_DIR) are something I have already made in my bootstrap and all they do is store full paths to directories.
Once the $_template variable has a template engine set up I can then use it to render my templates.
/**
* Returns HTML via Phalcon's volt engine.
* #param string $template_name
* #param array $data
*/
private function render_template($template_name = null, $data = null) {
// Check we have some data.
if (empty($data)) {
return false; // or set some default data maybe?
}
// Use the template name given to render the file in views/email
if(is_object($this->_template) && !empty($template_name)) {
return $this->_template->render($template_name, ['data' => $data]);
}
return false;
}
A sample volt email template may look like this:
{{ partial('elements/email_head') }}
<h2>Your Order has been dispatched</h2>
<p>Dear {{ data.name }}</p>
<p>Your order with ACME has now been dispatched and should be with you within a few days.</p>
<p>Do not hesitate to contact us should you have any questions when your waste of money arrives.</p>
<p>Thank you for choosing ACME Inc.</p>
{{ partial('elements/email_foot') }}
All I have to do then is grab the html and use swiftmailer's setBody method and I'm done:
->setBody($this->render_template($template, $data), 'text/html');
You don't need to place separate view engines like this in components, it could become memory hungry like that, but it does show the whole process. Hope that makes sense :)
The easiest way to render a view and return it as a variable is to use the Phalcon\Mvc\View\Simple class. In your controller, declare a new instance of the Simple view class and attach a rendering engine to it. You can then use its render() method to select a view file and pass in variables:
// create a simple view to help render sections of the page
$simple_view = new \Phalcon\Mvc\View\Simple();
$simple_view->setViewsDir( __DIR__ . '/../views/' );
$simple_view->setDI( $this->di );
$simple_view->registerEngines(array(
'.volt' => 'Phalcon\Mvc\View\Engine\Volt'
));
// use the simple view to generate one or more widgets
$widget_html = array();
$widget_objects = $widget_search->getWidgetObjects();
forEach( $widget_objects as $widget ){
$widget_html[] = $simple_view->render('index/widgetview',array('widget'=>$widget));
}
// pass the html snippets as a variable into your regular view
$this->view->setVar('widget_html',$widget_html);
use $view->render('partials/email') instead of calling partial method.
I usually use Volt engine and a simple way is a redefine view in DI container, like that:
$view = $this->view;
$content = $view->getRender('mail', 'show',
array(
"var1" => "some value 1",
"var2" => "some value 2"
),
function($view) {
$view->setRenderLevel(\Phalcon\Mvc\View::LEVEL_LAYOUT);
}
);
echo $content;

ZF2, how to create form view helper?

I want to change the way ZF2 shows the form elements. I think I have to create my own view helper but I don't know how.
I Googled for it but didn't find any useful resource.
See the SourceCode of existing Zend\Form\View\Helper*
Basically you extend those and overwrite the required functions of stuff you want to modify.
After that you'll need to register your very own view helper. This is easily done within Module.php's getViewHelperConfig()
public function getViewHelperConfig()
{
return array(
'invokables' => array(
'customViewHelperCallName' => 'Namespace\Form\View\Helper\Classname'
)
);
}