【问题标题】:TYPO3: Reading the values of a TCA 'type' => 'check' (bitmask)TYPO3:读取 TCA 'type' => 'check'(位掩码)的值
【发布时间】:2018-05-24 10:29:07
【问题描述】:

我需要在前端的事件中显示选择的日期:

在我的 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 堆栈溢出之外找不到任何东西,我不能去上班。

【问题讨论】:

    标签: typo3 fluid extbase bitmask typo3-extensions


    【解决方案1】:

    我强烈建议不要使用check 字段的位掩码功能。将值再次分开很少值得开销,而且对于大多数开发人员来说也更难理解。

    您可以改为使用select 字段,在这种情况下selectCheckBox 应该可以很好地为您服务。给定items 的静态列表,您将获得一个带有所选值的 CSV 字符串,该字符串更容易拆分,例如在 Extbase 域模型的 getter 方法中。如果有意义的话,您甚至可以使用与记录的关系来代替,这样更简洁,但需要额外的工作。

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

    【讨论】:

    • 感谢您的建议,这可能是一个明智的建议,但我仍然对这个问题的答案感兴趣,这一定是可能的!
    • 我添加了一个链接,指向我的旧答案,该答案解决了这个问题。
    • 谢谢,我确实在此期间找到了您的答案,并且该答案确实为我提供了我正在寻找的解决方案,谢谢...
    【解决方案2】:

    解决方案 1: 使用与Dimitri L. 之一混合的Mathias's 解决方案

    我想在这里给出这个特定问题的完整解决方案,所以在域模型中添加这个:

    /**
     * @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: 我最终在 viewhelper 中直接使用数据库中的十进制位掩码值:(解决方案适用于所使用的复选框数量,在我的情况下是 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);
        }
    }
    

    【讨论】:

      【解决方案3】:

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

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

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

      这是一个工作示例(在 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');
      }
      

      在 Classes/Utility/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>
      

      ...现在快乐编码!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多