it-swarm.dev

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

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

40
Dmitry Rekun

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 che devi usare negli esempi sotto è un component. Dopo Joomla 3.2 (per attività complesse inferiori) è possibile gestire la richiesta da moduli e plugin.


Risposta HTML generica (seguente MVC legacy)

Il tuo [~ # ~] url [~ # ~] per l'attività deve essere simile al seguente:

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

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

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 , come:

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

Il nome del tuo 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 avere senso utilizzare format=json E 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() torna utile qui. Leggi la documentazione su Come aggiungere CSRF anti-spoofing 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 fare richieste di gestione senza creare un componente

Joomla! Ajax Interface - 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.

47
Valentin Despa

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 è sicuramente apprezzato.

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

RL per chiamare/eseguire l'attività:

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

Modified Main Controller\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"
    }
}
20
GDP

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.php O view.raw.php Separati.

Per effettuare questa chiamata Ajax

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

Nel subcontrollore 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();
    }
}
11
Spunkie

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.

7
Harald Leithner

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 '@[email protected]' . json_encode(...) . '@[email protected]';
4
Anibal

È 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 (return è html se non usi die;)

3
Dennis Heiden