TYPO3:读取TCA'type'的值=> 'check'(位掩码)

时间:2018-05-24 10:29:08

标签: typo3 fluid extbase bitmask typo3-extensions

我需要在前端的活动中展示一系列日子:

在我的TCA中我设置了这样的字段:

'days' => [
    'exclude' => true,
    'label' => 'choose weekdays',
    'config' => [
        'type' => 'check',
        'eval' => 'required,unique',
        'items' => [
            ['monday',''],
            ['thuesday',''],
            ['wednesday',''],
            ['thursday',''],
            ['friday',''],
            ['saturday',''],
            ['sunday',''],
        ],
        'cols' => 'inline',
    ],
],

在数据库中存储一个整数,但现在我必须在前端的流体模板中显示所选日期。

这是关于TYPO3 documentation的参考资料,它解释了我应该检查值的0位...我已经搜索了很多但除了这个question之外找不到任何东西堆栈溢出,我无法工作。

3 个答案:

答案 0 :(得分:3)

我强烈建议不要使用check字段的位掩码功能。将这些值再次分开并且对于大多数开发人员而言更难以理解是很有必要的开销。

相反,您可以使用select字段,在这种情况下selectCheckBox可以为您提供服务。给定items的静态列表,您将获得一个包含所选值的CSV字符串,这些字符串更容易拆分,例如在Extbase域模型的getter方法中。如果它有意义,你甚至可以使用与记录的关系,而这种关系甚至更清晰但需要额外的工作。

如果您仍想继续使用位掩码,this answer可能对您有帮助。

答案 1 :(得分:2)

解决方案1:使用Mathias's解决方案与Dimitri L.

混合使用

我想在此处作为此特定问题的完整解决方案,请将其添加到域模型中:

/**
 * @var int
 */
protected $days;

然后关注所有日子:

/**
 * Get day 1
 *
 * @return int
 */
public function getDay1()
{
    return $this->days & 0b00000001 ? 1 : 0;
}

/**
 * Set day 1
 *
 * @param int $day1
 */
public function setDay1($day1) {
    if ($day1) {
        $this->days |= 0b00000001;
    } else {
        $this->days &= ~0b00000001;
    }
}

/**
 * And so on for the other 7 days
 */

您现在可以在extbase $object->getDay1()或流畅的{object.day1}

中使用它

正如Mathias所说,它很快变得非常复杂,我更喜欢这个解决方案,因为我只使用它来显示事件发生在一周内的日子,并且在日历中所以0或1解决方案就好了。

解决方案2:我最终直接在视图中使用数据库中的十进制位掩码值:(解决方案适用于所使用的复选框数量,在我的情况下为7个工作日)

use \TYPO3\CMS\Extbase\Utility\LocalizationUtility;

/**
 * News extension
 *
 * @package TYPO3
 * @subpackage tx_news
 */
class CoursedaysViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper
{
    /**
     * @param string $days (bitmask)
     * @return string checked weekdays seperated by /
     */
    public function render($days)
    {
        // render binary, 7 digits, split into array and reverse
        $days = decbin($days);
        $days = sprintf('%07d', $days);
        $days = str_split($days);
        $days = array_reverse($days);

        foreach($days as $day){
            $key = 'days.' . ++$a;
            if($day) $coursedays .= LocalizationUtility::translate($key, 'news_ext') . '/';
        }
        return  substr($coursedays, 0, -1);
    }
}

答案 2 :(得分:0)

通过评估位掩码来实现多个复选框的可能解决方案

程序员经常想将一些数据读入表单,然后将其输出为文本。这里有一些例子。

有时,程序员希望在具有多个复选框的同一表单中显示表单数据,以便用户可以更改数据。没有这样的例子,许多程序员发现很难一点一点地读取数据然后再次输出。

这是一个有效的示例(在BE和FE中): (已使用Typo3 9.5.20和10.4.9测试)

TCA 中,问题的示例:

'days' => [
    'exclude' => false,
    'label' => 'LLL:EXT:example/Resources/Private/Language/locallang_db.xlf:tx_example_domain_model_week.days',
    'config' => [
        'type' => 'check',
        'items' => [
            ['monday', ''],
            ['thuesday', ''],
            ['wednesday', ''],
            ['thursday', ''],
            ['friday', ''],
            ['saturday', ''],
            ['sunday', ''],
        ],
        'default' => 0,
    ]
],

模型

属性的类型必须为整数。 但是,getter和setter是数组,因为我们有多个复选框,并且使用数组来实现。 请记住这一点,这一点很重要,因为它会产生需要解决的问题。

class Week extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity
{
    /**
     * Days
     *
     * @var int
     */
    protected $days = 0;

    /**
     * Returns the days
     *
     * @return array $days
     */
    public function getDays()
    {
        return $this->days;
    }

    /**
     * Sets the days
     *
     * @param array $days
     * @return void
     */
    public function setDays($days)
    {
        $this->days = $days;
    }
}

控制器

在initializeCreateAction和initializeUpdateAction中,我们解决了整数和数组之间属性类型不同的问题。 否则,我们会收到一条错误消息,指出无法将数组转换为整数。 此代码意味着Extbase应该保留属性类型。

在createAction和updateAction中,我们分支到CheckboxUtility中的countBits方法,以添加所选复选框的值。 在editAction和updateAction中,我们将分支到CheckboxUtility中的convertDataForMultipleCheckboxes方法,以便将值转换为输入和输出。

/**
 * initializeCreateAction
 * @return void
 */
public function initializeCreateAction(): void
{
    if ($this->arguments->hasArgument('newWeek')) {
        $this->arguments->getArgument('newWeek')->getPropertyMappingConfiguration()->setTargetTypeForSubProperty('days', 'array');
    }
}

/**
 * action create
 *
 * @param Week $newWeek
 * @return void
 */
public function createAction(Week $newWeek)
{
    $days = (int)CheckboxUtility::countBits($newWeek->getDays());
    $newWeek->setDays($days);

    $this->weekRepository->add($newWeek);
    $this->redirect('list');
}

/**
 * action edit
 *
 * @param Week $week
 * @return void
 */
public function editAction(Week $week)
{
    $week->setDays(CheckboxUtility::convertDataForMultipleCheckboxes((int)$week->getDays()));
    $this->view->assign('week', $week);
}

/**
 * initializeUpdateAction
 * @return void
 */
public function initializeUpdateAction(): void
{
    if ($this->arguments->hasArgument('week')) {
        $this->arguments->getArgument('week')->getPropertyMappingConfiguration()->setTargetTypeForSubProperty('days', 'array');
    }
}

/**
 * action update
 *
 * @param Week $week
 * @return void
 */
public function updateAction(Week $week)
{
    $days = (int)CheckboxUtility::countBits($week->getDays());
    $week->setDays($days);

    $this->weekRepository->update($week);
    $this->redirect('list');
}

在“类/实用程序/CheckboxUtility.php”中

阅读代码。该过程在每个点都有描述。

在convertDataForMultipleCheckboxes方法中,基本方向如下: 我们在数据库中有一个整数值,例如109。 二进制表示法:1011011(64 + 32 + 0 + 8 + 4 + 0 + 1 = 109) 在表单中,这意味着已选中第一,第三,第四,第六和第七个复选框。

我们在1011011的七个循环中从左到右读取二进制值。 例如,让我们从左边读取第一个字符,然后用0覆盖右边的六个字符。这将产生二进制数1000000,十进制表示法= 64。 例如,让我们读取第四个字符(从左开始),然后用0覆盖右边的三个字符。这将产生二进制数1000,十进制表示法= 8。

阅读此内容后,由于从左到右阅读,因此将得到结果64 + 32 + 0 + 8 + 4 + 0 +1。 因此,我们最后将结果转过来,以便每个复选框都接收正确的值! 因此我们得到了1 + 0 + 4 + 8 + 0 + 32 + 64,因为选中了第一,第三,第四,第六和第七个复选框。

在方法countBits中,我们只将所有整数值加到一个数字上。

namespace Vendor\Example\Utility;
use TYPO3\CMS\Core\Utility\GeneralUtility;

class CheckboxUtility extends GeneralUtility
{
    /**
     * Convert an integer to binary and then convert each bit back to an integer for use with multiple checkboxes.
     *
     * @param int $value
     * @return array
     */
    public static function convertDataForMultipleCheckboxes(int $value): array
    {
        $bin = decbin($value); // convert dec to bin
        $num = strlen($bin); // counts the bits
        $res = array();

        for ($i = 0; $i < $num; $i++) {
            // loop through binary value
            if ($bin[$i] !== 0) {
                $bin_2 = str_pad($bin[$i], $num - $i, '0'); //pad string
                $res[] = bindec($bin_2); // convert that bit to dec and push in array
            }
        }

        return array_reverse($res); // reverse order and return
    }

    /**
     * Adds the values of the checkboxes
     *
     * @param array $value
     * @return int
     */
    public static function countBits(array $value): int
    {
        foreach ($value as $key => $item) {
            $res = $res + $item;
        }

        return $res;
    }
}

模板部分

此处的参数multiple =“ 1”很重要。这为属性天数组增加了一个附加维度。 (可以在网站的源代码中看到)。 重要的是,根据二进制符号为复选框提供正确的值。 当我们从数据库中读取值时,结果将以数组的形式提供给我们。因此,我们以与复选框的顺序相同的顺序在适当的位置(从0开始)读取附加维度。例如第七个值/复选框:checked =“ {week.days.6} == 64”

<f:form.checkbox
    id="day_1"
    property="days"
    value="1"
    multiple="1"
    checked="{week.days.0} == 1" />
<label for="day_1" class="form-control-label">
    <f:translate key="tx_example_domain_model_week.day1" />
</label>

<f:form.checkbox
    id="day_2"
    property="days"
    value="2"
    multiple="1"
    checked="{week.days.1} == 2" />
<label for="day_2" class="form-control-label">
    <f:translate key="tx_example_domain_model_week.day2" />
</label>

<f:form.checkbox
    id="day_3"
    property="days"
    value="4"
    multiple="1"
    checked="{week.days.2} == 4" />
<label for="day_3" class="form-control-label">
    <f:translate key="tx_example_domain_model_week.day3" />
</label>

<f:form.checkbox
    id="day_4"
    property="days"
    value="8"
    multiple="1"
    checked="{week.days.3} == 8" />
<label for="day_4" class="form-control-label">
    <f:translate key="tx_example_domain_model_week.day4" />
</label>

<f:form.checkbox
    id="day_5"
    property="days"
    value="16"
    multiple="1"
    checked="{week.days.4} == 16" />
<label for="day_5" class="form-control-label">
    <f:translate key="tx_example_domain_model_week.day5" />
</label>

<f:form.checkbox
    id="day_6"
    property="days"
    value="32"
    multiple="1"
    checked="{week.days.5} == 32" />
<label for="day_6" class="form-control-label">
    <f:translate key="tx_example_domain_model_week.day6" />
</label>

<f:form.checkbox
    id="day_7"
    property="days"
    value="64"
    multiple="1"
    checked="{week.days.6} == 64" />
<label for="day_7" class="form-control-label">
    <f:translate key="tx_example_domain_model_week.day7" />
</label>

...现在很高兴编写代码!