diff --git a/components/com_ajax/ajax.php b/components/com_ajax/ajax.php index 4c06d66bf8cf5..2232438c0029d 100644 --- a/components/com_ajax/ajax.php +++ b/components/com_ajax/ajax.php @@ -16,6 +16,7 @@ use Joomla\CMS\Log\Log; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Response\JsonResponse; +use Joomla\CMS\String\StringableInterface; use Joomla\CMS\Table\Table; /* @@ -205,15 +206,26 @@ // Return the results in the desired format switch ($format) { case 'json': - // JSONinzed - echo new JsonResponse($results, null, false, $input->get('ignoreMessages', true, 'bool')); + if (!($results instanceof Throwable) && $results instanceof StringableInterface) { + echo $results; + } else { + if (\is_object($results) && !($results instanceof Throwable) && $results instanceof \Stringable) { + @trigger_error( + 'Ajax result object (except Throwable) which implements Stringable interface (implicitly or explicitly), will be rendered directly. Starting from 7.0', + \E_USER_DEPRECATED + ); + } + + // JSONized + echo new JsonResponse($results, null, false, $input->get('ignoreMessages', true, 'bool')); + } break; default: // Handle as raw format // Output exception - if ($results instanceof Exception) { + if ($results instanceof Throwable) { // Log an error Log::add($results->getMessage(), Log::ERROR); @@ -222,7 +234,7 @@ // Echo exception type and message $out = \get_class($results) . ': ' . $results->getMessage(); - } elseif (\is_scalar($results)) { + } elseif (\is_scalar($results) || $results instanceof StringableInterface) { // Output string/ null $out = (string) $results; } else { diff --git a/libraries/src/String/StringableInterface.php b/libraries/src/String/StringableInterface.php new file mode 100644 index 0000000000000..001488e076324 --- /dev/null +++ b/libraries/src/String/StringableInterface.php @@ -0,0 +1,31 @@ + + * @license GNU General Public License version 2 or later; see LICENSE.txt + */ + +namespace Joomla\CMS\String; + +// phpcs:disable PSR1.Files.SideEffects +\defined('_JEXEC') or die; +// phpcs:enable PSR1.Files.SideEffects + +/** + * A transitioning interface to PHP implicit \Stringable interface + * + * @since __DEPLOY_VERSION__ + */ +interface StringableInterface +{ + /** + * To String magick. + * + * @return string + * + * @since __DEPLOY_VERSION__ + */ + public function __toString(): string; +} diff --git a/plugins/editors/tinymce/src/Extension/TinyMCE.php b/plugins/editors/tinymce/src/Extension/TinyMCE.php index 0dc33731ad865..6116faf3c00df 100644 --- a/plugins/editors/tinymce/src/Extension/TinyMCE.php +++ b/plugins/editors/tinymce/src/Extension/TinyMCE.php @@ -11,9 +11,11 @@ namespace Joomla\Plugin\Editors\TinyMCE\Extension; use Joomla\CMS\Event\Editor\EditorSetupEvent; +use Joomla\CMS\Event\Plugin\AjaxEvent; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Session\Session; +use Joomla\CMS\String\StringableInterface; use Joomla\Database\DatabaseAwareTrait; use Joomla\Event\SubscriberInterface; use Joomla\Filesystem\Folder; @@ -77,11 +79,21 @@ public function onEditorSetup(EditorSetupEvent $event) * * @since 5.0.0 */ - public function onAjaxTinymce() + public function onAjaxTinymce(AjaxEvent $event) { + // Create response object, with list of the templates + $response = new class () implements StringableInterface { + public $data = []; + + public function __toString(): string + { + return json_encode($this->data); + } + }; + $event->updateEventResult($response); + if (!Session::checkToken('request')) { - echo json_encode([]); - exit(); + return; } $this->loadLanguage(); @@ -91,8 +103,7 @@ public function onAjaxTinymce() $template = $this->getApplication()->getInput()->getPath('template', ''); if ('' === $template) { - echo json_encode([]); - exit(); + return; } $filepaths = is_dir(JPATH_ROOT . '/templates/' . $template) @@ -115,7 +126,7 @@ public function onAjaxTinymce() ]; } - echo json_encode($templates); - exit(); + // Add the list of templates to the response + $response->data = $templates; } }