Zend Framework 2 two templates in one layout? - zend-framework2

In each module in my application I'll have a main content section and a sidebar menu.
In my layout I have the following...
<div id="main" class="span8 listings">
<?php echo $this->content; ?>
</div>
<div id="sidebar" class="span4">
<?php echo $this->sidebar; ?>
</div>
My controllers all return a single ViewModel which specifies the content (see below) but how do I get it to also populate the sidebar?
public function detailsAction()
{
*some code to populate data*
$params = array('data' => $data);
$viewModel = new ViewModel($params);
$viewModel->setTemplate('school/school/details.phtml');
return $viewModel;
}
I've got a feeling I am doing something fundamentally wrong here.

You can include "sub templates" by using the partial view helper
<div id="main" class="span8 listings">
<?php echo $this->content; ?>
</div>
<div id="sidebar" class="span4">
<?php echo $this->partial('sidebar.phtml', array('params' => $this->params)); ?>
</div>

In a controller you could use view models nesting and the layout plugin:
public function fooAction()
{
// Sidebar content
$content = array(
'name' => 'John'
'lastname' => 'Doe'
);
// Create a model for the sidebar
$sideBarModel = new Zend\View\Model\ViewModel($content);
// Set the sidebar template
$sideBarModel->setTemplate('my-module/my-controller/sidebar');
// layout plugin returns the layout model instance
// First parameter must be a model instance
// and the second is the variable name you want to capture the content
$this->layout()->addChild($sideBarModel, 'sidebar');
// ...
}
Now you just echo the variable in the layout script:
<?php
// 'sidebar' here is the same passed as the second parameter to addChild() method
echo $this->sidebar;
?>

// Module.php add it is
use Zend\View\Model\ViewModel;
public function onBootstrap($e)
{
$app = $e->getParam('application');
$app->getEventManager()->attach('dispatch', array($this, 'setLayout'));
}
public function setLayout($e)
{
// IF only for this module
$matches = $e->getRouteMatch();
$controller = $matches->getParam('controller');
if (false === strpos($controller, __NAMESPACE__)) {
// not a controller from this module
return;
}
// END IF
// Set the layout template
$template = $e->getViewModel();
$footer = new ViewModel(array('article' => "Dranzers"));
$footer->setTemplate('album/album/footer');
$template->addChild($footer, 'sidebar');
}

Related

How to create grouped form fields in symfony 1.4

I want to group the form fields like field set or simply enclosed by div. My form needs to be look like below
<form>
<div class="step-1">
Field 1
Field 2
</div>
<div class="step-2">
Field 3
Field 4
</div>
</form>
Graphical example :
Edit : Form class added for reference!
class ProfileForm extends BaseProfileForm
{
public function configure()
{
..... // other widget configuration
$this->embedForm('media', new MediaForm());
}
}
How can I do this in symfony form?
For example:
In action:
$this->form = new MyCoolForm()
In templates:
<form name="form name" id="MyCoolForm" action="<?php echo url_for('action_url') ?>" method="post" <?php $form->isMultipart() and print 'enctype="multipart/form-data" ' ?>>
<?php echo $form['name']->render() ?>
<?php echo $form['name']->renderError(); ?>
<fieldset>
<legend>Ppassword:</legend>
<?php echo $form['password']->render() ?>
<?php echo $form['password']->renderError(); ?>
<?php echo $form['password_again']->render() ?>
<?php echo $form['password_again']->renderError(); ?>
<fieldset>
<?php echo $form->renderHiddenFields(); ?>
</form>
etc...

Issues with sfDoctrinePager pagination

I am using sfDoctrinePager in my module. I search the table on one or more criteria. First time the result displayed is correct but after it if I click on page 2 or more it again gives me the whole resultset and my search resultset is lost.
I am facing this issue for the first time, even though I have been using sfDoctrinePager since a long time.
I get this Array from my search form
(
[field_type] => log_type
[field_value] => ABC
[is_active] => on
)
I send this array variable to my model:
$getQuery = $objMgr->getSearchQuery($request->getPostParameters());
** The query which runs in model is:
public function getSearchQuery($arrSearchValues)
{
$q = Doctrine_Query::create()
->select('u.*')
->from('SomsConfigValues u');
->where('u.deleted_at IS NULL');
if(isset($arrSearchValues['is_active']) && $arrSearchValues['is_active'] == 'on'){
$q->where('u.is_active = ?', 1);
}
if(isset($arrSearchValues['field_type']) && $arrSearchValues['field_type'] != ""){
$revertChg = ucwords(str_replace("_", " ", $arrSearchValues['field_type']));
$q->andWhere('u.field_type = ?', $revertChg);
}
if(isset($arrSearchValues['field_value']) && $arrSearchValues['field_value'] != ''){
$q->andWhere('u.field_type = ?', $arrSearchValues['field_value']);
}
return $q;
}
First time I get the perfect searched result, but second time (when I click on page 2 it gives me whole resultset).
My action is:
public function executeIndex(sfWebRequest $request)
{
$objMgr = AdminFactory::adminObject();
$getQuerys = $objMgr->getSearchQuery($request->getPostParameters());
$this->config_values = $getQuerys;
$this->pager = new sfDoctrinePager('configValues', sfConfig::get('app_max_row_display'));
$this->pager->setQuery($this->config_values);
$this->pager->setPage($request->getParameter('page', 1));
$this->pager->init();
}
The template where I am using this pagination is:
<div class="grid_footer">
<div style="padding:5px;">
<?php if(count($pager->getLinks())) : ?>
<div class="tableControl">
<div class="pagination_inner">
<?php if(!$pager->isFirstPage()){ ?>
<?php echo link_to1(image_tag('/images/first.png'), 'configValues/index?page='.$pager->getFirstPage()) ?>
<?php echo link_to1(image_tag('/images/previous.png'), 'configValues/index?page='.$pager->getPreviousPage()) ?>
<?php } ?>
<div class="numbers">
<?php if ($pager->haveToPaginate()): ?>
<?php $links = $pager->getLinks(); foreach ($links as $page): ?>
<?php echo ($page == $pager->getPage()) ? $page : link_to($page, 'configValues/index?page='.$page) ?>
<?php endforeach ?>
<?php endif ?>
</div>
<?php if(!$pager->isLastPage()){ ?>
<?php echo link_to1(image_tag('/images/next.png'), 'configValues/index?page='.$pager->getNextPage()) ?>
<?php echo link_to1(image_tag('/images/last.png'), 'configValues/index?page='.$pager->getLastPage()) ?>
<?php } ?>
</div>
</div>
<?php echo $pager->getNbResults() ?> results (page <?php echo $pager->getPage(); ?>/<?php echo count($pager->getLinks()); ?>)
<?php endif; ?>
</div>
</div>
I was having exactly the same problem. The only way around this I found is as you said, to store the query. Instead of using the session, create an attribute in the user to store this.
in the action class put something like...
$this->getUser()->setAttribute('searchQuery', $getQuery);
This value persists through the session, so you can retreive it using e.g.
$storedQuery = $this->getUser()->getAttribute('searchQuery');
You can view the User attributes via the config item on the dev toolbar.

sfWidgetFormDoctrineChoice for NestedSet model

I'm experiencing a difficulty in rendering sfWidgetFormDoctrineChoice (set of checkboxes) widget for a NestedSet structure.
class ModelForm extends BaseModelForm
{
public function configure()
{
$this->setWidget('relatedmodel_list', new sfWidgetFormDoctrineChoice(array(
'expanded' => true,
'multiple' => true,
'model' => 'Relatedmodel',
'table_method' => 'fetchTree'
)));
}
}
class RelatedmodelTable extends Doctrine_Table
{
/**
* Gets tree elements in one query (one root only)
*/
public function fetchTree()
{
$q = $this->createQuery('m')
->addOrderBy('m.lft');
$tree = $q->execute(array(), Doctrine_Core::HYDRATE_RECORD_HIERARCHY);
return $tree;
}
}
Now, if I just render form like this: <?php echo $form['relatedmodel_list'] ?>
It will only display form widgets (checkboxes) for first level elements of my hierarchy.
I am looking for an implementation that will allow me to iterate over widget's choices the way I would iterate over collection:
<?php foreach ($form['relatedmodel_list'] as $widget): ?>
<?php echo $widget->render() ?>
<?php foreach ($widget->getChildren() as $child_widget): ?>
<?php echo $child_widget->render() ?>
<?php endforeach; ?>
<?php endforeach; ?>
I'm using sfWidgetFormTree to display my nestedSet. If you really want to display your tree in a flat way don't use HYDRATE_RECORD_HIERARCHY.
The widget linked is very convinient, you just have to provide a choices array like this :
$choices = array(
1=> array('label'=>'test', 'children'=>array(
2=> array('label'=>'test2', 'children'=> array(
3=> array('label'=>'test3'),
4=> array('label'=>'hans')
)),
5=> array('label'=>'wurst')
)),
6=>array('label'=>'letzter')
);
If anyone cares, I think I found a wonderful solution which allows you to recursively iterate over checkboxes in template. The idea behind it is that you configure 'relatedmodel_list' widget as a single checkbox and render it many times in your template (while iterating over relatedmodel collection).
class ModelForm extends BaseBookForm
{
public function configure()
{
$this->setWidget('relatedmodel_list', new myWidgetFormInputCheckbox());
}
}
Checkboxes now have incorrect name and value attributes. This can be fixed very easily:
class myWidgetFormInputCheckbox extends sfWidgetFormInputCheckbox
{
public function render($name, $value = null, $attributes = array(), $errors = array())
{
//fix value checking
if (in_array($attributes['value'], (array)$value))
{
$attributes['checked'] = 'checked';
}
//fix name for multiple
$name = $name . "[]";
return parent::render($name, null, $attributes, $errors);
}
}
Now we can recursively render our form widget in template:
//_form.php
<ul>
// Model::getRelatedTree() is proxy to Relatedmodel::fetchTree()
<?php include_partial('node', array('node' => $form->getObject()->getRelatedTree(), 'form' => $form)) ?>
</ul>
//_node.php
<?php foreach ($node as $item): ?>
<li>
<?php echo $form['pages_list']->render(array('value'=>$item->id)) ?>
<?php echo $form['pages_list']->renderLabel((string)$item) ?>
<?php if (isset($item['__children']) && count($item['__children']) > 0): ?>
<ul>
<?php include_partial('node', array('node' => $item['__children'], 'form' => $form)) ?>
</ul>
<?php endif; ?>
</li>
<?php endforeach; ?>

symfony - embedForm and form widgets not saving

I have an embeddedForm that I am trying to configure the widgets for.
Currently I am just outputting the form in a _form.php template like:
<?php echo $form ?>
This is great, but I'd like to have my form fields in a particular order, so I thought I'd try:
<?php echo $form['firstname']->renderRow() ?>
<?php echo $form['lastname']->renderRow() ?>
<?php echo $form['email_address']->renderRow() ?>
This gives me an invalid widget error.
Now I have 2 forms, one is a basic form, that simply embeds another form.
<?php
class labSupportForm extends sfGuardUserAdminForm
{
public function configure()
{
$form = new labSupportProfileForm($this->getObject()->getProfile());
$this->embedForm('profile', $form);
unset($this['is_super_admin'], $this['is_admin'], $this['permissions_list'], $this['groups_list']);
$this->widgetSchema['profile'] = $form->getWidgetSchema();
$this->validatorSchema['profile'] = $form->getValidatorSchema();
}
public function save($con = null)
{
$user = parent::save($con);
if (!$user->hasGroup('Lab Support'))
{
$user->addGroupByName('Lab Support');
$user->save();
}
return $user;
}
}
and:
<?php
class labSupportProfileForm extends sfGuardUserProfileForm
{
public function configure()
{
unset($this['email_new'],
$this['validate_at'],
$this['validate'],
$this['address_1'],
$this['address_2'],
$this['city'],
$this['country'],
$this['postcode'],
$this['created_at'],
$this['updated_at'],
$this['user_id'],
$this['is_super_admin'],
$this['is_admin'],
$this['permissions_list'],
$this['groups_list']);
}
}
But If I add the widget/validator to the labSupportForm and save, the firstname value doesn't save.
Am I doing something wrong here, as I would have thought this value would save.
Thanks
When you render a form by fields, you have to explicitly call $form->renderHiddenFields(). For example:
<?php echo form_tag_for($form, '#url') ?>
<table>
<tfoot>
<tr>
<td colspan="2">
<input type="submit" value="Save" />
<?php echo $form->renderHiddenFields() ?>
</td>
</tr>
</tfoot>
<tbody>
<?php echo $form['username']->renderRow() ?>
<?php echo $form['profile_form']->renderRow() ?>
</tbody>
</table>
</form>
Also, beware calling embedded form name the same as relation name (e.g. 'profile') or you will have troubles when saving it. Just add '_form' suffix and you will be safe:
$this->embedForm('profile_form', $form);
If you want to keep a linear display structure of your form fields, you should render them explicitly according to your widget schema:
<?php echo $form['username']->renderRow() ?>
<?php echo $form['profile_form']['first_name']->renderRow() ?>
<?php echo $form['profile_form']['last_name']->renderRow() ?>
Or you can do it automatically for all fields of an embedded form:
<?php foreach ($form['profile_form'] as $field): ?>
<?php if (!$field->isHidden()): ?>
<?php echo $field->renderRow() ?>
<?php endif; ?>
<?php endforeach; ?>
Call $this->saveEmbeddedForms() in the labSupportForm save method

Question about the code of the backend of symfony

this is the index action and template generated at the backend for the
model "coche".
public function executeIndex(sfWebRequest $request)
{
// sorting
if ($request->getParameter('sort') &&
$this->isValidSortColumn($request->getParameter('sort')))
{
$this->setSort(array($request->getParameter('sort'),
$request->getParameter('sort_type')));
}
// pager
if ($request->getParameter('page'))
{
$this->setPage($request->getParameter('page'));
}
$this->pager = $this->getPager();
$this->sort = $this->getSort();
}
This is the index template:
<?php use_helper('I18N', 'Date') ?>
<?php include_partial('coche/assets') ?>
<div id="sf_admin_container">
<h1><?php echo __('Coche List', array(), 'messages') ?></h1>
<?php include_partial('coche/flashes') ?>
<div id="sf_admin_header">
<?php include_partial('coche/list_header', array('pager' => $pager)) ?>
</div>
<div id="sf_admin_bar">
<?php include_partial('coche/filters', array('form' => $filters,
'configuration' => $configuration)) ?>
</div>
<div id="sf_admin_content">
<form action="<?php echo url_for('coche_coche_collection',
array('action' => 'batch')) ?>" method="post">
<?php include_partial('coche/list', array('pager' => $pager, 'sort' =>
$sort, 'helper' => $helper)) ?>
<ul class="sf_admin_actions">
<?php include_partial('coche/list_batch_actions', array('helper' =>
$helper)) ?>
<?php include_partial('coche/list_actions', array('helper' => $helper)) ?>
</ul>
</form>
</div>
<div id="sf_admin_footer">
<?php include_partial('coche/list_footer', array('pager' => $pager)) ?>
</div>
</div>
In the template there is this line:
include_partial('coche/filters', array('form' => $filters,
'configuration' => $configuration)) ?>
but i can not find the variables $this->filters and $this->configuration in the
index action.
How is that possible?
Javi
Is the index action extending a class? If yes, that's how!
It looks like a module generated by admin generator. If it's so, then these vars are set in autoCocheActions class which resides in project cache and is generated on the fly.

Resources