Qual è il modo corretto di effettuare una chiamata AJAX nel componente?


40

Sto sviluppando un componente personalizzato per Joomla! 3.xe desideri effettuare una chiamata AJAX al suo interno per recuperare alcuni dati. Qual è il modo corretto di farlo?


Un consiglio importante non interrompe mai il flusso di Joomla. Ad esempio pochi componenti sono una richiesta Ajax sull'evento AfterRoute ed eseguono l'attività e terminano la richiesta qui stessa. Ciò causa errori difficili da eseguire il debug.
Shyam,

Vuoi dire: non chiudere un'app? Puoi approfondire di più?
Dmitry Rekun,

Sì, se joomla chiude l'app, sarà la cosa migliore. In questo modo l'estensione dell'estensione verrà mantenuta.
Shyam,

Ancora non capisco completamente. Quello di cui sto parlando è $ app-> close () nel controller. Intendi lo stesso? :)
Dmitry Rekun,

Sì, parlando lo stesso punto. Perché dovremmo chiudere l'app nel controller, mentre lo stesso verrà fatto dallo stesso joomla.
Shyam,

Risposte:


47

SI PREGA DI NOTARE CHE QUESTA RISPOSTA ha già qualche anno e non è stata aggiornata. Sentiti libero di modificare / commentare se pensi che qualcosa non sia più esatto.

Astratto

Non esiste quasi un modo veramente ufficiale di gestirlo, dipende molto dalla complessità e da quanto si desidera fare affidamento sul modello MVC per svolgere il proprio lavoro.

Di seguito sono riportate alcune possibili soluzioni che dovrebbero funzionare in Joomla 2.5 e 3.x. Il codice non viene presentato per un processo di copia e incolla ma piuttosto come un'idea generale.

Prima di Joomla! 3.2 l'unica cosa di cui hai bisogno per usare gli esempi seguenti è a component. Dopo Joomla 3.2 (per attività complesse inferiori) è possibile gestire la richiesta da moduli e plugin.


Risposta HTML generica (a seguito di MVC legacy)

L' URL per l'attività deve essere simile al seguente:

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

Si crea il controller che utilizzerà la vista, diciamo Abc, che conterrà il file view.raw.html (identico a un normale file di visualizzazione).

Di seguito è riportato il codice per generare una risposta HTML non elaborata:

/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";

Nota: questa è la soluzione che userei se dovessi restituire HTML (è più pulito e segue la logica di Joomla). Per la restituzione di semplici dati JSON, vedere di seguito come inserire tutto nel controller.

sub-console

Se invii la tua richiesta Ajax a un subcontrollore , ad esempio:

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

Il nome del subcontrollore (per la vista non elaborata) deve essere abc.raw.php.

Questo significa anche che avrai / potresti avere 2 subcontrollori chiamati Abc.

Se si restituisce JSON, potrebbe essere logico utilizzare format=jsone abc.json.php. In Joomla 2.5. Ho avuto dei problemi a far funzionare questa opzione (in qualche modo l'output era corrotto), quindi ho usato raw.


Risposta JSON valida (a seguito di MVC nuovo / legacy)

Se è necessario generare una risposta JSON valida , consultare la pagina dei documenti Generazione dell'output 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);

In genere inseriresti questo codice nel controller (chiamerai un modello che restituirà i dati che codifichi - uno scenario molto comune). Se è necessario andare oltre, è anche possibile creare una vista JSON (view.json.php), simile all'esempio non elaborato.


Sicurezza

Ora che la richiesta Ajax funziona, non chiudere ancora la pagina. Leggere sotto.

Non dimenticare di controllare i falsi delle richieste. JSession::checkToken()vieni utile qui. Leggi la documentazione su Come aggiungere l' anti-spoofing CSRF ai moduli


Siti multilingue

Può succedere che se non invii il nome della lingua nella richiesta, Joomla non tradurrà le stringhe della lingua che desideri.

Valuta di aggiungere in qualche modo il parametro lang alla tua richiesta (come &lang=de).


Joomla! Interfaccia Ajax

Novità in Joomla 3.2! - ti ha permesso di effettuare richieste handle senza creare un componente

Joomla! Interfaccia Ajax - Joomla ora fornisce un modo leggero per gestire la richiesta Ajax in un plugin o modulo. Potresti voler usare Joomla! Interfaccia Ajax se non si dispone già di un componente o se è necessario effettuare richieste da un modulo già esistente.


9
La migliore risposta di qualità che ho visto su joomla.stackexchange.com finora - ben fatto e un modo per alzare il tiro. Lavoro eccellente!
NivF007,

D'accordo, ma che dire JRequest? È deprecato dovrebbe essere semplicemente $this->inputda quando uso v3.x?
Dmitry Rekun,

1
Ho risposto alla tua preoccupazione in merito JRequest. Grazie
Valentin Despa,

3
Bella risposta, volevo solo menzionare che esiste una classe Joomla dal 3.1 che gestisce l'output JSON: API , Utilizzo
fruppel

@ fl0r yeap, Valentin lo ha menzionato nella Valid JSON Responsesezione.
Dmitry Rekun,

20

Questa è una risposta tardiva a questa domanda a cui è stata data una risposta molto buona, ma volevo aggiungere questa soluzione immediata per coloro che hanno solo bisogno di un modo semplice per accedere ai dati dei loro componenti con una chiamata AJAX.

Con tutte le versioni di Joomla, le possibilità di terze parti e gli hack che ho trovato in diversi giorni di ricerche su Google, questo è stato l'approccio più semplice che ho potuto escogitare - e il feedback è DEFINATAMENTE apprezzato.

  1. Aggiunta funzione executeal mio controller principale esistente
  2. Creato un subcontrollore con una funzione pubblica per le attività che volevo chiamare con AJAX
  3. Ho usato la classe integrata Joomla JResponseJson per gestire l'output ( è davvero bello! )

URL per chiamare / eseguire l'attività:

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

Controller principale modificato \ 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);
        }
    }
}

Nuovo subcontrollore \ 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();
    }
}

Output JSON reso

{
    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

La risposta di Valentin è buona ma è un po 'troppo complessa se tutto ciò che devi fare è aggiungere 1 o 2 chiamate ajax a un componente che è già stato creato. È perfettamente possibile cavarsela senza creare file controller.raw.phpo view.raw.phpfile separati .

Per effettuare questa chiamata Ajax

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

Nel jobsubcontrollore

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

La risposta di Valentin è buona.

Preferisco un controller json che gestisce la codifica e la gestione degli errori per questo Ho creato una classe base 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();
  }

}

Questo controller viene esteso dalla classe controller che fa il lavoro, qualcosa del genere:

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();
  }
}

e chiamate la richiesta in questo modo:

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

L'hash token viene generato da JSession :: getFormToken (). Quindi la chiamata completa completa potrebbe essere simile a questa:

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

Il secondo parametro è impostato su "false", quindi possiamo usarlo nelle chiamate javascript senza riscrivere xml.


1
Bello, ma perché non usare la JResponseJsonclasse per gestirlo?
Dmitry Rekun,

JResponseJson è stato introdotto in Joomla 3
Anibal il

Non c'era Joomla SE dove avrei potuto chiedere;)
Harald Leithner il

4

Se sei sicuro al 100% che non esiste un plug-in di terze parti che aggiunge alcun output Javascript, un json_encode puro funziona bene.

Ma ... per esempio JomSocial aggiunge "" all'intero sito.

Quindi ... un trucco utile, avvolgi json_encode con i tag ed elaboralo sul lato Javascript.

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

3

È possibile accedere direttamente a un controller utilizzando il nome del controller nell'attività:

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

chiamerà: controller.raw.php (il ritorno è grezzo)

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

chiamerà: controller.php (il ritorno è html se non lo usi die;)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.