TYPO3:读取 TCA 的值 'type' => 'check'(位掩码)
TYPO3: Reading the values of a TCA 'type' => 'check' (bitmask)
我需要在前端显示事件中选择的日期:
在我的 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 which explains that I should check the bit-0 of values ... I've searched a lot but couldn't find anything except this 此处关于堆栈溢出的参考,我无法开始工作。
我强烈建议不要使用 check
字段的位掩码功能。再次拆分这些值几乎不值得,而且对于大多数开发人员来说也更难理解。
相反,您可以使用 select
字段,在这种情况下 selectCheckBox
应该很适合您。给定 items
的静态列表,您将获得一个包含所选值的 CSV 字符串,这更容易拆分,例如在 Extbase 域模型的 getter 方法中。如果有意义,您甚至可以使用与记录的关系来代替,这更清晰,但需要额外的工作。
如果您仍想继续使用位掩码 可能会对您有所帮助。
解决方案 1: 使用 solution mixed with the one of
我想在这里给出它作为这个特定问题的完整解决方案,所以在域模型中添加它:
/**
* @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()
或 fluid {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);
}
}
通过评估位掩码对多个复选框的可能解决方案
程序员经常希望将一些数据读取到表单中,然后将其输出为文本。这里有几个例子。
有时程序员希望在具有多个复选框的同一表单中显示表单数据,以便用户可以更改数据。没有这方面的例子,很多程序员发现很难逐位读取数据,然后再输出。
这是一个工作示例(在 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;
}
}
在 Templates 或 Partials
参数 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>
...现在编码愉快!
我需要在前端显示事件中选择的日期:
在我的 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 which explains that I should check the bit-0 of values ... I've searched a lot but couldn't find anything except this
我强烈建议不要使用 check
字段的位掩码功能。再次拆分这些值几乎不值得,而且对于大多数开发人员来说也更难理解。
相反,您可以使用 select
字段,在这种情况下 selectCheckBox
应该很适合您。给定 items
的静态列表,您将获得一个包含所选值的 CSV 字符串,这更容易拆分,例如在 Extbase 域模型的 getter 方法中。如果有意义,您甚至可以使用与记录的关系来代替,这更清晰,但需要额外的工作。
如果您仍想继续使用位掩码
解决方案 1: 使用
我想在这里给出它作为这个特定问题的完整解决方案,所以在域模型中添加它:
/**
* @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()
或 fluid {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);
}
}
通过评估位掩码对多个复选框的可能解决方案
程序员经常希望将一些数据读取到表单中,然后将其输出为文本。这里有几个例子。
有时程序员希望在具有多个复选框的同一表单中显示表单数据,以便用户可以更改数据。没有这方面的例子,很多程序员发现很难逐位读取数据,然后再输出。
这是一个工作示例(在 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;
}
}
在 Templates 或 Partials
参数 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>
...现在编码愉快!