Reputation: 406
Some time ago, Matthew Weier O'Phinney posted this article on his blog about creating composite form elements in Zend Framework 1.
I'm trying to create the same element for my custom library in Zend Framewor 2 but I'm having issues finding the form view helper when rendering the form.
Here is my element (DateSegmented.php):
<?php
namespace Si\Form\Element;
use Zend\Form\Element;
use Zend\ModuleManager\Feature\ViewHelperProviderInterface;
class DateSegmented extends Element implements ViewHelperProviderInterface
{
public function getViewHelperConfig(){
return array( 'type' => '\Si\Form\View\Helper\DateSegment' );
}
protected $_dateFormat = '%year%-%month%-%day%';
protected $_day;
protected $_month;
protected $_year;
/**
* Seed attributes
*
* @var array
*/
protected $attributes = array(
'type' => 'datesegmented',
);
public function setDay($value)
{
$this->_day = (int) $value;
return $this;
}
public function getDay()
{
return $this->_day;
}
public function setMonth($value)
{
$this->_month = (int) $value;
return $this;
}
public function getMonth()
{
return $this->_month;
}
public function setYear($value)
{
$this->_year = (int) $value;
return $this;
}
public function getYear()
{
return $this->_year;
}
public function setValue($value)
{
if (is_int($value)) {
$this->setDay(date('d', $value))
->setMonth(date('m', $value))
->setYear(date('Y', $value));
} elseif (is_string($value)) {
$date = strtotime($value);
$this->setDay(date('d', $date))
->setMonth(date('m', $date))
->setYear(date('Y', $date));
} elseif (is_array($value)
&& (isset($value['day'])
&& isset($value['month'])
&& isset($value['year'])
)
) {
$this->setDay($value['day'])
->setMonth($value['month'])
->setYear($value['year']);
} else {
throw new Exception('Invalid date value provided');
}
return $this;
}
public function getValue()
{
return str_replace(
array('%year%', '%month%', '%day%'),
array($this->getYear(), $this->getMonth(), $this->getDay()),
$this->_dateFormat
);
}
}
And here is my form view helper:
<?php
namespace Si\Form\View\Helper;
use Zend\Form\ElementInterface;
use Si\Form\Element\DateSegmented as DateSegmented;
use Zend\Form\Exception;
class DateSegmented extends FormInput
{
/**
* Render a form <input> element from the provided $element
*
* @param ElementInterface $element
* @throws Exception\InvalidArgumentException
* @throws Exception\DomainException
* @return string
*/
public function render(ElementInterface $element)
{
$content = "";
if (!$element instanceof DateSegmented) {
throw new Exception\InvalidArgumentException(sprintf(
'%s requires that the element is of type Si\Form\Input\DateSegmented',
__METHOD__
));
}
$name = $element->getName();
if (empty($name) && $name !== 0) {
throw new Exception\DomainException(sprintf(
'%s requires that the element has an assigned name; none discovered',
__METHOD__
));
}
$view = $element->getView();
if (!$view instanceof \Zend\View\View) {
// using view helpers, so do nothing if no view present
return $content;
}
$day = $element->getDay();
$month = $element->getMonth();
$year = $element->getYear();
$name = $element->getFullyQualifiedName();
$params = array(
'size' => 2,
'maxlength' => 2,
);
$yearParams = array(
'size' => 4,
'maxlength' => 4,
);
$markup = $view->formText($name . '[day]', $day, $params)
. ' / ' . $view->formText($name . '[month]', $month, $params)
. ' / ' . $view->formText($name . '[year]', $year, $yearParams);
switch ($this->getPlacement()) {
case self::PREPEND:
return $markup . $this->getSeparator() . $content;
case self::APPEND:
default:
return $content . $this->getSeparator() . $markup;
}
$attributes = $element->getAttributes();
$attributes['name'] = $name;
$attributes['type'] = $this->getInputType();
$attributes['value'] = $element->getCheckedValue();
$closingBracket = $this->getInlineClosingBracket();
if ($element->isChecked()) {
$attributes['checked'] = 'checked';
}
$rendered = sprintf(
'<input %s%s',
$this->createAttributesString($attributes),
$closingBracket
);
if ($element->useHiddenElement()) {
$hiddenAttributes = array(
'name' => $attributes['name'],
'value' => $element->getUncheckedValue(),
);
$rendered = sprintf(
'<input type="hidden" %s%s',
$this->createAttributesString($hiddenAttributes),
$closingBracket
) . $rendered;
}
return $rendered;
}
/**
* Return input type
*
* @return string
*/
protected function getInputType()
{
return 'datesegmented';
}
}
This question describes adding the view helper as an invokable, but it's already being declared, as my custom library (Si) has been added to the 'StandardAutoLoader'.
Upvotes: 3
Views: 4742
Reputation: 406
OK, figured this one out eventually.
Copy Zend/Form/View/HelperConfig.php to the same location in your custom library. Adjust contents to reflect your view helpers.
Add the following to an event or bootstrap in your Module.php
$app = $e->getApplication();
$serviceManager = $app->getServiceManager();
$phpRenderer = $serviceManager->get('ViewRenderer');
$plugins = $phpRenderer->getHelperPluginManager();
$config = new \Si\Form\View\HelperConfig;
$config->configureServiceManager($plugins);
Update the 'Si' namespace with your custom one.
The 'class already exists' error was actually down to the includes at the top of my view helper file. I have updated it with:
use Zend\Form\View\Helper\FormElement;
use Zend\Form\Element;
use Zend\Form\ElementInterface;
use Zend\Form\Exception;
I also updated the instanceof statement to an absolute location due to the duplicate class names:
if (!$element instanceof \Si\Form\Element\DateSegmented) {
There were further errors in the translation from ZF1 to 2 but they are not related to this issue.
Upvotes: 1
Reputation: 16445
The way i understand your code is: You are creating a new Form\Element
as well as a new Form\View\Helper
. In this case the following information is needed for you:
The StandardAutoloader
only takes care of actually finding the classes. The declaration of the invokables
inside the getViewHelperConfig()
is there, so the framework knows what Class
to load when the ViewHelper
is called.
In your case you'd do it like this:
public function getViewHelperConfig()
{
return array(
'invokables' => array(
'dateSegmented' => 'Si\Form\View\Helper\DateSegmented'
)
);
}
Zend Framework 2 does this for it's own ViewHelpers
inside /Zend/Form/View/HelperConfig.php
Upvotes: 0