diff --git a/composer.json b/composer.json index 021e9ff8b7fcd989d0b4fc19db0e7759a0d64a0a..320040e6221505627f01fd85d0a25a6b15f0f7b5 100644 --- a/composer.json +++ b/composer.json @@ -5,5 +5,8 @@ "description": "Provides an 'or-able' token.", "require": { "drupal/token": "^1.0" + }, + "require-dev": { + "drupal/webform": "^6.2" } } diff --git a/modules/token_or_webform/src/TokenOrWebformTokenManager.php b/modules/token_or_webform/src/TokenOrWebformTokenManager.php new file mode 100644 index 0000000000000000000000000000000000000000..ea91124f1e0198916fbe503c432e69c400c172ec --- /dev/null +++ b/modules/token_or_webform/src/TokenOrWebformTokenManager.php @@ -0,0 +1,45 @@ +<?php + +namespace Drupal\token_or_webform; + +use Drupal\Core\Entity\EntityInterface; +use Drupal\Core\Render\BubbleableMetadata; +use Drupal\webform\WebformTokenManager; + +/** + * Tokens Pre Alter Service. + * + * @property \Drupal\Core\Utility\Token $token + */ +class TokenOrWebformTokenManager extends WebformTokenManager { + + /** + * {@inheritdoc} + */ + public function replace($text, EntityInterface $entity = NULL, array $data = [], array $options = [], BubbleableMetadata $bubbleable_metadata = NULL) { + if (!$text) { + return $text; + } + + if (is_array($text) || strpos($text, '|') === FALSE) { + return parent::replace($text, $entity, $data, $options, $bubbleable_metadata); + } + $options['clear'] = 1; + + // For anonymous users remove all [current-user] tokens to prevent + // anonymous user properties from being displayed. + // For example, the [current-user:display-name] token will return + // 'Anonymous', which is not an expected behavior. + // + // Updated to handle token_or's | syntax. + if ($this->currentUser->isAnonymous() && strpos($text, '[current-user:') !== FALSE) { + $text = preg_replace('/\[current-user:[^|]+\|/', '[', $text); + // Removing current-user: might leave a single string token. + // Let's clean that up. + $text = preg_replace('/\["([^]"]+)"\]/', '$1', $text); + } + + return parent::replace($text, $entity, $data, $options, $bubbleable_metadata); + } + +} diff --git a/modules/token_or_webform/tests/module/webform_test/config/install/webform.webform.test.yml b/modules/token_or_webform/tests/module/webform_test/config/install/webform.webform.test.yml new file mode 100644 index 0000000000000000000000000000000000000000..5aaaa8ae2bbf4e740789e4e17df70e69cccecaa1 --- /dev/null +++ b/modules/token_or_webform/tests/module/webform_test/config/install/webform.webform.test.yml @@ -0,0 +1,224 @@ +uuid: null +langcode: es +status: open +dependencies: { } +weight: 0 +open: null +close: null +uid: 1 +template: false +archive: false +id: test +title: Test +description: '' +categories: { } +elements: |- + current_page_query: + '#title': CID + '#type': textfield + '#required': true + '#default_value': 'Lorem lorem [current-page:query:cid|"foobar"]' + current_page_query_clear: + '#title': CID + '#type': textfield + '#required': true + '#default_value': 'Lorem lorem [current-page:query:cid:clear|"foobar"]' + current_user_display_name: + '#title': Display + '#type': textfield + '#required': true + '#default_value': 'Lorem lorem [current-user:display-name]' + current_user_display_name_fallback: + '#title': Display + '#type': textfield + '#required': true + '#default_value': 'Lorem lorem [current-user:display-name|"Nothing"]' + actions: + '#type': webform_actions + '#title': 'Submit button(s)' + '#submit__label': 'Send message' +css: '' +javascript: '' +settings: + ajax: false + ajax_scroll_top: form + ajax_progress_type: '' + ajax_effect: '' + ajax_speed: null + page: true + page_submit_path: '' + page_confirm_path: '' + page_theme_name: '' + form_title: both + form_submit_once: false + form_open_message: '' + form_close_message: '' + form_exception_message: '' + form_previous_submissions: true + form_confidential: false + form_confidential_message: '' + form_disable_remote_addr: false + form_convert_anonymous: false + form_prepopulate: false + form_prepopulate_source_entity: false + form_prepopulate_source_entity_required: false + form_prepopulate_source_entity_type: '' + form_unsaved: false + form_disable_back: false + form_submit_back: false + form_disable_autocomplete: false + form_novalidate: false + form_disable_inline_errors: false + form_required: false + form_autofocus: false + form_details_toggle: false + form_reset: false + form_access_denied: default + form_access_denied_title: '' + form_access_denied_message: '' + form_access_denied_attributes: { } + form_file_limit: '' + form_attributes: { } + form_method: '' + form_action: '' + share: false + share_node: false + share_theme_name: '' + share_title: true + share_page_body_attributes: { } + submission_label: '' + submission_exception_message: '' + submission_locked_message: '' + submission_log: false + submission_excluded_elements: { } + submission_exclude_empty: false + submission_exclude_empty_checkbox: false + submission_views: { } + submission_views_replace: { } + submission_user_columns: { } + submission_user_duplicate: false + submission_access_denied: default + submission_access_denied_title: '' + submission_access_denied_message: '' + submission_access_denied_attributes: { } + previous_submission_message: '' + previous_submissions_message: '' + autofill: false + autofill_message: '' + autofill_excluded_elements: { } + wizard_progress_bar: true + wizard_progress_pages: false + wizard_progress_percentage: false + wizard_progress_link: false + wizard_progress_states: false + wizard_start_label: '' + wizard_preview_link: false + wizard_confirmation: true + wizard_confirmation_label: '' + wizard_auto_forward: true + wizard_auto_forward_hide_next_button: false + wizard_keyboard: true + wizard_track: '' + wizard_prev_button_label: '' + wizard_next_button_label: '' + wizard_toggle: false + wizard_toggle_show_label: '' + wizard_toggle_hide_label: '' + wizard_page_type: container + wizard_page_title_tag: h2 + preview: 0 + preview_label: '' + preview_title: '' + preview_message: '' + preview_attributes: { } + preview_excluded_elements: { } + preview_exclude_empty: true + preview_exclude_empty_checkbox: false + draft: none + draft_multiple: false + draft_auto_save: false + draft_saved_message: '' + draft_loaded_message: '' + draft_pending_single_message: '' + draft_pending_multiple_message: '' + confirmation_type: page + confirmation_url: '' + confirmation_title: '' + confirmation_message: '' + confirmation_attributes: { } + confirmation_back: true + confirmation_back_label: '' + confirmation_back_attributes: { } + confirmation_exclude_query: false + confirmation_exclude_token: false + confirmation_update: false + limit_total: null + limit_total_interval: null + limit_total_message: '' + limit_total_unique: false + limit_user: null + limit_user_interval: null + limit_user_message: '' + limit_user_unique: false + entity_limit_total: null + entity_limit_total_interval: null + entity_limit_user: null + entity_limit_user_interval: null + purge: none + purge_days: null + results_disabled: false + results_disabled_ignore: false + results_customize: false + token_view: false + token_update: false + token_delete: false + serial_disabled: false +access: + create: + roles: + - anonymous + - authenticated + users: { } + permissions: { } + view_any: + roles: { } + users: { } + permissions: { } + update_any: + roles: { } + users: { } + permissions: { } + delete_any: + roles: { } + users: { } + permissions: { } + purge_any: + roles: { } + users: { } + permissions: { } + view_own: + roles: { } + users: { } + permissions: { } + update_own: + roles: { } + users: { } + permissions: { } + delete_own: + roles: { } + users: { } + permissions: { } + administer: + roles: { } + users: { } + permissions: { } + test: + roles: { } + users: { } + permissions: { } + configuration: + roles: { } + users: { } + permissions: { } +handlers: { } +variants: { } diff --git a/modules/token_or_webform/tests/module/webform_test/token_or_webform_test.info.yml b/modules/token_or_webform/tests/module/webform_test/token_or_webform_test.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..612e348e0eca36172eafa7b1e3fd2cda9a051f8a --- /dev/null +++ b/modules/token_or_webform/tests/module/webform_test/token_or_webform_test.info.yml @@ -0,0 +1,6 @@ +name: 'Token Or Webform test' +type: module +description: 'Support module for webform testing.' +core_version_requirement: ^9 || ^10 +dependencies: + - 'webform:webform' \ No newline at end of file diff --git a/modules/token_or_webform/tests/src/Functional/TokenOrWebformFunctionalBrokenTest.php b/modules/token_or_webform/tests/src/Functional/TokenOrWebformFunctionalBrokenTest.php new file mode 100644 index 0000000000000000000000000000000000000000..470b7f17fa5239c47fb9eb732b7f7624ae72fa1d --- /dev/null +++ b/modules/token_or_webform/tests/src/Functional/TokenOrWebformFunctionalBrokenTest.php @@ -0,0 +1,101 @@ +<?php + +namespace Drupal\Tests\token_or_webform\Functional; + +use Drupal\Tests\BrowserTestBase; +use Drupal\user\Entity\Role; + +/** + * Test that the issue exists without this module being enabled. + * + * @group token_or_webform + */ +class TokenOrWebformFunctionalBrokenTest extends BrowserTestBase { + + /** + * Modules to enable. + * + * @var array + */ + protected static $modules = ['token_or', 'webform', 'token_or_webform_test']; + + /** + * Theme to enable. + * + * @var string + */ + protected $defaultTheme = 'claro'; + + /** + * A user with permission to administer site configuration. + * + * @var \Drupal\user\UserInterface + */ + protected $user; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $anon_role = Role::load(Role::ANONYMOUS_ID); + $this->grantPermissions($anon_role, ['access content']); + } + + /** + * Tests token [current-page:query:cid|"foobar"] when get param is present. + */ + public function testCurrentPageGetParamPresent() { + $params = [ + 'cid' => 'param_cid', + 'nid' => 'param_nid', + ]; + $this->drupalGet('webform/test', ['query' => $params]); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-page-query"][@value="Lorem lorem param_cid"]'); + } + + /** + * Tests token [current-page:query:cid|"foobar"] when get param is missing. + */ + public function testCurrentPageGetParamMissing() { + // If not exists first param, use fallback. + $this->drupalGet('webform/test'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-page-query"][@value="Lorem lorem [current-page:query:cid]"]'); + } + + /** + * Tests token [current-page:query:cid:clear|"foobar"]... + * + * When get param is missing. + */ + public function testCurrentPageGetParamMissingClear() { + // If not exists first param, use fallback. + $this->drupalGet('webform/test'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-page-query-clear"][@value="Lorem lorem "]'); + } + + /** + * Tests token [current-user:display-name] still returns nothing. + */ + public function testAnonymousCurrentUser() { + $this->drupalGet('webform/test'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-user-display-name"][@value="Lorem lorem "]'); + } + + /** + * Tests token [current-user:display-name|"Nothing"]... + * + * Does not return its fallback. + */ + public function testAnonymousCurrentUserFallback() { + $this->drupalGet('webform/test'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-user-display-name-fallback"][@value="Lorem lorem "]'); + } + +} diff --git a/modules/token_or_webform/tests/src/Functional/TokenOrWebformFunctionalTest.php b/modules/token_or_webform/tests/src/Functional/TokenOrWebformFunctionalTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ce0617019ada8e638fc390b94465b4b3e05f82b8 --- /dev/null +++ b/modules/token_or_webform/tests/src/Functional/TokenOrWebformFunctionalTest.php @@ -0,0 +1,103 @@ +<?php + +namespace Drupal\Tests\token_or_webform\Functional; + +use Drupal\Tests\BrowserTestBase; +use Drupal\user\Entity\Role; + +/** + * Test that the module works. + * + * @group token_or_webform + */ +class TokenOrWebformFunctionalTest extends BrowserTestBase { + + /** + * Modules to enable. + * + * @var array + */ + protected static $modules = [ + 'token_or', + 'webform', + 'token_or_webform_test', + 'token_or_webform', + ]; + + /** + * Theme to enable. + * + * @var string + */ + protected $defaultTheme = 'claro'; + + /** + * A user with permission to administer site configuration. + * + * @var \Drupal\user\UserInterface + */ + protected $user; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + + $anon_role = Role::load(Role::ANONYMOUS_ID); + $this->grantPermissions($anon_role, ['access content']); + } + + /** + * Tests token [current-page:query:cid|"foobar"] when get param is present. + */ + public function testCurrentPageGetParamPresent() { + $params = [ + 'cid' => 'param_cid', + ]; + $this->drupalGet('webform/test', ['query' => $params]); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-page-query"][@value="Lorem lorem param_cid"]'); + } + + /** + * Tests token [current-page:query:cid|"foobar"] when get param is missing. + */ + public function testCurrentPageGetParamMissing() { + // If not exists first param, use fallback. + $this->drupalGet('webform/test'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-page-query"][@value="Lorem lorem foobar"]'); + } + + /** + * Tests token [current-page:query:cid:clear|"foobar"]... + * + * When get param is missing. + */ + public function testCurrentPageGetParamMissingClear() { + // If not exists first param, use fallback. + $this->drupalGet('webform/test'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-page-query-clear"][@value="Lorem lorem foobar"]'); + } + + /** + * Tests token [current-user:display-name] still returns nothing. + */ + public function testAnonymousCurrentUser() { + $this->drupalGet('webform/test'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-user-display-name"][@value="Lorem lorem "]'); + } + + /** + * Tests token [current-user:display-name|"Nothing"] returns its fallback. + */ + public function testAnonymousCurrentUserFallback() { + $this->drupalGet('webform/test'); + $this->assertSession()->statusCodeEquals(200); + $this->assertSession()->elementExists('xpath', '//*[@id="edit-current-user-display-name-fallback"][@value="Lorem lorem Nothing"]'); + } + +} diff --git a/modules/token_or_webform/tests/src/Kernel/TokenOrWebformKernelBrokenTest.php b/modules/token_or_webform/tests/src/Kernel/TokenOrWebformKernelBrokenTest.php new file mode 100644 index 0000000000000000000000000000000000000000..3e821f07547d41ebd00339ea9bed7335c35e3f13 --- /dev/null +++ b/modules/token_or_webform/tests/src/Kernel/TokenOrWebformKernelBrokenTest.php @@ -0,0 +1,58 @@ +<?php + +namespace Drupal\Tests\token_or_webform\Kernel; + +use Drupal\KernelTests\KernelTestBase; + +/** + * Tests the Token Or Webform module. + * + * @group token_or_webform + * @requires module token + */ +class TokenOrWebformKernelBrokenTest extends KernelTestBase { + + /** + * Token service. + * + * @var \Drupal\token\Token + */ + protected $tokenService; + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'webform', + 'token', + 'user', + 'token_or', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + $this->tokenService = \Drupal::service('webform.token_manager'); + } + + /** + * Test that current user token does not fallback. + */ + public function testBrokenCurrentUserToken() { + $value = $this->tokenService->replace('[current-user:email|"foobar"]'); + $this->assertEquals('', $value); + } + + /** + * Test that current user token array does not fallback. + */ + public function testArrayToken() { + $value = $this->tokenService->replace( + ['[current-user:email|"foobar"]', '[current-user:email|"foobar"]'] + ); + $this->assertEquals(['', ''], $value); + } + +} diff --git a/modules/token_or_webform/tests/src/Kernel/TokenOrWebformKernelTest.php b/modules/token_or_webform/tests/src/Kernel/TokenOrWebformKernelTest.php new file mode 100644 index 0000000000000000000000000000000000000000..ab30ad4a50755f7bc7ab6079ef68318a14dc0100 --- /dev/null +++ b/modules/token_or_webform/tests/src/Kernel/TokenOrWebformKernelTest.php @@ -0,0 +1,59 @@ +<?php + +namespace Drupal\Tests\token_or_webform\Kernel; + +use Drupal\KernelTests\KernelTestBase; + +/** + * Tests the Token Or module. + * + * @group token_or_webform + * @requires module token + */ +class TokenOrWebformKernelTest extends KernelTestBase { + + /** + * Token service. + * + * @var \Drupal\token\Token + */ + protected $tokenService; + + /** + * {@inheritdoc} + */ + protected static $modules = [ + 'webform', + 'token', + 'user', + 'token_or', + 'token_or_webform', + ]; + + /** + * {@inheritdoc} + */ + protected function setUp(): void { + parent::setUp(); + $this->tokenService = \Drupal::service('webform.token_manager'); + } + + /** + * Test that current user token does fallback. + */ + public function testToken() { + $value = $this->tokenService->replace('[current-user:display-name|"foobar"]'); + $this->assertEquals('foobar', $value); + } + + /** + * Test that current user token array does fallback. + */ + public function testArrayToken() { + $value = $this->tokenService->replace( + ['[current-user:email|"foobar"]', '[current-user:email|"foobar"]'] + ); + $this->assertEquals(['foobar', 'foobar'], $value); + } + +} diff --git a/modules/token_or_webform/token_or_webform.info.yml b/modules/token_or_webform/token_or_webform.info.yml new file mode 100644 index 0000000000000000000000000000000000000000..964aca3e4037e5dedf50f1b7eb69c9e757bf4742 --- /dev/null +++ b/modules/token_or_webform/token_or_webform.info.yml @@ -0,0 +1,7 @@ +name: Token Or Webform +type: module +description: Support for token_or in webform. +core_version_requirement: ^9 || ^10 +dependencies: + - webform:webform + - token_or:token_or diff --git a/modules/token_or_webform/token_or_webform.services.yml b/modules/token_or_webform/token_or_webform.services.yml new file mode 100644 index 0000000000000000000000000000000000000000..d352107148a5be905ae9d126f8fd9bb2f7ab0433 --- /dev/null +++ b/modules/token_or_webform/token_or_webform.services.yml @@ -0,0 +1,7 @@ +services: + token_or_webform.token_manager: + class: Drupal\token_or_webform\TokenOrWebformTokenManager + decorates: webform.token_manager + decoration_priority: 50 + public: false + arguments: ['@current_user', '@language_manager', '@config.factory', '@module_handler', '@token'] diff --git a/src/Token.php b/src/Token.php index 2bcab86c1fa63cf05547ab5070384630f0aa62b7..734dad26eec18f80cfdc21a390f3913f6ccfd0da 100644 --- a/src/Token.php +++ b/src/Token.php @@ -2,8 +2,8 @@ namespace Drupal\token_or; -use Drupal\token\Token as OriginalToken; use Drupal\Core\Render\BubbleableMetadata; +use Drupal\token\Token as OriginalToken; /** * Overrride class for tokens.