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
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...
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.
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; ?>
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
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.