it-swarm-es.tech

¿Cuál es la forma correcta de hacer una llamada AJAX en el componente?

Estoy desarrollando un componente personalizado para Joomla! 3.xy desea realizar una llamada AJAX dentro de ella para recuperar algunos datos. ¿Cuál es la forma correcta de hacerlo?

40
Dmitry Rekun

TENGA EN CUENTA QUE ESTA RESPUESTA ya tiene algunos años y no se actualizó. Siéntase libre de editar/comentar si cree que algo ya no es exacto.

Abstracto

Casi no hay una forma realmente oficial de lidiar con esto, depende mucho de la complejidad y de cuánto desee confiar en el patrón MVC para hacer el trabajo.

A continuación se presentan algunas posibles soluciones que deberían funcionar en Joomla 2.5 y 3.x. El código no se presenta para un trabajo de copiar y pegar, sino más bien como una idea general.

Antes de Joomla! 3.2 lo único que necesita para usar los ejemplos a continuación es un component. Después de Joomla 3.2 (para tareas de menor complejidad) puede manejar la solicitud de módulos y complementos.


Respuesta HTML genérica (siguiendo MVC heredado)

Su [~ # ~] url [~ # ~] para la tarea debe tener este aspecto:

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

En lugar de crear el controlador que usará la vista, digamos Abc, que contendrá el archivo view.raw.html (idéntico a un archivo de vista normal).

A continuación tiene el código para generar una respuesta HTML sin procesar:

/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: Esta es la solución que usaría si tuviera que devolver HTML (es más limpio y sigue la lógica de Joomla). Para devolver datos JSON simples, consulte a continuación cómo colocar todo en el controlador.

Subcontroladores

Si realiza su solicitud de Ajax a un subcontrolador , como:

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

Entonces, el nombre de su subcontrolador (para la vista sin procesar) debe ser abc.raw.php.

Esto significa también que tendrá/puede tener 2 subcontroladores llamados Abc.

Si devuelve JSON, puede tener sentido usar format=json Y abc.json.php. En Joomla 2.5. Tuve algunos problemas para que esta opción funcionara (de alguna manera el resultado estaba dañado), así que utilicé raw.


Respuesta JSON válida (siguiente MVC nuevo/heredado)

Si necesita generar una respuesta JSON válida , consulte la página de documentación Generando salida 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);

En general, colocaría este código en el controlador (llamará a un modelo que devolverá los datos que codifica, un escenario muy común). Si necesita llevarlo más lejos, también puede crear una vista JSON (view.json.php), similar al ejemplo en bruto.


Seguridad

Ahora que la solicitud de Ajax está funcionando, no cierre la página todavía. Lee abajo.

No olvide verificar las falsificaciones de solicitudes. JSession::checkToken() son útiles aquí. Lea la documentación sobre Cómo agregar CSRF anti-spoofing a formularios


Sitios multilingües

Puede suceder que si no envía el nombre del idioma en la solicitud, Joomla no traducirá las cadenas de idioma que desea.

Considere agregar de alguna manera el parámetro lang a su solicitud (como &lang=de).


Joomla! Interfaz Ajax

¡Nuevo en Joomla 3.2! - ¡le permitió hacer solicitudes de manejo sin crear un componente

Interfaz Joomla! Ajax - Joomla ahora proporciona una forma liviana de manejar la solicitud de Ajax en un complemento o módulo. Es posible que desee utilizar Joomla! Interfaz Ajax si aún no tiene un componente o si necesita realizar solicitudes desde un módulo que ya tiene.

47
Valentin Despa

Esta es una respuesta tardía para esta pregunta muy bien respondida, pero quería agregar esta solución inmediata para aquellos que solo necesitan una forma simple de acceder a los datos de sus componentes con una llamada AJAX.

Con todas las versiones de Joomla, las posibilidades de terceros y los hacks que encontré durante varios días de búsqueda en Google, este fue el enfoque más simple que pude encontrar, y los comentarios son DEFINITIVAMENTE apreciados.

  1. Se agregó la función execute a mi controlador principal existente
  2. Creé un subcontrolador con una función pública para las tareas que quería llamar con AJAX
  3. Usé la clase integrada Joomla JResponseJson para manejar la salida ( ¡es realmente agradable! )

RL para llamar/ejecutar la tarea:

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

Controlador principal modificado\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);
        }
    }
}

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

Salida JSON representada

{
    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 respuesta de Valentin es buena, pero es un poco compleja si todo lo que necesita hacer es agregar 1 o 2 llamadas ajax a un componente que ya está construido. Es perfectamente posible salirse con la suya al no hacer por separado controller.raw.php o view.raw.php archivos.

Para hacer esta llamada ajax

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

En el subcontrolador 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 respuesta de Valentin es buena.

Prefiero un controlador json que maneje la codificación y el manejo de errores para esto. Creé una clase 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();
  }

}

Este controlador se extiende por la clase de controlador que hace el trabajo, algo como esto:

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

y llamas a la solicitud así:

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

El hash de token se genera mediante JSession :: getFormToken (). Entonces, la llamada completa completa podría verse así:

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

El segundo parámetro se establece en "falso" para que podamos usar esto en llamadas de JavaScript sin reescritura xml.

7
Harald Leithner

Si está 100% seguro de que no hay ningún complemento de terceros que agregue ninguna salida de Javascript, un json_encode puro funciona bien.

Pero ... por ejemplo, JomSocial agrega "" a todo el sitio.

Entonces ... un truco útil, envuelva json_encode con etiquetas y proceselo en el lado Javascript.

echo '@[email protected]' . json_encode(...) . '@[email protected]';
4
Anibal

Puede acceder a un controlador directamente utilizando el nombre del controlador en la tarea:

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

llamará a: controller.raw.php (el retorno es sin formato)

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

llamará a: controller.php (return es html si no usa die;)

3
Dennis Heiden