Який правильний спосіб здійснити дзвінок AJAX в компоненті?


40

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


Важлива порада - ніколи не порушити потік Joomla. Наприклад, кілька компонентів isten ajax запит на подіюAfterRoute і виконують завдання і вбивають запит тут сам. Це викликає помилки, які важко налагодити.
Шям

Ви маєте на увазі - не закривати додаток? Чи можете ви детальніше розробити?
Дмитро Рекун

Так, якщо Joomla закриє додаток, це буде найкраще. Так розширюваність вашого розширення буде збережена.
Шям

Досі не розумію повністю. Те, про що я говорю, - це $ app-> close () в контролері. Ви маєте на увазі те саме? :)
Дмитро Рекун

Так, говорити те саме. Чому ми повинні закрити додаток у контролері, тоді як те саме зробить і сам Joomla.
Шям

Відповіді:


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 дивіться нижче, як все поставити в контролер.

Субконтролери

Якщо ви зробите свій запит Ajax на субпідрядник , наприклад:

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

Чим має бути ваше ім'я субконтролера (для необробленого виду) abc.raw.php.

Це означає також, що у вас / можуть бути 2 субконтролера на ім'я Abc.

Якщо ви повернете JSON, це може мати сенс використовувати format=jsonі abc.json.php. У Joomla 2.5. У мене були деякі проблеми з тим, як ця опція працювала (якось вихід був пошкоджений), тому я використовував сирий


Дійсна відповідь 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=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, сторонніми можливостями та хаками, які я виявив протягом декількох днів гуглінгу, це був найпростіший підхід, який я міг придумати, - і відгуки виразно оцінені.

  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 \ контролери \ 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
Анібал

Не було 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.