ti-enxame.com

Qual é a maneira correta de fazer uma chamada AJAX no componente?

Estou desenvolvendo um componente personalizado para o Joomla! 3.xe deseja fazer uma chamada AJAX dentro dela para recuperar alguns dados. Qual é a maneira correta de fazer isso?

40
Dmitry Rekun

Observe que esta resposta já tem alguns anos e não foi atualizada. Sinta-se livre para editar/comentar se você acha que algo não é mais exato.

Abstrato

Quase não existe uma maneira realmente oficial de lidar com isso, depende muito da complexidade e do quanto você deseja confiar no padrão MVC para fazer o trabalho.

Abaixo estão algumas soluções possíveis que devem funcionar no Joomla 2.5 e 3.x. O código não é apresentado para um trabalho de copiar e colar, mas como uma idéia geral.

Antes do Joomla! 3.2 a única coisa que você precisa para usar os exemplos abaixo é um component. Após o Joomla 3.2 (para tarefas menos complexas), você pode lidar com solicitações de módulos e plugins.


Resposta HTML genérica (após MVC herdado)

Seu [~ # ~] URL [~ # ~] para a tarefa precisa ter a seguinte aparência:

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

Você criou o controlador que usará a visualização, digamos Abc, que conterá o arquivo view.raw.html (idêntico a um arquivo de visualização normal).

Abaixo você tem o código para gerar uma resposta HTML bruta:

/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 é a solução que eu usaria se tivesse que retornar HTML (é mais limpo e segue a lógica do Joomla). Para retornar dados JSON simples, veja abaixo como colocar tudo no controlador.

Subcontroladores

Se você fizer sua solicitação do Ajax para um subcontrolador , como:

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

O nome do seu subcontrolador (para a visualização bruta) precisa ser abc.raw.php.

Isso significa também que você terá/poderá ter 2 subcontroladores chamados Abc.

Se você retornar JSON, pode fazer sentido usar format=json E abc.json.php. No Joomla 2.5. Eu tive alguns problemas para que essa opção funcionasse (de alguma forma, a saída foi corrompida), então usei raw.


Resposta JSON válida (após o MVC novo/legado)

Se você precisar gerar uma resposta JSON válida , consulte a página de documentos Gerando saída 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);

Você geralmente colocaria esse código no controlador (você chamará um modelo que retornará os dados que você codifica - um cenário muito comum). Se você precisar ir além, também poderá criar uma visualização JSON (view.json.php), semelhante ao exemplo bruto.


Segurança

Agora que a solicitação do Ajax está funcionando, não feche a página ainda. Leia abaixo.

Não se esqueça de verificar falsificações de pedidos. JSession::checkToken() é útil aqui. Leia a documentação sobre como adicionar anti-spoofing CSRF para formulários


Sites multilíngues

Pode acontecer que, se você não enviar o nome do idioma na solicitação, o Joomla não traduzirá as seqüências de caracteres desejadas.

Considere anexar de alguma forma o parâmetro lang à sua solicitação (como &lang=de).


Joomla! Interface Ajax

Novo no Joomla 3.2! - permitiu que você fizesse solicitações de manipulação sem criar um componente

Interface do Joomla! Ajax - O Joomla agora oferece uma maneira leve de lidar com a solicitação do Ajax em um plug-in ou módulo. Você pode querer usar o Joomla! Interface Ajax se você ainda não possui um componente ou se precisa fazer solicitações de um módulo que já possui.

47
Valentin Despa

Essa é uma resposta tardia para essa pergunta muito bem respondida, mas eu gostaria de adicionar esta solução simples para aqueles que precisam apenas de uma maneira simples de acessar os dados de seus componentes com uma chamada AJAX.

Com todas as versões do Joomla, possibilidades de terceiros e hacks que eu encontrei durante vários dias pesquisando no Google, essa foi a abordagem mais simples que eu pude apresentar - e o feedback é DEFINATAMENTE apreciado.

  1. Adicionada função execute ao meu controlador principal existente
  2. Criou um subcontrolador com uma função pública para as tarefas que eu queria chamar com o AJAX
  3. Utilizou a classe Joomla JResponseJson incorporada para lidar com a saída ( é realmente legal! )

RL para chamar/executar a tarefa:

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

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

Saída JSON renderizada

{
    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

A resposta de Valentin é boa, mas é um pouco complexa, se tudo o que você precisa fazer é adicionar 1 ou 2 chamadas ajax a um componente que já foi criado. É perfeitamente possível fugir sem fazer separações controller.raw.php ou view.raw.php arquivos.

Para fazer esta chamada ajax

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

No 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

A resposta de Valentin é boa.

Eu prefiro um controlador json que lida com a codificação e manipulação de erros para isso, criei uma 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();
  }

}

Esse controlador é estendido pela classe do controlador que faz o trabalho, algo como isto:

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 você chama a solicitação assim:

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

O hash do token é gerado por JSession :: getFormToken (). Portanto, a chamada completa completa pode ser assim:

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

O segundo parâmetro é definido como "false" para que possamos usá-lo em chamadas javascript sem reescrever xml.

7
Harald Leithner

Se você tem 100% de certeza de que não há plug-ins de terceiros que adicionem saída de Javascript, um json_encode puro funciona.

Mas ... por exemplo, o JomSocial adiciona "" a todo o site.

Então ... um truque útil, envolva json_encode com tags e processe-o no lado do Javascript.

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

Você pode acessar um controlador diretamente usando o nome do controlador na tarefa:

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

chamará: controller.raw.php (o retorno é bruto)

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

chama: controller.php (o retorno é html se você não usar die;)

3
Dennis Heiden