Zend: Quick and succinct way of inserting custom HTML into a Zend_Form? - zend-framework

Is there some method that accepts inserting custom html without having to actually add form controls, even if they're hidden and making my html a decorator?
I'm looking for something like:
$this->addCustomElement( array(
'div',
'body' => '<p>inner text</p>'
) );
I need something short and quick, I don't want to create a new class or something overkill.

Well it's really as simple as this:
$note = new Zend_Form_Element('note');
$note->helper = 'formNote';
$note->setValue('<b>hi</b>');
$form->addElement($note);
But the problem is that when you submit the form, the form calls $note->isValid(), which overrides the value, so if there are errors with the form, the next time you display it, the custom HTML won't be shown. There are two easy ways to fix this, the first is to override isValid() in your Form class like this:
public function isValid($data)
{
$note = $this->note->getValue();
$valid = parent::isValid($data);
$this->note->setValue($note);
return $valid;
}
But personally I find this kinda hackish way, and prefer the second option. That is to write a very simple class (this should really be part of Zend itself, I have no idea why it isn't, since it includes a formNote view helper, but no element that uses it):
class My_Form_Element_Note extends Zend_Form_Element_Xhtml
{
public $helper = 'formNote';
public function isValid($value, $context = null) { return true; }
}
Then you just have to do:
$note = new My_Form_Element_Note('note');
$note->setValue('<b>hi</b>');
$form->addElement($note);
And everything will just work.
Other options include doing some black magic with decorators, but I really recommend you to not go down that path.

Also note the AnyMarkup Decorator.

Related

TYPO3 Extension: Generate a PDF

Im trying to make an extension with Kickstarter that overrides the normal rendering of the page, and renders a PDF file. For this im using FPDF. But im not sure how to do it. I tried doing this, but it didnt work:
<?php
// require_once(PATH_tslib . 'class.tslib_pibase.php');
class tx_ishurkunde_pi1 extends tslib_pibase {
public $prefixId = 'tx_ishurkunde_pi1';
public $scriptRelPath = 'pi1/class.tx_ishurkunde_pi1.php';
public $extKey = 'ish_urkunde';
public $pi_checkCHash = TRUE;
public function main($content, array $conf) {
if (!t3lib_extMgm::isLoaded('fpdf')) return "Error!";
$pdf = new FPDF();
$pdf->AddPage();
$content = $pdf->Output('', 'S');
return $content;
}
}
?>
It still keeps rendering the normal web template. What am I missing?
FYI, Im not trying to render the HTML as PDF. Im trying to generate a PDF from scratch, using the URL parameters are text variables.
As far as I understood, your aim is to render a PDF instead of page elements.
Your current approach will not work since you are inserting a plugin onto the page. The plugin's return value is then given back to the TYPO3 content parser, and if the page has finished parsing, it is displayed. There is no part in it where you can throw over the whole page rendering; At least it is not intended to do, and you shouldn't to (albeit there are extensions that do this).
The eID approach would be to either create an eID script (have a look at dd_googlesitemap) which is called via GET param and renders only what you need. There you basically can do everything you want to.
In your extension's ext_localconf.php you register the eID script, like this:
$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include'][$_EXTKEY] = "EXT:{$_EXTKEY}/path/to/my/EIDHandler.php";
An Example eID handler structure:
class Tx_MyExt_EIDHandler
{
public function main()
{
// Your code here
}
}
$output = t3lib_div::makeInstance('Tx_MyExt_EIDHandler');
$output->main();
To call your eID script in the frontend, you append the appropriate GET params, like http://example.com/index.php?eID=tx_myext. This is the array key you defined in your ext_localconf.php (in my example, it is $_EXTKEY, but it can basically be any string).
The plugin/typoscript approach would be like e.g. TemplaVoila does it: You create a PAGE type and call a user_func which does your things. This would be the fastest approach because you already have a plugin. Important is that you render your own page type with only your plugin in it.
Example TypoScript:
specialPage = PAGE
specialPage {
type = 2
10 = USER
10.userFunc = tx_myextension_pi1->myFunc
}
After that, you can call your new page with http://example.com/index.php?type=2. However, headers etc are still rendered and you may need to remove them.

How do I change the tag used by Zend_View_Helpers_FormErrors?

When using Zend_Form, if an element is not valid the form returns the errors by way of an unordered list. How do I change this to use paragraph tags instead?
I have attempted loading the Errors decorator for the elements and calling setOptions() to pass in a bunch of tags to replace the ul/li stuff being used by Zend_Form_Decorator_FormErrors, but that didn't work =/ Instead Zend_Form_Decorator_Errors just put the options as attribute/value pairs in the ul tag.
Instead of extending the Errors decorator I have extended the formErrors view helper, getting it to accept and process the options in the array. The formErrors view helper has setters to let me change the tags being used:
class My_View_Helper_FormErrors extends Zend_View_Helper_FormErrors
{
public function formErrors($errors, array $options = null)
{
if(key_exists('htmlElementStart', $options))
{
$this->setElementStart($options['htmlElementStart']);
unset($options['htmlElementStart']);
}
if(key_exists('htmlElementEnd', $options))
{
$this->setElementEnd($options['htmlElementEnd']);
unset($options['htmlElementEnd']);
}
if(key_exists('htmlElementSeparator', $options))
{
$this->setElementSeparator($options['htmlElementSeparator']);
unset($options['htmlElementSeparator']);
}
return parent::formErrors($errors, $options);
}
}
To pass options, I got the error decorator and setOptions() on it:
$element->getDecorator()->setOptions(
array(
'class' => 'error',
'htmlElementStart' => '<p%s>',
'htmlElementEnd' => '</p>',
'htmlElementSeparator' => '<br/>'
)
);
And tell the elements to load the helper path:
$element->getView()->addHelperPath('My/View/Helper', 'My_View_Helper');
Unfortunatelly, you cannot change the output format by just passing a bunch of options.
If you like to change this behaviour you have no choice but to write your own Errors decorator (most likely a derivative from the original Errors decorator). This new decorator has to have its render () method overwritten in order to be able to call your own view helper (instead of the formErrors helper which ZF uses by default).

How to change the separation character of Zend Url?

I use Zend URL view helper for building my urls. Everythings works exactly as I'd like to, except one thing: The character used for replacing spaces in the url is a plus (+). I'd like it to be a 'min' (-). How can I change this?
Example:
Now: /nl/nieuws/bericht/3/title/nieuwe**+affiches
Wish: /nl/nieuws/bericht/3/title/nieuwe-**affiches
Thanks in advcance!
This isn't in the documentation anywhere, but it appears that the Zend URL view helper can take a parameter in it's $urlOptions array called chainNameSeparator. No guarantee that's what you're looking for, but trying playing with that and see if it changes anything.
This is likely happening because, by default, Zend_View_Helper_Url will urlencode() what you send it, which would translate spaces into +. My suggestion to you would be to create a new view helper for the type of URL in your code that needs the special inflection.
Something like:
class Default_View_Helper_SpecialUrl extends Zend_View_Helper_Abstract
{
public function specialUrl(array $opts = array(), $name = null, $reset = false, $encode = true)
{
if (!empty($opts['whatever'])) {
$opts['whatever'] = str_replace(' ', '-', $opts['whatever']);
}
$router = Zend_Controller_Front::getInstance()->getRouter();
return $router->assemble($opts, $name, $reset, $encode);
}
}
This way the spaces are changed for whatever necessary route parameters before URL encoding happens by the router.

Zend Form Validator : Element A or Element B

I have two fields in my Zend Form, and i want to apply the validation rule that ensures the user enters either one of the these two fields.
$companyname = new Zend_Form_Element_Text('companyname');
$companyname->setLabel('Company Name');
$companyname->setDecorators($decors);
$this->addElement($companyname);
$companyother = new Zend_Form_Element_Text('companyother');
$companyother->setLabel('Company Other');
$companyother->setDecorators($decors);
$this->addElement($companyother);
How can i add a validator that will look at both fields?
See the 'Note: Validation Context' on at this page. Zend_Form passes the context along to every Zend_Form_Element::isValid call as the second parameter. So simply write your own validator that analyzes the context.
EDIT:
Alright, I thought I'ld take a shot at this myself. It's not tested, nor is it a means to all ends, but it will give you a basic idea.
class My_Validator_OneFieldShouldBePresent extend Zend_Validator_Abstract
{
const NOT_PRESENT = 'notPresent';
protected $_messageTemplates = array(
self::NOT_PRESENT => 'Field %field% is not present'
);
protected $_messageVariables = array(
'field' => '_field'
);
protected $_field;
protected $_listOfFields;
public function __construct( array $listOfFields )
{
$this->_listOfFields = $listOfFields;
}
public function isValid( $value, $context = null )
{
if( !is_array( $context ) )
{
$this->_error( self::NOT_PRESENT );
return false;
}
foreach( $this->_listOfFields as $field )
{
if( isset( $context[ $field ] ) )
{
return true;
}
}
$this->_field = $field;
$this->_error( self::NOT_PRESENT );
return false;
}
}
Usage:
$oneOfTheseFieldsShouldBePresent = array( 'companyname', 'companyother' );
$companyname = new Zend_Form_Element_Text('companyname');
$companyname->setLabel('Company Name');
$companyname->setDecorators($decors);
$companyname->addValidator( new My_Validator_OneFieldShouldBePresent( $oneOfTheseFieldsShouldBePresent ) );
$this->addElement($companyname);
$companyother = new Zend_Form_Element_Text('companyother');
$companyother->setLabel('Company Other');
$companyother->setDecorators($decors);
$companyname->addValidator( new My_Validator_OneFieldShouldBePresent( $oneOfTheseFieldsShouldBePresent ) );
$this->addElement($companyother);
The solution provided by #fireeyedboy is handy but not working for this exact issue.
Zend_Validate_Abstract is using the context, which cannot be passed as variable to isValid(). This way when using the isValid() method (no matter if the original or overwritten one) the empty fields are not passed over and validated (unless you have setRequired(true) or setAllowEmpty(false), which we don't want). So in the case when you leave both two fields (companyname and companyother) empty, no action will take place. The only solution I am aware of is extending the Zend_Validate class to allow empty fields being validated.
Please let me know if you know better solution as I am struggling with similar problem too.
I haven't come across such a solution, but it's perfectly valid so +1.
I would extend Your_Form::isValid() to include a manual check for the values of those two elements.
If all fields pass their own individual validators, this validation probably belongs on the form as-a-whole and such it could be placed on the validation of the form instead of the fields. Do you agree with this line of thinking?
I agree with #chelmertz that a feature like this does not exists.
What I don't agree is extending Your_Form::isValid(). Instead, I'd write a custom Validator that accepts the values of both form elements that have to have a value. This way I could reuse it on arbitrary form elements. This is somewhat similar to the Identical Validator.

Wordpress: Accessing A Plugin's Function From A Theme

I'm trying to add some functionality from a plugin I have made into a Wordpress theme but I am having little joy. The documentation doesn't really help me solve the problem so perhaps someone here can help.
I have a plugin in Wordpress that is activated and working fine. The class for this plugin has a function called generateHtml which I would like to access from a Wordpress Theme. But whatever I try, I cannot seem to access my plugin's code.
Can either give me a summary of what I need to do to get a theme accessing code from a plugin and/or point out there I am going wrong in my code:
Plugin:
<?php
/** Usual comments here **/
if (!class_exists("ImageRotator")) {
class ImageRotator {
private $uploadPath = '';
private $pluginPath = '';
private $options;
function __construct() {
$this->uploadPath = dirname(__file__).'\\uploads\\';
// add_shortcode('imagerotator', array(&$this, 'generateHtml'));
}
// Various functions for plugin
function generateHtml() {
echo '<p>Hello World</p>';
}
}
}
/**
* Create instance of image rotator
*/
$imageRotator = new ImageRotator();
/**
* Create actions & filters for Wordpress
*/
if (isset($imageRotator)) {
// Actions
add_action('admin_menu', array(&$imageRotator, 'createMenu'));
add_action('admin_init', array(&$imageRotator, 'registerSettings'));
add_action('imagerotator_show', array(&$imageRotator, 'generateHtml'));
}
Portion from theme header page:
<?php if (isset($imageRotator)) {
$imageRotator->generateHtml();
} else if (isset($ImageRotator)) {
print_r($ImageRotator);
} else {
echo '<p>Nope!</p>';
}
if (function_exists("imagerotator_show")) {
echo 'Function found';
} else {
echo 'Function NOT found';
}
?>
Currently all I ever see is "Nope" and "Function NOT found". Thanks for any input.
Lee,
For starters, "imagerotator_show" is not a function; it's the name of a type of action. When you use the add_action() function, Wordpress just adds your method to the list of functions/methods to call when a particular action is triggered. Thus your second test will always respond with 'Function NOT found'.
The most likely cause of the first problem is failing to declare the method you want to call as a public method. You're also making the code harder than it needs to be.
The best practice I've seen for declaring methods and registering hooks from a class looks something like this:
if ( ! class_exists( 'Foo' ) ):
class Foo {
function __construct() {
add_action( 'hook_name', array( &$this, 'my_hook_implementation' ) );
}
function my_hook_implementation() {
// does something
}
public function my_special_method() {
// does something else
}
}
if ( class_exists( 'Foo' ) ):
$MyFoo = new Foo();
This allows your class to keep all of its implementation details private. When you need to call my_special_method(), you do it as follows:
$MyFoo->my_special_method();
#andrew since I can't comment I thought I would answer your ancillary question. See:
http://net.tutsplus.com/tutorials/wordpress/create-wordpress-plugins-with-oop-techniques/
Where it is explained that when defining a callback function from an object you have to use the array function. It's basically saying get the function 'my_hook_implementation' from the object $this and use it as the callback parameter to the add action hook. It is because you defined the function within the scope of the object and you have to define the scope in order for PHP to know what function you are talking about. The scope being the object referred to by the variable $this.
You just need to use do_action() function, inside your theme.
If you want the function generateHtml to appears inside your header.php you just need to open the header.php file and paste <?php do_action('imagerotator_show'); ?> where you want and then your function will be called there.