Tworzę niestandardowy komponent dla Joomla! 3.x i chcesz wykonać wywołanie AJAX w celu pobrania niektórych danych. Jaki jest właściwy sposób to zrobić?
Tworzę niestandardowy komponent dla Joomla! 3.x i chcesz wykonać wywołanie AJAX w celu pobrania niektórych danych. Jaki jest właściwy sposób to zrobić?
Odpowiedzi:
PROSZĘ PAMIĘTAĆ, ŻE ODPOWIEDŹ ma już kilka lat i nie została zaktualizowana. Edytuj / komentuj, jeśli uważasz, że coś nie jest już dokładne.
Prawie nie ma naprawdę oficjalnego sposobu radzenia sobie z tym, to zależy od złożoności i od tego, jak bardzo chcesz polegać na wzorcu MVC.
Poniżej znajduje się kilka możliwych rozwiązań, które powinny działać w Joomla 2.5 i 3.x. Kod nie jest prezentowany dla zadania kopiowania-wklejania, ale jako ogólny pomysł.
Przed Joomla! 3,2 jedyną rzeczą, którą należy użyć poniższych przykładów jest component
. Po Joomla 3.2 (dla mniej złożonych zadań) możesz obsługiwać żądania z modułów i wtyczek.
Twój adres URL zadania musi wyglądać następująco:
index.php?option=com_similar&task=abc&format=raw
Abc
Następnie tworzysz kontroler, który będzie korzystał z widoku, powiedzmy , który będzie zawierał plik view.raw.html (identyczny z normalnym plikiem widoku).
Poniżej masz kod do generowania surowej odpowiedzi 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";
Uwaga: jest to rozwiązanie, którego użyłbym, gdybym musiał zwrócić HTML (jest czystszy i postępuje zgodnie z logiką Joomla). Aby zwrócić proste dane JSON, zobacz poniżej, jak umieścić wszystko w kontrolerze.
Jeśli przesyłasz żądanie Ajax do podwykonawcy , na przykład:
index.php?option=com_similar&controller=abc&format=raw
Nazwa twojego podwykonawcy (dla surowego widoku) musi być abc.raw.php
.
Oznacza to również, że będziesz / mógł mieć 2 subskrybentów o nazwie Abc.
Jeśli zwrócisz JSON, warto użyć format=json
i abc.json.php
. W Joomla 2.5. Miałem pewne problemy z uruchomieniem tej opcji (jakoś wynik był uszkodzony), więc użyłem raw.
Jeśli chcesz wygenerować prawidłową odpowiedź JSON , sprawdź stronę z dokumentami Generowanie danych wyjściowych 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);
Zazwyczaj umieszczasz ten kod w kontrolerze (wywołujesz model, który zwróci kodowane dane - bardzo częsty scenariusz). Jeśli chcesz pójść dalej, możesz również utworzyć widok JSON (view.json.php), podobny do surowego przykładu.
Teraz, gdy żądanie Ajax działa, nie zamykaj jeszcze strony. Czytaj poniżej.
Nie zapomnij sprawdzić fałszywych zapytań. JSession::checkToken()
przydaj się tutaj. Przeczytaj dokumentację na temat dodawania funkcji CSRF do fałszowania formularzy
Może się zdarzyć, że jeśli nie wyślesz nazwy języka we wniosku, Joomla nie przetłumaczy żądanych ciągów językowych.
Zastanów się, czy w jakiś sposób nie dołączyć do swojego żądania lang param (jak &lang=de
).
Nowości w Joomla 3.2! - umożliwiło wykonywanie żądań obsługi bez budowania komponentu
Joomla! Interfejs Ajax - Joomla zapewnia teraz lekki sposób obsługi żądania Ajax we wtyczce lub module. Możesz użyć Joomla! Interfejs Ajax, jeśli nie masz jeszcze komponentu lub jeśli chcesz wysyłać żądania z modułu, który już masz.
JRequest
? Jest przestarzałe, czy powinno to być po prostu, $this->input
ponieważ używam v3.x?
JRequest
. Dzięki
Valid JSON Response
rozdziale.
To późna odpowiedź na to pytanie, na które bardzo dobrze odpowiedziano, ale chciałem dodać to bezpośrednie rozwiązanie dla tych, którzy potrzebują prostego sposobu na uzyskanie dostępu do danych swoich komponentów za pomocą wywołania AJAX.
Ze wszystkimi wersjami Joomla, możliwościami stron trzecich i hackami, które znalazłem w ciągu kilku dni googlingu, było to najprostsze podejście, jakie mogłem wymyślić - i opinie są zdecydowanie doceniane.
execute
do mojego istniejącego głównego kontroleraAdres URL do wywołania / wykonania zadania:
www.mysite.com/index.php?option=com_example&task=ForAjax.mytaskname
Zmodyfikowany główny kontroler \ 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);
}
}
}
Nowy subkontroler \ com_example \ kontrolers \ 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();
}
}
Renderowane wyjście 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"
}
}
Odpowiedź Valentin jest dobra, ale jest nieco zbyt złożona, jeśli wszystko, co musisz zrobić, to dodać 1 lub 2 wywołania ajax do już zbudowanego komponentu. Zupełnie możliwe jest uniknięcie tworzenia osobnych plików controller.raw.php
lub view.raw.php
plików.
Aby wykonać to wywołanie ajax
index.php?format=raw&option=com_example&controller=job&task=keep_alive&tokenhash=1
W job
subkontrolerze
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();
}
}
Odpowiedź Valentina jest dobra.
Wolę kontroler json, który obsługuje kodowanie i obsługę błędów. Utworzyłem klasę podstawową 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();
}
}
Ten kontroler zostaje rozszerzony o klasę kontrolera, która działa, mniej więcej tak:
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();
}
}
i wywołujesz takie żądanie:
index.php?option=com_component&task=address.get&format=json&id=1234&tokenhash=1
Skrót tokenów jest generowany przez JSession :: getFormToken (). Kompletne pełne połączenie może wyglądać następująco:
$link = JRoute::_('index.php?option=com_component&task=address.get&format=json&id=1234&'.JSession::getFormToken().'=1', false);
Drugi parametr jest ustawiony na „false”, dzięki czemu możemy go używać w wywołaniach javascript bez przepisywania xml.
JResponseJson
klasy, aby sobie z tym poradzić?
Jeśli masz 100% pewności, że żadna wtyczka Thrid-Party nie dodaje żadnych danych wyjściowych JavaScript, czysty kod_json działa.
Ale ... na przykład JomSocial dodaje „” do całej witryny.
Więc ... przydatna sztuczka, zawiń json_encode tagami i przetwarzaj go po stronie Javascript.
echo '@START@' . json_encode(...) . '@END@';
Możesz uzyskać dostęp do kontrolera bezpośrednio, używając nazwy kontrolera w zadaniu:
index.php?option=com_similar&task=controller.abc&format=raw
wywoła: controller.raw.php (return is raw)
index.php?option=com_similar&task=controller.abc
wezwie: controller.php (powrót jest html, jeśli nie używać die;
)