[TYPO3-mvc] Multiple Checkboxes for an object in a form
Christian Zenker
christian.zenker at 599media.de
Tue Nov 9 15:38:28 CET 2010
> I'm going to test it and then post my solution here if it works.
Ok, it seems to work now:
The Tx_CzDmRegister_Domain_Model_Address is the heart of the model. It
holds contact information of subscribers based on tt_address. It also has
an M-M-relation to the table sys_dmail_category (reperesented by
Tx_CzDmRegister_Domain_Model_MailCategory). This is a vital snippet in the
Tx_CzDmRegister_Domain_Model_Address
/**
* the property moduleSysDmailCategory
*
* @var
Tx_Extbase_Persistence_ObjectStorage<Tx_CzDmRegister_Domain_Model_MailCategory>
moduleSysDmailCategory
*/
protected $moduleSysDmailCategory;
/**
* getter for moduleSysDmailCategory
*
* @return
Tx_Extbase_Persistence_ObjectStorage<Tx_CzDmRegister_Domain_Model_MailCategory>
*/
public function getMailCategories() {
return $this->moduleSysDmailCategory;
}
/**
* setter for moduleSysDmailCategory
*
* @param
Tx_Extbase_Persistence_ObjectStorage<Tx_CzDmRegister_Domain_Model_MailCategory>
$moduleSysDmailCategory
* @return Tx_CzDmRegister_Domain_Model_Address
*/
public function setMailCategories($moduleSysDmailCategory) {
$this->moduleSysDmailCategory = $moduleSysDmailCategory;
return $this;
}
public function getMailCategoriesAsArray() {
$return = array();
if(!is_null($this->moduleSysDmailCategory)) {
foreach($this->moduleSysDmailCategory as $cat) {
$return[] = $cat->getUid();
}
}
return $return;
}
/**
* @param array $categories
*/
public function setMailCategoriesAsArray($categories) {
/**
* the ids of the currently selected categories
* @var array<integer>
*/
$current = array();
if(empty($this->moduleSysDmailCategory)) {
$this->moduleSysDmailCategory =
t3lib_div::makeInstance('Tx_Extbase_Persistence_ObjectStorage');
}
foreach($this->moduleSysDmailCategory as $cat) {
$current[] = $cat->getUid();
}
// clean the input data
foreach($categories as &$cat) {
$cat = intval($cat);
}
/**
* uids of records that need to be linked
* @var array<integer>
*/
$link = array_diff($categories, $current);
/**
* uids of records that need to be unlinked
* @var array<integer>
*/
$unlink = array_diff($current, $categories);
if($link) {
// if there are records that need to be linked
foreach(t3lib_div::makeInstance('Tx_CzDmRegister_Domain_Repository_MailCategoryRepository')->findByUids($link)
as $cat) {
$this->moduleSysDmailCategory->attach($cat);
}
}
if($unlink) {
// if there are records that need to be unlinked
/* we will first select all records to remove and then unlink them in a
batch
*
* this is done because unsetting objects while using the iterator
interface will
* usually skip some records
*/
$unlinkRecords = array();
foreach($this->moduleSysDmailCategory as $cat) {
if(in_array($cat->getUid(), $unlink)) {
$unlinkRecords[] = $cat;
}
}
foreach($unlinkRecords as $cat) {
$this->moduleSysDmailCategory->offsetUnset($cat);
}
}
}
/**
* just a dummy for the property mapper
* it seems the property mapper does not recognize a property even if a
setter exists
*
* @deprecated This is only needed for the property mapper and should
never be actually used
* @var array
*/
protected $mailCategoriesAsArray;
Note the ...AsArray() methods. They are used to work together with the
Form_CheckboxViewHelper. Franz, I guess this is basically what you have
done in your VH.
The template gets the Tx_CzDmRegister_Domain_Model_Address as 'address'
and a list of all available categories
(Tx_CzDmRegister_Domain_Model_MailCategory) as 'categories'.
The template looks like that:
<f:form name="address" method="post" controller="Address" action="create"
object="{address}">
<!-- the other stuff -->
<label for="categories">Categories</label>
<f:for each="{categories}" as="category">
<label for="category-{category.uid}">{category.category}</label>
<f:form.checkbox id="category-{category.uid}"
property="mailCategoriesAsArray" value="{category.uid}"/>
</f:for>
<!-- submit -->
</f:form>
and the createAction has just this signature:
public function createAction(Tx_CzDmRegister_Domain_Form_Address $address)
{
//...
}
And that's it.
Just never, *never*, NEVER(!!!) try to set the "checked" argument in the
Form_CheckboxViewHelper! It will cost you hours and drive you almost
insane. Believe me - I know what I am talking about. ;) For some reason
the VH is hardcoded to basically ignore the "property" argument if the
"checked" argument is set. I would call this a bug, but I guess there is a
reason why this was done...? Otherwise this works like a charm.
Christian.
More information about the TYPO3-project-typo3v4mvc
mailing list