views:

296

answers:

3

I was wondering if is there an easy way to generate views from form objects when dealing with CRUDs.

I mean, when we have these options: VIEW | EDIT | DELETE I want my VIEW option like EDIT option, but without form elements, just the values.

This will minimize so much the time spent to create these views.

Someone knowks something like that?

A: 

I'm not sure if I understand, but I think that for the view option you can just fetch the data from your model. No need to access them through Zend_Form.

But if you want the make your form read-only, you can add readonly (setAttrib('readonly', 'readonly')) attribute to your elements.

Marcin
Why create I view from scratch when your view is exactly alike to your form except for the input elements? For a real CRUD generation I think this need to be automated.
Keyne
+3  A: 

In my last project I had this dilemma too. My solution may not be the most elegant, but it did the job. Mind you, I use a Form viewscript decorator in stead of a full decorator generated elements. But you could adjust this example to use decorators I presume. What I'm showing is a very basic example, to give you a general idea. Here's what I did:

class Cms_Form_Page extends Zend_Form
{
  const FOR_CREATE = 'forCreate';
  const FOR_READ   = 'forRead';
  const FOR_UPDATE = 'forUpdate';
  const FOR_DELETE = 'forDelete';

  protected $_name = 'page';

  private $_for;

  private $_viewScripts = array(
    self::FOR_CREATE => 'page-manager/partials/form-page-create.phtml',
    self::FOR_READ => 'page-manager/partials/form-page-read.phtml',
    self::FOR_UPDATE => 'page-manager/partials/form-page-update.phtml',
    self::FOR_DELETE => 'page-manager/partials/form-page-delete.phtml'
  );

  public function __construct( $for = self::FOR_CREATE, $options = null )
  {
    $this->_for = $for;

    parent::__construct( $options );
  }

  public function init()
  {
    $this->setName( $this->_name )
        ->setAttribs( array( 'accept-charset' => 'utf-8' ) )
        ->setDecorators( array(
            'PrepareElements',
            array( 'ViewScript', array( 'viewScript' => $this->_viewScripts[ $this->_for ] ) ),
            'Form'
        ) );

    $elements = array();

    swith( $this->_for )
    {
      case self::FOR_CREATE:
        $title = new Zend_Form_Element_Text( 'title' );
        $elements[] = $title;
        break
      case self::FOR_READ:
        $id = new Zend_Form_Element_Hidden( 'id' );
        $elements[] = $id;
        break;
      case self::FOR_UPDATE:
        $id = new Zend_Form_Element_Hidden( 'id' );
        $elements[] = $id;
        $title = new Zend_Form_Element_Text( 'title' );
        $elements[] = $title;
      break;
        case self::FOR_DELETE:
        $id = new Zend_Form_Element_Hidden( 'id' );
        $elements[] = $id;
        break;
      default:
        throw new Exception( 'invalid Form type' );
    }

    $submit = new Zend_Form_Element_Button( 'submit' );
    $elements[] = $submit;

    $this->addElements( $elements );
  }
}

So, basically, I pass one of the class constants to it's constructor. And based on that value, I determine what elements are needed for the form, and how the elements should be rendered.

For instance, for create you could have a select dropdown form field where you would choose a Locale, where for delete this would be a hidden field (not shown in my example btw).

Hope this has given you some ideas.

PS:
In one of the selected viewscripts you could then simply show the value of an element (along with rendering the hidden element too), with something like:

<?
  $form = $this->element;
?>

... some html

// let's presume id and locale are hidden form fields for current form type 
// (Cms_Form_Page::FOR_UPDATE for instance)
<?= $form->id->renderViewHelper(); ?>
<?= $form->locale->renderViewHelper(); ?>

// and here we simply output the current locale value
// of course, you should have populated the values in the form somewhere first
<dt>Current locale:</dt>
<dd><?= $form->locale->getValue(); ?></dd>

...etc

So, I think you'ld be best of with using viewscript decorators for the form, or you could roll your own form element decorator that renders the hidden field (if neccesary) and simply shows it's value in some html tag.

fireeyedboy
Thx! You shed me some light. With this in mind, I have thought if instead of a viewscript I can just have a different viewhelper for my "form-page-read", which will be a <span>$value</span> for example. This viewhelper will echo the value passed through $form->populate() and will use the same decorators of a normal form, except for the viewhelper that render the element. With that I think I can achieve a completely CRUD generation.
Keyne
@Keyne: exactly! That was kind of what I was proposing. :)
fireeyedboy
+1  A: 

Hector from Nabble, show me this, which seems to be the best way:

class Default_View_Helper_FormView extends Zend_View_Helper_Abstract
{
    public function formView(Zend_Form $form)
    {
        $html = "<dl>";
        foreach ($form->getElements as $element) {
            $html .= "<dt>{$element->getLabel()}</dt>";
            $html .= "<dd>{$element->getValue()}</dd>";
        }
        $html .= "</dl>";
        return $html;
    }
}
Keyne