Как правильно сделать AJAX-вызов в компоненте?


40

Я разрабатываю пользовательский компонент для Joomla! 3.x и хотите сделать AJAX-вызов внутри него, чтобы получить некоторые данные. Как правильно это сделать?


Важный совет никогда не нарушать поток Joomla. Например, несколько компонентов isten ajax-запрос на событие onAfterRoute и выполнить задачу и убить запрос здесь сам. Это приводит к ошибкам, которые сложно отладить.
— Шиам

Вы имеете в виду - не закрывать приложение? Можете ли вы рассказать подробнее?
— Дмитрий Рекун

Да, если Joomla закроет приложение, оно будет лучшим. Таким образом, расширяемость вашего расширения будет сохранена.
— Shyam

Все еще не понимаю полностью. То, о чем я говорю, это $ app-> close () в контроллере. Вы имеете в виду то же самое? :)
— Дмитрий Рекун

Да, говорю то же самое. Почему мы должны закрывать приложение в контроллере, а то же самое будет делать сама Joomla.
— Shyam

Ответы:


47

ОБРАТИТЕ ВНИМАНИЕ, ЭТОМУ ОТВЕТУ уже несколько лет, и он не был обновлен. Не стесняйтесь редактировать / комментировать, если считаете, что что-то уже не точное.

Аннотация

Практически нет официального способа справиться с этим, все зависит от сложности и от того, насколько вы хотите полагаться на шаблон MVC для выполнения работы.

Ниже приведены некоторые возможные решения, которые должны работать в Joomla 2.5 и 3.x. Код представлен не для задания копирования-вставки, а в качестве общей идеи.

До Joomla! 3.2 единственное, что вам нужно, чтобы использовать примеры ниже, это component. После Joomla 3.2 (для более низких сложных задач) вы можете обрабатывать запросы от модулей и плагинов.


Общий ответ HTML (в соответствии с устаревшим MVC)

Ваш URL для задачи должен выглядеть следующим образом:

index.php?option=com_similar&task=abc&format=raw

AbcЗатем вы создаете контроллер, который будет использовать представление, скажем , которое будет содержать файл view.raw.html (идентичный обычному файлу представления).

Ниже у вас есть код для генерации необработанного HTML-ответа:

/controller.php

public function abc() 
{
    // Set view

    // Joomla 2.5
    JRequest::setVar('view', 'Abc'); 

    // (use JInput in 3.x)
    $this->input->set('view', 'Abc');

    parent::display();
}

/views/abc/view.raw.php

<?php
defined('_JEXEC') or die;

jimport('joomla.application.component.view');

class SimilarViewAbc extends JViewLegacy
{
    function display($tpl = null)
    {
        parent::display($tpl);
    }
}

/views/abc/tmpl/default.php

<?php

echo "Hello World from /views/abc/tmpl/default.php";

Примечание: это решение я бы использовал, если бы мне пришлось возвращать HTML (он чище и следует логике Joomla). Для возврата простых данных JSON, смотрите ниже, как поместить все в контроллер.

Subcontrollers

Если вы отправите запрос Ajax субконтроллеру , например:

index.php?option=com_similar&controller=abc&format=raw

Чем должно быть ваше имя субконтроллера (для необработанного представления) abc.raw.php.

Это также означает, что у вас будет / может быть 2 субконтроллера с именем Abc.

Если вы возвращаете JSON, возможно, имеет смысл использовать format=jsonи abc.json.php. В Joomla 2.5. У меня были некоторые проблемы с получением этой опции (каким-то образом вывод был поврежден), поэтому я использовал raw.


Действительный ответ JSON (следующий новый / устаревший MVC)

Если вам необходимо сгенерировать правильный ответ JSON , проверьте страницу документы Генерирование JSON выход

// We assume that the whatver you do was a success.
$response = array("success" => true);
// You can also return something like:
$response = array("success" => false, "error"=> "Could not find ...");

// Get the document object.
$document = JFactory::getDocument();

// Set the MIME type for JSON output.
$document->setMimeEncoding('application/json');

// Change the suggested filename.
JResponse::setHeader('Content-Disposition','attachment;filename="result.json"');

echo json_encode($response);

Обычно вы помещаете этот код в контроллер (вы будете вызывать модель, которая будет возвращать закодированные вами данные - очень распространенный сценарий). Если вам нужно продвинуться дальше, вы также можете создать представление JSON (view.json.php), аналогичное необработанному примеру.


Безопасность

Теперь, когда Ajax-запрос работает, пока не закрывайте страницу. Читай ниже.

Не забудьте проверить подделку запроса. JSession::checkToken()пригодиться здесь. Прочитайте документацию о том, как добавить антиспуфинг CSRF в формы.


Многоязычные сайты

Может случиться так, что если вы не отправите имя языка в запросе, Joomla не переведет нужные вам языковые строки.

Попробуйте добавить параметр lang к вашему запросу (например &lang=de).


Joomla! Интерфейс Ajax

Новое в Joomla 3.2! - позволил вам обрабатывать запросы без сборки компонента

Joomla! Интерфейс Ajax - Joomla теперь предоставляет облегченный способ обработки запросов Ajax в плагине или модуле. Вы можете использовать Joomla! Ajax-интерфейс, если у вас еще нет компонента или если вам нужно делать запросы от модуля, который у вас уже есть.


9
Лучший качественный ответ, который я когда-либо видел на joomla.stackexchange.com - отлично сделано и способ поднять планку. Отличная работа!
— NivF007

Согласитесь, а что JRequest? Это не рекомендуется, так $this->inputкак я использую v3.x?
— Дмитрий Рекун

1
Я обратился к вашей озабоченности по поводу JRequest. Спасибо
— Валентин Деспа

3
Хороший ответ, просто хотел упомянуть, что существует класс Joomla начиная с версии 3.1, который обрабатывает вывод JSON: API , использование
— fruppel

@ fl0r да, Валентин упомянул об этом в Valid JSON Responseразделе.
— Дмитрий Рекун

20

Это очень поздний ответ на этот очень хорошо отвеченный вопрос, но я хотел добавить это решение для тех, кому просто нужен простой способ получить данные своих компонентов с помощью вызова AJAX.

Со всеми версиями Joomla, сторонними возможностями и хакерами, которые я нашел за несколько дней поиска в Google, это был самый простой подход, который я мог придумать - и обратная связь ОПРЕДЕЛЕННО приветствуется.

  1. Добавлена ​​функция executeв мой существующий основной контроллер
  2. Создал субконтроллер с публичной функцией для задач, которые я хотел вызвать с помощью AJAX
  3. Использовал встроенный класс Joomla JResponseJson для обработки вывода ( это действительно хорошо! )

URL для вызова / выполнения задачи:

www.mysite.com/index.php?option=com_example&task=ForAjax.mytaskname

Модифицированный главный контроллер \ com_example \ controller.php

class ExampleController extends JControllerLegacy {
    public function display($cachable = false, $urlparams = false) {
        $app = JFactory::getApplication();
        $view = $app->input->getCmd('view', 'default');
        $app->input->set('view', $view);
        parent::display($cachable, $urlparams);
        return $this;
    }

    public function execute()
    {
        // Not technically needed, but a DAMN good idea.  See http://docs.joomla.org/How_to_add_CSRF_anti-spoofing_to_forms
        // JSession::checkToken();
        $task = JFactory::getApplication()->input->get('task');
        try
        {
            parent::execute($task);
        }
        catch(Exception $e)
        {
            echo new JResponseJson($e);
        }
    }
}

Новый субконтроллер \ com_example \ controllers \ forajax.php

require_once JPATH_COMPONENT.'/controller.php';
class ExampleControllerForAjax extends ExampleController
{
    public function MyTaskName()
    {
        $app = JFactory::getApplication();

        $data['myRequest'] =$_REQUEST;
        $data['myFile'] =__FILE__;
        $data['myLine'] ='Line '.__LINE__;

        $app->enqueueMessage('This part was reached at line ' . __LINE__);
        $app->enqueueMessage('Then this part was reached at line ' . __LINE__);
        $app->enqueueMessage('Here was a small warning at line ' . __LINE__, 'warning');
        $app->enqueueMessage('Here was a big warning at line ' . __LINE__, 'error');

        $task_failed = false;
        echo new JResponseJson($data, 'My main response message',$task_failed);

        $app->close();
    }
}

Визуализированный вывод JSON

{
    success: true,
    message: "My main response message",
    messages: {
        message: [
            "This part was reached at line 26",
            "Then this part was reached at line 27"
        ],
        warning: [
            "Here was a small warning at line 28"
        ],
        error: [
            "Here was a big warning at line 29"
        ]
    },
    data: {
        myRequest: {
            option: "com_example",
            task: "mytaskname",
            Itemid: null
        },
        myFile: "C:\mysite\components\com_example\controllers\forajax.php",
        myLine: "Line 24"
    }
}

11

Ответ Валентина хороший, но он слишком сложный, если все, что вам нужно сделать, это добавить 1 или 2 вызова ajax к компоненту, который уже построен. Вполне возможно сойти с рук, не делая отдельные controller.raw.phpили view.raw.phpфайлы.

Чтобы сделать этот вызов AJAX

index.php?format=raw&option=com_example&controller=job&task=keep_alive&tokenhash=1

В jobсубконтроллере

public function keep_alive() {
    $this->ajax_check();

    //Do your processing and echo out whatever you want to return to the AJAX call
    header('HTTP/1.1 202 Accepted', true, 202);
    echo 'OK';

    JFactory::getApplication()->close();
}

// Verifies jtoken and does a basic check that this is actually an AJAX call
private function ajax_check() {
    if(!JSession::checkToken('GET') || !isset($_SERVER['HTTP_X_REQUESTED_WITH']) || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) !== 'xmlhttprequest') {
        header('HTTP/1.1 403 Forbidden', true, 403);
        JFactory::getApplication()->close();
    }
}

7

Валентин ответил хорошо.

Я предпочитаю контроллер json, который обрабатывает кодирование и обработку ошибок, для этого я создал базовый класс json:

class itrControllerJson extends JControllerLegacy {

  /** @var array the response to the client */
  protected $response = array();

  public function addResponse($type, $message, $status=200) {

    array_push($this->response, array(
      'status' => $status,
      'type' => $type,
      'data' => $message
    ));

  }

  /**
   * Outputs the response
   * @return JControllerLegacy|void
   */
  public function display() {

    $response = array(
      'status' => 200,
      'type' => 'multiple',
      'count' => count($this->response),
      'messages' => $this->response
    );

    echo json_encode($response);
    jexit();
  }

}

Этот контроллер расширяется классом контроллера, который выполняет работу, что-то вроде этого:

require_once __DIR__.'json.php';

class componentControllerAddress extends itrControllerJson {
  public function get() {

    try {
      if (!JSession::checkToken()) {
        throw new Exception(JText::_('JINVALID_TOKEN'), 500);
      }
      $app = JFactory::getApplication();

      $id = $app->input->get('id', null, 'uint');
      if (is_null($id)) {
        throw new Exception('Invalid Parameter', 500);
      }

      $db = JFactory::getDbo();
      $query = $db->getQuery(true);
      $query->select('*');
      $query->from('#__table');
      $query->where('id = '.$db->quote($id));
      $db->setQuery($query);
      $response = $db->loadObject();

      $this->addResponse('message', $response, 200);

    } catch (Exception $e) {
      $this->addResponse('error', $e->getMessage(), 500);
    }

    $this->display();
  }
}

и вы называете запрос так:

index.php?option=com_component&task=address.get&format=json&id=1234&tokenhash=1

Хэш токена генерируется JSession :: getFormToken (). Таким образом, полный завершенный вызов может выглядеть следующим образом:

$link = JRoute::_('index.php?option=com_component&task=address.get&format=json&id=1234&'.JSession::getFormToken().'=1', false);

Второй параметр имеет значение «false», поэтому мы можем использовать его в вызовах javascript без перезаписи xml.


1
Хорошо, но почему бы не использовать JResponseJsonкласс, чтобы справиться с этим?
— Дмитрий Рекун

JResponseJson был представлен в Joomla 3
— Anibal

Там не было Joomla SE, где я мог бы спросить;)
— Харальд Лейтнер

4

Если вы на 100% уверены, что нет стороннего плагина, добавляющего какой-либо вывод Javascript, чистый json_encode работает нормально.

Но ... например, JomSocial добавляет "" ко всему сайту.

Итак ... удобный трюк, оберните json_encode тегами и обработайте его на стороне Javascript.

echo '@START@' . json_encode(...) . '@END@';

3

Вы можете получить доступ к контроллеру напрямую, используя имя контроллера в задаче:

index.php?option=com_similar&task=controller.abc&format=raw

вызовет: controller.raw.php (возврат необработанный)

index.php?option=com_similar&task=controller.abc

вызовет: controller.php (возврат html, если вы не используете die;)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.