Open hannesbochmann opened 6 years ago
Here is a short wrap up what I did to support the categories:
Add custom model with the following TS:
config.tx_extbase{
objects {
AFM\Registeraddress\Domain\Model\Address.className = DMK\Myext\Domain\Model\Address
}
persistence{
classes{
DMK\Myext\Domain\Model\Address {
mapping {
tableName = tt_address
recordType = Tx_Registeraddress_Address
columns {
module_sys_dmail_category.mapOnProperty = moduleSysDmailCategory
}
}
}
DMK\Myext\Domain\Model\NewsletterCategory {
mapping {
tableName = sys_dmail_category
}
}
}
}
}
The model looks like this:
class Address extends \AFM\Registeraddress\Domain\Model\Address
{
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\DMK\Myext\Domain\Model\NewsletterCategory>
*/
protected $moduleSysDmailCategory;
/**
* __construct
*/
public function __construct()
{
$this->initStorageObjects();
}
/**
* @return void
*/
protected function initStorageObjects()
{
$this->moduleSysDmailCategory = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* @param \DMK\Myext\Domain\Model\NewsletterCategory $moduleSysDmailCategory
* @return void
*/
public function addModuleSysDmailCategory(\DMK\Myext\Domain\Model\NewsletterCategory $moduleSysDmailCategory)
{
$this->moduleSysDmailCategory->attach($moduleSysDmailCategory);
}
/**
* @param \DMK\Myext\Domain\Model\NewsletterCategory $moduleSysDmailCategory The Category to be removed
* @return void
*/
public function removeModuleSysDmailCategory(\DMK\Myext\Domain\Model\NewsletterCategory $moduleSysDmailCategory)
{
$this->moduleSysDmailCategory->detach($moduleSysDmailCategory);
}
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\DMK\Myext\Domain\Model\NewsletterCategory> $moduleSysDmailCategory
*/
public function getModuleSysDmailCategory()
{
return $this->moduleSysDmailCategory;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\DMK\Myext\Domain\Model\NewsletterCategory> $moduleSysDmailCategory
* @return void
*/
public function setModuleSysDmailCategory(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $moduleSysDmailCategory)
{
$this->moduleSysDmailCategory = $moduleSysDmailCategory;
}
}
The category model is just an empty wrapper:
class NewsletterCategory extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
}
So far so good, now I added a ViewHelper to return raw database records for the categories for the view. In this ViewHelper I just return all categories from a given pid. I think there needs to be a more generic solution.
Additionally I needed a ViewHelper to determine if a category is selected:
class IsCategorySelectedViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper
{
/**
* @param int $categoryUid
*
* @return array
*/
public function render($categoryUid)
{
$request = $this->controllerContext->getRequest()->getOriginalRequest();
// if form is not submitted the default is checked
if (!$request) {
$checked = true;
} else {
$checked = in_array($categoryUid, $request->getArgument('newAddress')['moduleSysDmailCategory']);
}
return $checked;
}
}
Here's a template snippet for the field:
<f:alias map="{categories: '{mk:newsletter.getCategories()}'}">
<f:if condition="{categories}">
<f:if condition="{categories -> f:count()} == 1">
<f:then>
<f:comment>
We can't use the property attribute as we need the parameter to be
multiple (ending with []) in every case. This is not possible with the normal
hidden field. That's why we set the name by ourselves.
</f:comment>
<f:form.hidden name="newAddress[moduleSysDmailCategory][]" value="{categories.0.uid}" />
</f:then>
<f:else>
<fieldset class="checkboxes">
<f:for each="{categories}" as="category">
<f:form.checkbox
checked="{mk:newsletter.isCategorySelected(categoryUid: '{category.uid}')}"
id="option-{category.uid}"
property="moduleSysDmailCategory"
multiple="1"
value="{category.uid}"
/>
<label for="option-{category.uid}">{category.category}</label>
</f:for>
</fieldset>
</f:else>
</f:if>
</f:if>
</f:alias>
The last step was to validate that categories were selected. I added the corresponding validation into the createAction method of the controller with something like this: @validate $newAddress \DMK\Myext\Validation\Validator\AddressValidator. The validator looks like this:
class AddressValidator extends \TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator
{
/**
* Object Manager
*
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
* @inject
*/
protected $objectManager;
/**
* Is valid
*
* @param \DMK\Mkwsw\Domain\Model\Address $address
*
* @return bool
*/
public function isValid($address)
{
$isValid = true;
if ($address->getModuleSysDmailCategory()->count() == 0) {
$error = $this->objectManager->get(
'TYPO3\CMS\Extbase\Validation\Error',
'No newsletter category selected',
'no_newsletter_category_selected'
);
$this->result->forProperty('moduleSysDmailCategory')->addError($error);
$isValid = false;
}
return $isValid;
}
}
The error message can be set with TS in the path plugin.tx_registeraddress._LOCAL_LANG.default.error.no_newsletter_category_selected.newAddress.moduleSysDmailCategory
Thought I share that in case anybody needs it.
Hi there! First of all, thank you for this huge submission!
I'm trying to get this feature working now, too - It seems that you ommitted the "getCategories"-Viewhelper? (it gets called right in the first line of the template)
I left it out because we use the rn_base extension to access the database which might not be suitable for most users. But anyway here it is so you can adapt the ViewHelper to use core methods or whatever you like. Getting the categories by pid might not be necessary, depends on your requirements:
class GetCategoriesViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper
{
/**
* @return array
*/
public function render()
{
$settings = $this->renderingContext->getVariableProvider()->get('settings');
return \Tx_Rnbase_Database_Connection::getInstance()->doSelect(
'*',
'sys_dmail_category',
array('where' => 'pid = ' . intval($settings['categoriesStoragePid']))
);
}
}
Whoa! Thank you very much for your fast reply!
I'm almost done building the complete extension infrastructure for this feature - I will post it here when I'm done.
Thank you for the Code, Hannes! Where exactly did you put the @validate $newAddress (...)\Validation\Validator\AddressValidator ?
(BTW: don't forget the namespaces! )
Extension for directmail categories: https://github.com/opaque01/registeraddress_categories
Thanks. But there's no validation of the categories either.
The validation is done in the controller. You need to provide an own controller:
config.tx_extbase{
objects {
AFM\Registeraddress\Controller\AddressController.className = DMK\Myext\Controller\AddressController
}
}
And the controller:
class AddressController extends \AFM\Registeraddress\Controller\AddressController
{
/**
* we check additionally that at least one category was choosen
*
* @param \AFM\Registeraddress\Domain\Model\Address $newAddress
* @validate $newAddress \DMK\Myext\Validation\Validator\AddressValidator
*
* @return void
*/
public function createAction(\AFM\Registeraddress\Domain\Model\Address $newAddress)
{
parent::createAction($newAddress);
}
}
Thanks! I finally it works! Though I had to change the ViewHelper to
// if form is not submitted the default is unchecked
$checked = false;
if ($request) {
if (is_array($request->getArgument('newAddress')['moduleSysDmailCategory'])) {
$checked = in_array($categoryUid, $request->getArgument('newAddress')['moduleSysDmailCategory']);
} else {
array_push( $formCategories, $request->getArgument('newAddress')['moduleSysDmailCategory'] );
$checked = in_array($categoryUid, $formCategories);
}
}
(Hopefully) the last question: Do you know the error id? I tried
<trans-unit id="error.1221560718.newAddress.moduleSysDmailCategory" xml:space="preserve">
<source>Please choose at least one category.</source>
</trans-unit>
but the number doesn't seem to be the right one. Sorry, but I don't know where to find it...
@Meggie-K Can you add it to this extension? https://github.com/opaque01/registeraddress_categories
I'm not sure if it works with your extension (I wrote my own - which is more based on your code above and not exactly the same as registeraddress_categories). I had to change it because I worked in a VM without realurl - so the request was always set (id= 123).
The label for the error when no category is selected should be error.no_newsletter_category_selected.newAddress.moduleSysDmailCategory
Thank you! Just noticed that you already mentioned that at the end of your first post in November... Sorry!
FYI: if you want to highlight the checkboxes when no category is selected, add <span class="checkmark"></span>
after each checkbox label and insert following CSS:
.f3-form-error ~ .checkmark { position: absolute; left: 11px; height: 21px; width: 21px; border: 1px solid #FF0000; border-radius: 0.25em; }
Is it possible to give the user a selection of directmail categories in the subscription form? As far as I understand I would to need configure a subclass for the domain model in the persistence section of the TypoScript configuration to be able to save the field module_sys_dmail_category. Furthermore I would need a ViewHelper to provide the categories for the selection in the template. Or do you see a better way?