Я разрабатываю пользовательский компонент для Joomla! 3.x и хотите сделать AJAX-вызов внутри него, чтобы получить некоторые данные. Как правильно это сделать?
Я разрабатываю пользовательский компонент для Joomla! 3.x и хотите сделать AJAX-вызов внутри него, чтобы получить некоторые данные. Как правильно это сделать?
Ответы:
ОБРАТИТЕ ВНИМАНИЕ, ЭТОМУ ОТВЕТУ уже несколько лет, и он не был обновлен. Не стесняйтесь редактировать / комментировать, если считаете, что что-то уже не точное.
Практически нет официального способа справиться с этим, все зависит от сложности и от того, насколько вы хотите полагаться на шаблон MVC для выполнения работы.
Ниже приведены некоторые возможные решения, которые должны работать в Joomla 2.5 и 3.x. Код представлен не для задания копирования-вставки, а в качестве общей идеи.
До Joomla! 3.2 единственное, что вам нужно, чтобы использовать примеры ниже, это component
. После Joomla 3.2 (для более низких сложных задач) вы можете обрабатывать запросы от модулей и плагинов.
Ваш 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. У меня были некоторые проблемы с получением этой опции (каким-то образом вывод был поврежден), поэтому я использовал raw.
Если вам необходимо сгенерировать правильный ответ 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 3.2! - позволил вам обрабатывать запросы без сборки компонента
Joomla! Интерфейс Ajax - Joomla теперь предоставляет облегченный способ обработки запросов Ajax в плагине или модуле. Вы можете использовать Joomla! Ajax-интерфейс, если у вас еще нет компонента или если вам нужно делать запросы от модуля, который у вас уже есть.
JRequest
? Это не рекомендуется, так $this->input
как я использую v3.x?
JRequest
. Спасибо
Valid JSON Response
разделе.
Это очень поздний ответ на этот очень хорошо отвеченный вопрос, но я хотел добавить это решение для тех, кому просто нужен простой способ получить данные своих компонентов с помощью вызова AJAX.
Со всеми версиями Joomla, сторонними возможностями и хакерами, которые я нашел за несколько дней поиска в Google, это был самый простой подход, который я мог придумать - и обратная связь ОПРЕДЕЛЕННО приветствуется.
execute
в мой существующий основной контроллер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"
}
}
Ответ Валентина хороший, но он слишком сложный, если все, что вам нужно сделать, это добавить 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();
}
}
Валентин ответил хорошо.
Я предпочитаю контроллер 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.
JResponseJson
класс, чтобы справиться с этим?
Если вы на 100% уверены, что нет стороннего плагина, добавляющего какой-либо вывод Javascript, чистый json_encode работает нормально.
Но ... например, JomSocial добавляет "" ко всему сайту.
Итак ... удобный трюк, оберните json_encode тегами и обработайте его на стороне Javascript.
echo '@START@' . json_encode(...) . '@END@';
Вы можете получить доступ к контроллеру напрямую, используя имя контроллера в задаче:
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;
)