Page Menu
Home
In-Portal Phabricator
Search
Configure Global Search
Log In
Files
F1069152
D529.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Jul 19, 11:55 AM
Size
9 KB
Mime Type
text/x-diff
Expires
Sun, Jul 20, 11:55 AM (2 m, 23 s ago)
Engine
blob
Format
Raw Data
Handle
692109
Attached To
D529: INP-1917 - Validate "kOptionsFormatter::Parse" method values
D529.diff
View Options
Index: core/install/english.lang
===================================================================
--- core/install/english.lang
+++ core/install/english.lang
@@ -308,6 +308,7 @@
<PHRASE Label="la_err_Primary_Lang_Required" Module="Core" Type="1">UHJpbWFyeSBMYW5nLiB2YWx1ZSBSZXF1aXJlZA==</PHRASE>
<PHRASE Label="la_err_required" Module="Core" Type="1">RmllbGQgaXMgcmVxdWlyZWQ=</PHRASE>
<PHRASE Label="la_err_unique" Module="Core" Type="1">RmllbGQgdmFsdWUgbXVzdCBiZSB1bmlxdWU=</PHRASE>
+ <PHRASE Label="la_err_unknown_option" Module="Core" Type="1">T3B0aW9uICJ7b3B0aW9ufSIgaXMgdW5rbm93bg==</PHRASE>
<PHRASE Label="la_err_value_out_of_range" Module="Core" Type="1">RmllbGQgdmFsdWUgaXMgb3V0IG9mIHJhbmdlLCBwb3NzaWJsZSB2YWx1ZXMgZnJvbSB7bWluX3ZhbHVlfSB0byB7bWF4X3ZhbHVlfQ==</PHRASE>
<PHRASE Label="la_exportfoldernotwritable" Module="Core" Type="1">RXhwb3J0IGZvbGRlciBpcyBub3Qgd3JpdGFibGU=</PHRASE>
<PHRASE Label="la_fck_ErrorCreatingFolder" Module="Core" Type="1">RXJyb3IgY3JlYXRpbmcgZm9sZGVyLiBFcnJvciBudW1iZXI6</PHRASE>
Index: core/kernel/db/cat_event_handler.php
===================================================================
--- core/kernel/db/cat_event_handler.php
+++ core/kernel/db/cat_event_handler.php
@@ -2909,9 +2909,11 @@
/** @var CategoryHelper $category_helper */
$category_helper = $this->Application->recallObject('CategoryHelper');
+ /** @var array $virtual_fields */
$virtual_fields = $this->Application->getUnitOption($event->Prefix, 'VirtualFields');
- $virtual_fields['CategoryId']['default'] = (int)$this->Application->GetVar('m_cat_id');
+ $category_id = $this->Application->GetVar('m_cat_id');
+ $virtual_fields['CategoryId']['default'] = $category_id > 0 ? (int)$category_id : null;
$virtual_fields['CategoryId']['options'] = $category_helper->getStructureTreeAsOptions();
$this->Application->setUnitOption($event->Prefix, 'VirtualFields', $virtual_fields);
Index: core/kernel/utility/formatters/options_formatter.php
===================================================================
--- core/kernel/utility/formatters/options_formatter.php
+++ core/kernel/utility/formatters/options_formatter.php
@@ -98,35 +98,77 @@
}
/**
- * Performs basic type validation on form field value
- *
- * @param mixed $value
- * @param string $field_name
- * @param kDBItem $object
- * @return mixed
- * @access public
+ * @inheritDoc
*/
public function Parse($value, $field_name, &$object)
{
if ( $value == '' ) {
- return NULL;
+ return null;
}
- $found = $option_key = false;
+ $patched_value = $value;
$options = $object->GetFieldOptions($field_name);
$use_phrases = getArrayValue($options, 'use_phrases');
- foreach ($options['options'] as $option_key => $option_value) {
+ // Support for "value 1, value 2, ..." notation.
+ if ( strpos($patched_value, ',') !== false ) {
+ $patched_value = '|' . preg_replace('/(\s+)?,(\s+)?/', '|', $patched_value) . '|';
+ }
+
+ // Support for "|value 1|value 2|..." notation.
+ if ( strpos($patched_value, '|') !== false ) {
+ // Multiple checkboxes OR multiselect.
+ $parsed_values = array();
+
+ foreach ( explode('|', substr($patched_value, 1, -1)) as $raw_option ) {
+ $parsed_value = $this->parseOption($raw_option, $options, $use_phrases);
+
+ if ( $parsed_value !== '' ) {
+ $parsed_values[] = $parsed_value;
+ continue;
+ }
+
+ $object->SetError($field_name, 'unknown_option', null, array('option' => $raw_option));
+
+ return $value;
+ }
+
+ return '|' . implode('|', $parsed_values) . '|';
+ }
+
+ $parsed_value = $this->parseOption($value, $options, $use_phrases);
+
+ if ( $parsed_value !== '' ) {
+ return $parsed_value;
+ }
+
+ $object->SetError($field_name, 'unknown_option', null, array('option' => $value));
+
+ return $value;
+ }
+
+ /**
+ * Converts an "option title" into an "option key".
+ *
+ * @param string $value Value.
+ * @param array $options Options.
+ * @param boolean $use_phrases Use phrases.
+ *
+ * @return integer|string
+ */
+ protected function parseOption($value, array $options, $use_phrases = true)
+ {
+ foreach ( $options['options'] as $option_key => $option_value ) {
if ( $use_phrases ) {
$option_value = $this->Application->Phrase($option_value);
}
if ( "$option_value" === "$value" ) {
- $found = true;
- break;
+ return $option_key;
}
}
- return $found ? $option_key : $value;
+ return array_key_exists($value, $options['options']) ? $value : '';
}
+
}
Index: core/kernel/utility/validator.php
===================================================================
--- core/kernel/utility/validator.php
+++ core/kernel/utility/validator.php
@@ -60,6 +60,7 @@
'invalid_format' => '!la_err_invalid_format!', // Incorrect data format, please use %s
'bad_date_format' => '!la_err_bad_date_format!', // Incorrect date format, please use (%s) ex. (%s)
'primary_lang_required' => '!la_err_primary_lang_required!', // Primary Lang. value Required
+ 'unknown_option' => '!la_err_unknown_option!', // Option "{option}" is unknown
);
/**
Index: core/tests/Unit/kernel/utility/formatters/kOptionsFormatterTest.php
===================================================================
--- /dev/null
+++ core/tests/Unit/kernel/utility/formatters/kOptionsFormatterTest.php
@@ -0,0 +1,135 @@
+<?php
+
+
+class kOptionsFormatterTest extends AbstractTestCase
+{
+
+ /**
+ * Fixture of the kDBItem class.
+ *
+ * @var kDBItem
+ */
+ protected $dbItemFixture;
+
+ /**
+ * @before
+ */
+ protected function setUpTest()
+ {
+ $db_item = new kDBItem();
+ $db_item->Init('stop-word', ''); // Existing unit used for the "ValidatorClass" unit config option to work.
+ $db_item->SetFieldOptions(
+ 'SampleField',
+ array(
+ 'options' => array(1 => 'la_ADP', 2 => 'la_AED', 3 => 'la_AFA', 4 => 'la_ALL'),
+ )
+ );
+
+ $this->dbItemFixture = $db_item;
+ }
+
+ public function testParseEmptyValue()
+ {
+ $option_formatter = new kOptionsFormatter();
+ $actual = $option_formatter->Parse('', 'SampleField', $this->dbItemFixture);
+
+ $this->assertEmpty($this->dbItemFixture->GetErrorPseudo('SampleField'), 'No validation errors');
+ $this->assertNull($actual);
+ }
+
+ /**
+ * @dataProvider usePhrasesDataProvider
+ */
+ public function testParseKnownOptionByValue($use_phrases)
+ {
+ $option_formatter = new kOptionsFormatter();
+ $this->dbItemFixture->SetFieldOption('SampleField', 'use_phrases', $use_phrases);
+
+ $option_title = $use_phrases ? 'UAE Dirham' : 'la_AED';
+ $actual = $option_formatter->Parse($option_title, 'SampleField', $this->dbItemFixture);
+
+ $this->assertEmpty($this->dbItemFixture->GetErrorPseudo('SampleField'), 'No validation errors');
+ $this->assertSame(2, $actual);
+ }
+
+ public function testParseKnownOptionByKey()
+ {
+ $option_formatter = new kOptionsFormatter();
+ $actual = $option_formatter->Parse(2, 'SampleField', $this->dbItemFixture);
+
+ $this->assertEmpty($this->dbItemFixture->GetErrorPseudo('SampleField'), 'No validation errors');
+ $this->assertSame(2, $actual);
+ }
+
+ public function testParseUnknownOption()
+ {
+ $option_formatter = new kOptionsFormatter();
+ $option_title_in = 'option5';
+ $actual = $option_formatter->Parse($option_title_in, 'SampleField', $this->dbItemFixture);
+
+ $this->assertEquals('unknown_option', $this->dbItemFixture->GetErrorPseudo('SampleField'));
+ $this->assertEquals('Option "option5" is unknown', $this->dbItemFixture->GetErrorMsg('SampleField'));
+ $this->assertSame($option_title_in, $actual, 'Given value returned as-as');
+ }
+
+ /**
+ * @dataProvider usePhrasesDataProvider
+ */
+ public function testParseKnownOptionsByKey($use_phrases)
+ {
+ $option_formatter = new kOptionsFormatter();
+ $this->dbItemFixture->SetFieldOption('SampleField', 'use_phrases', $use_phrases);
+
+ $option_titles = $use_phrases ? '|Leck|UAE Dirham|' : '|la_ALL|la_AED|';
+ $actual = $option_formatter->Parse($option_titles, 'SampleField', $this->dbItemFixture);
+
+ $this->assertEmpty($this->dbItemFixture->GetErrorPseudo('SampleField'), 'No validation errors');
+ $this->assertSame('|4|2|', $actual);
+ }
+
+ public function testParseUnknownOptions()
+ {
+ $option_formatter = new kOptionsFormatter();
+ $option_titles_in = '|la_ALL|missing|la_AED|missing 2|';
+ $actual = $option_formatter->Parse($option_titles_in, 'SampleField', $this->dbItemFixture);
+
+ $this->assertSame('unknown_option', $this->dbItemFixture->GetErrorPseudo('SampleField'));
+ $this->assertSame('Option "missing" is unknown', $this->dbItemFixture->GetErrorMsg('SampleField'));
+ $this->assertSame($option_titles_in, $actual, 'Given value returned as-as');
+ }
+
+ /**
+ * @dataProvider usePhrasesDataProvider
+ */
+ public function testParseKnownOptionsByKeyWithCommaSeparator($use_phrases)
+ {
+ $option_formatter = new kOptionsFormatter();
+ $this->dbItemFixture->SetFieldOption('SampleField', 'use_phrases', $use_phrases);
+
+ $option_titles = $use_phrases ? 'Leck, UAE Dirham' : 'la_ALL, la_AED';
+ $actual = $option_formatter->Parse($option_titles, 'SampleField', $this->dbItemFixture);
+
+ $this->assertEmpty($this->dbItemFixture->GetErrorPseudo('SampleField'), 'No validation errors');
+ $this->assertSame('|4|2|', $actual);
+ }
+
+ public function testParseUnknownOptionsWithCommaSeparator()
+ {
+ $option_formatter = new kOptionsFormatter();
+ $option_titles_in = 'la_ALL, missing, la_AED, missing 2';
+ $actual = $option_formatter->Parse($option_titles_in, 'SampleField', $this->dbItemFixture);
+
+ $this->assertSame('unknown_option', $this->dbItemFixture->GetErrorPseudo('SampleField'));
+ $this->assertSame('Option "missing" is unknown', $this->dbItemFixture->GetErrorMsg('SampleField'));
+ $this->assertSame($option_titles_in, $actual, 'Given value returned as-as');
+ }
+
+ public static function usePhrasesDataProvider()
+ {
+ return array(
+ 'not using phrases' => array(false),
+ 'using phrases' => array(true),
+ );
+ }
+
+}
Event Timeline
Log In to Comment