diff --git a/api/js/etemplate/et2_widget_entry.js b/api/js/etemplate/et2_widget_entry.js
index 8f5545e71d..d486efda46 100644
--- a/api/js/etemplate/et2_widget_entry.js
+++ b/api/js/etemplate/et2_widget_entry.js
@@ -138,7 +138,12 @@ var et2_entry = (function(){ "use strict"; return et2_valueWidget.extend(
// If value was set, find the record explicitly.
if(typeof this.options.value == 'string')
{
- widget.options.value = this.getRoot().getArrayMgr('content').getEntry(this.prefix+this.options.value + '['+this.options.field+']');
+ widget.options.value = this.getArrayMgr('content').getEntry(this.id+'['+this.options.field+']') ||
+ this.getRoot().getArrayMgr('content').getEntry(this.prefix+this.options.value + '['+this.options.field+']');
+ }
+ else if (this.options.field && this.options.value && this.options.value[this.options.field])
+ {
+ widget.options.value = this.options.value[this.options.field];
}
if(this.options.compare)
{
diff --git a/api/src/Etemplate.php b/api/src/Etemplate.php
index 83c301f8a7..9a519608a6 100644
--- a/api/src/Etemplate.php
+++ b/api/src/Etemplate.php
@@ -531,6 +531,7 @@ class Etemplate extends Etemplate\Widget\Template
public static function reset_request()
{
self::$request = Etemplate\Request::read();
+ self::$cache = array();
}
/**
* Get template data as array
diff --git a/api/src/Etemplate/Widget/Entry.php b/api/src/Etemplate/Widget/Entry.php
index 1bac26f21a..b8b92d839c 100644
--- a/api/src/Etemplate/Widget/Entry.php
+++ b/api/src/Etemplate/Widget/Entry.php
@@ -70,7 +70,8 @@ abstract class Entry extends Transformer
$attrs['id'] = $this->id;
$form_name = self::form_name($cname, $this->id);
- $data_id = $attrs['value'] ? self::form_name($cname, $attrs['value']) : self::form_name($cname, self::ID_PREFIX . $this->id);
+ $prefixed_id = (substr($this->id, 0, 1) == self::ID_PREFIX ? $this->id : self::ID_PREFIX . $this->id);
+ $data_id = $attrs['value'] ? self::form_name($cname, $attrs['value']) : self::form_name($cname, $prefixed_id);
// No need to proceed
if(!$data_id) return;
@@ -94,8 +95,8 @@ abstract class Entry extends Transformer
}
// Set the new value so transformer can find it. Use prefix to avoid changing the original value
- $new_value =& self::get_array(self::$request->content, self::ID_PREFIX .$this->id, true, false);
- if (true) $new_value = $data;
+ $new_value =& self::get_array(self::$request->content, $prefixed_id, true, false);
+ if ($data) $new_value = $data;
// Check for missing field
if(!$attrs['field'] && !$attrs['alternate_fields'])
@@ -109,10 +110,15 @@ abstract class Entry extends Transformer
$this->regex($attrs, $new_value);
+ // Change this before parent so client gets what it needs
+ // Client is expecting to find data with the prefix
+ if(substr($this->id, 0, 1) !== self::ID_PREFIX)
+ {
+ $this->id = self::ID_PREFIX . $this->id . "[{$attrs['field']}]";
+ }
+
parent::beforeSendToClient($cname, $expand);
- // Change this after parent::beforeSendToClient or it adds another layer
- $this->id = self::ID_PREFIX . $this->id . "[{$attrs['field']}]";
}
@@ -173,7 +179,8 @@ abstract class Entry extends Transformer
protected function customfield($attrs, &$data)
{
list($app, $type) = explode('-',$attrs['type']);
- $id = is_array($data) ? static::get_array($data, $this->id) : $data;
+ $data_id = $attrs['value'] ?: $attrs['id'];
+ $id = is_array($data) ? static::get_array($data, $data_id) : $data;
if(!$app || !$type || !$GLOBALS['egw_info']['apps'][$app] || !$id ||
// Simple CF, already there
$data[$attrs['field']]
@@ -207,9 +214,10 @@ abstract class Entry extends Transformer
*/
protected function regex($attrs, &$data)
{
- $id = is_array($data) ? static::get_array($data, $this->id) : $data;
+ $data_id = $attrs['value'] ?: $attrs['id'];
+ $id = is_array($data) ? static::get_array($data, $data_id) : $data;
$value =& $this->get_data_field($attrs, $data);
- if(!$attrs['regex'] || !$id || !$value)
+ if(!$attrs['regex'] || !$value)
{
return;
}
@@ -221,6 +229,6 @@ abstract class Entry extends Transformer
$replace = array_pop($regex);
$regex = implode(',', $regex);
}
- $value = preg_replace($regex, $replace, $value);
+ $data[$attrs['field']] = preg_replace($regex, $replace, $value);
}
}
\ No newline at end of file
diff --git a/api/templates/test/entry_test.xet b/api/templates/test/entry_test.xet
new file mode 100644
index 0000000000..c52bf96db3
--- /dev/null
+++ b/api/templates/test/entry_test.xet
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api/templates/test/entry_test_contact.xet b/api/templates/test/entry_test_contact.xet
new file mode 100644
index 0000000000..d4967324cb
--- /dev/null
+++ b/api/templates/test/entry_test_contact.xet
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api/tests/Etemplate/Widget/ContactEntryTest.php b/api/tests/Etemplate/Widget/ContactEntryTest.php
new file mode 100644
index 0000000000..db65bb3f79
--- /dev/null
+++ b/api/tests/Etemplate/Widget/ContactEntryTest.php
@@ -0,0 +1,139 @@
+elements as $id)
+ {
+ list($app, $id) = explode(':',$id);
+
+ $bo_class = "{$app}_bo";
+ $bo = new $bo_class();
+ $bo->delete($id, true, false, true);
+ }
+
+ parent::tearDown();
+
+ }
+
+ /**
+ * Test that the correct value is extracted, based on the value attribute,
+ * or if it is missing try the ID. This goes to contact, rather than
+ * abstract test class.
+ */
+ public function testContact()
+ {
+ // Create a test contact
+ $test_contact = $this->make_contact();
+
+ // Instanciate the template
+ $etemplate = new Etemplate();
+ $etemplate->read(static::TEST_TEMPLATE, 'test');
+
+ // Content - IDs are important, they should match valid contacts
+ $content = array(
+ 'entry_id' => $GLOBALS['egw_info']['user']['person_id'],
+ 'info_contact' => $test_contact
+ );
+
+ $result = $this->mockedExec($etemplate, $content);
+ $data = array();
+ foreach($result as $response)
+ {
+ if($response['type'] == 'et2_load')
+ {
+ $data = $response['data']['data'];
+ break;
+ }
+ }
+
+ // Check that the entry was found
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'widget']);
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'entry_id']);
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'info_contact_email']);
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'info_contact']);
+ $this->assertEmpty($data['content'][Entry::ID_PREFIX.'no_value']);
+
+ // Check that the value is present - exact value is pulled client side
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'widget']['email']);
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'entry_id']['n_fn']);
+
+ $this->assertEquals($GLOBALS['egw_info']['user']['account_email'], $data['content'][Entry::ID_PREFIX.'entry_id']['email']);
+ $this->assertEquals($GLOBALS['egw_info']['user']['account_fullname'], $data['content'][Entry::ID_PREFIX.'entry_id']['n_fn']);
+
+ // Values are to be done as labels
+ $this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'widget[email]']['type'], 'Unexpected widget type');
+ $this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'entry_id[n_fn]']['type'], 'Unexpected widget type');
+ $this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'info_contact_email[email]']['type'], 'Unexpected widget type');
+ $this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'info_contact[email]']['type'], 'Unexpected widget type');
+ $this->assertEquals('label', $data['modifications'][Entry::ID_PREFIX.'no_value[email]']['type'], 'Unexpected widget type');
+
+ // No errors
+ $this->assertEmpty($data['validation_errors']);
+ }
+
+ /**
+ * Make a contact so we can test
+ */
+ protected function make_contact()
+ {
+ $bo = new \addressbook_bo();
+ $element = array(
+ 'n_fn' => "Mr Test Guy",
+ 'n_family' => 'Guy',
+ 'n_fileas' => 'Test Organisation: Guy, Test',
+ 'n_given' => 'Test',
+ 'n_prefix' => 'Mr',
+ 'org_name' => 'Test Organisation',
+ 'tel_cell' => '555-4321',
+ 'tel_home' => '66 12 34 56',
+ 'bday' => "1995-07-28T10:52:54Z"
+ );
+ $element_id = $bo->save($element, true, true, true, true);
+ $this->elements[] = 'addressbook:'.$element_id;
+ return $element_id;
+ }
+}
+
+/**
+ * Testable entry widget
+ */
+class EntryTestWidget extends \EGroupware\Api\Etemplate\Widget\Entry
+{
+ public function get_entry($value, array $attrs)
+ {
+ $entry = EntryTest::getEntry($value, $attrs);
+
+ return $entry;
+ }
+}
\ No newline at end of file
diff --git a/api/tests/Etemplate/Widget/EntryTest.php b/api/tests/Etemplate/Widget/EntryTest.php
new file mode 100644
index 0000000000..3d8bcddc7f
--- /dev/null
+++ b/api/tests/Etemplate/Widget/EntryTest.php
@@ -0,0 +1,138 @@
+ 7,
+ 'entry_field_1' => 'Field 1',
+ 'entry_field_2' => 'Field 2',
+ 'entry_field_3' => 'Field 3',
+ 'entry_num_1' => 1,
+ 'entry_num_2' => 2,
+ 'entry_num_3' => 3,
+ 'entry_date' => '2018-11-12'
+ );
+ return $entry[$value];
+ }
+ /**
+ * Test that the correct value is extracted, based on the value attribute,
+ * or if it is missing try the ID
+ */
+ public function testValueAttr()
+ {
+ // Instanciate the template
+ $etemplate = new Etemplate();
+ $etemplate->read(static::TEST_TEMPLATE, 'test');
+
+ // Content - entry ID is important, it should match what getEntry() gives
+ $content = array(
+ 'entry_id' => '7',
+ 'not_entry_id' => '123'
+ );
+
+ $result = $this->mockedExec($etemplate, $content);
+ $data = array();
+ foreach($result as $response)
+ {
+ if($response['type'] == 'et2_load')
+ {
+ $data = $response['data']['data'];
+ break;
+ }
+ }
+
+ // Check that the entry was found
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'widget']);
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'entry_id']);
+
+ // Check that the entry was not found
+ $this->assertEmpty($data['content'][Entry::ID_PREFIX.'no_value']);
+
+ // Check that the value is present - exact value is pulled client side
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'widget']['entry_field_1']);
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'entry_id']['entry_field_2']);
+
+ // No errors
+ $this->assertEmpty($data['validation_errors']);
+ }
+
+ /**
+ * Check on compare attribute.
+ * Actual comparison is done client side, but here we check that the value is found.
+ */
+ public function testCompareAttr()
+ {
+ // Instanciate the template
+ $etemplate = new Etemplate();
+ $etemplate->read(static::TEST_TEMPLATE, 'test');
+
+ // Content - entry ID is important, it should match what getEntry() gives
+ $content = array(
+ 'entry_id' => '7',
+ );
+
+ $result = $this->mockedExec($etemplate, $content);
+ $data = array();
+ foreach($result as $response)
+ {
+ if($response['type'] == 'et2_load')
+ {
+ $data = $response['data']['data'];
+ break;
+ }
+ }
+
+ // Check that the value is present - exact value is pulled client side
+ $this->assertNotEmpty($data['content'][Entry::ID_PREFIX.'compare']['entry_num_1']);
+ }
+}
+
+/**
+ * Testable entry widget
+ */
+class EntryTestWidget extends \EGroupware\Api\Etemplate\Widget\Entry
+{
+ public function get_entry($value, array $attrs)
+ {
+ $entry = EntryTest::getEntry($value, $attrs);
+
+ return $entry;
+ }
+}
\ No newline at end of file