Apa cara yang tepat untuk melakukan panggilan komponen AJAX?


40

Saya sedang mengembangkan komponen khusus untuk Joomla! 3.x dan ingin membuat panggilan AJAX di dalamnya untuk mengambil beberapa data. Apa cara yang tepat untuk melakukannya?


Nasihat penting adalah jangan pernah memutus aliran Joomla. Misalnya beberapa komponen meminta ajax pada acara AfterRoute dan melakukan tugas dan membunuh permintaan itu sendiri. Ini menyebabkan kesalahan yang sulit di-debug.
Shyam

Maksud Anda - jangan tutup Aplikasi? Bisakah Anda menjelaskan lebih lanjut?
Dmitry Rekun

Ya, jika joomla menutup aplikasi, itu akan menjadi yang terbaik. Jadi ekstensibilitas ekstensi Anda akan dipertahankan.
Shyam

Masih belum mengerti sepenuhnya. Yang saya bicarakan adalah $ app-> close () di controller. Apakah maksud Anda sama? :)
Dmitry Rekun

Ya, membicarakan hal yang sama. Mengapa kita harus menutup aplikasi di controller, sementara yang sama akan dilakukan oleh joomla sendiri.
Shyam

Jawaban:


47

HARAP DICATAT BAHWA JAWABAN INI sudah berusia beberapa tahun dan tidak diperbarui. Jangan ragu untuk mengedit / berkomentar jika Anda berpikir ada sesuatu yang tidak tepat lagi.

Abstrak

Hampir tidak ada cara resmi untuk menangani hal ini, ini sangat tergantung pada kompleksitas dan seberapa banyak Anda ingin bergantung pada pola MVC untuk melakukan pekerjaan.

Di bawah ini adalah beberapa solusi yang mungkin apa yang harus bekerja di Joomla 2.5 dan 3.x. Kode ini tidak disajikan untuk pekerjaan salin-rekat melainkan sebagai gagasan umum.

Sebelum ke Joomla! 3.2 satu-satunya hal yang perlu Anda gunakan contoh di bawah ini adalah a component. Setelah Joomla 3.2 (untuk tugas-tugas kompleks yang lebih rendah) Anda dapat menangani permintaan dari modul dan plugin.


Respons HTML umum (mengikuti MVC lama)

URL Anda untuk tugas harus terlihat seperti ini:

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

Anda daripada membuat pengontrol yang akan menggunakan tampilan, katakanlah Abc, yang akan berisi file view.raw.html (identik dengan file tampilan normal).

Di bawah ini Anda memiliki kode untuk menghasilkan respons HTML mentah:

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

Catatan: Ini adalah solusi yang akan saya gunakan jika saya harus mengembalikan HTML (lebih bersih dan mengikuti logika Joomla). Untuk mengembalikan data JSON sederhana, lihat di bawah ini cara meletakkan semuanya di controller.

Subkontroler

Jika Anda membuat permintaan Ajax ke subkontroller , seperti:

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

Daripada perlu nama subkontroler (untuk tampilan mentah) abc.raw.php.

Ini juga berarti bahwa Anda akan / mungkin memiliki 2 subkontrol bernama Abc.

Jika Anda mengembalikan JSON, mungkin masuk akal untuk menggunakan format=jsondan abc.json.php. Di Joomla 2.5. Saya punya beberapa masalah untuk mendapatkan opsi ini untuk bekerja (entah bagaimana hasilnya rusak), jadi saya menggunakan mentah.


Respon JSON yang valid (mengikuti MVC baru / lama)

Jika Anda perlu membuat respons JSON yang valid , lihat halaman dokumen Menghasilkan 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);

Anda biasanya akan meletakkan kode ini di controller (Anda akan memanggil model yang akan mengembalikan data yang Anda encode - skenario yang sangat umum). Jika Anda perlu melangkah lebih jauh, Anda juga dapat membuat tampilan JSON (view.json.php), mirip dengan contoh mentah.


Keamanan

Sekarang setelah permintaan Ajax berfungsi, jangan tutup halamannya. Baca di bawah.

Jangan lupa untuk memeriksa permintaan pemalsuan. JSession::checkToken()berguna di sini. Baca dokumentasi di Bagaimana menambahkan CSRF anti-spoofing ke bentuk


Situs multibahasa

Mungkin saja terjadi jika Anda tidak mengirim nama bahasa dalam permintaan, Joomla tidak akan menerjemahkan string bahasa yang Anda inginkan.

Pertimbangkan untuk menambahkan entah bagaimana lang param ke permintaan Anda (seperti &lang=de).


Joomla! Antarmuka Ajax

Baru di Joomla 3.2! - Memungkinkan Anda membuat permintaan handle tanpa membangun komponen

Joomla! Ajax Interface - Joomla sekarang menyediakan cara yang ringan untuk menangani permintaan Ajax dalam plugin atau modul. Anda mungkin ingin menggunakan Joomla! Ajax Interface jika Anda belum memiliki komponen atau jika Anda perlu membuat permintaan dari modul yang sudah Anda miliki.


9
Jawaban kualitas terbaik yang pernah saya lihat di joomla.stackexchange.com sejauh ini - dilakukan dengan baik dan cara meningkatkan standar. Kerja bagus!
NivF007

Setuju, tapi bagaimana JRequest? Itu sudah tidak digunakan lagi $this->inputkarena saya menggunakan v3.x?
Dmitry Rekun

1
Saya membahas kekhawatiran Anda tentang JRequest. Terima kasih
Valentin Despa

3
Jawaban yang bagus, hanya ingin menyebutkan bahwa ada kelas Joomla sejak 3.1 yang menangani output JSON: API , Usage
fruppel

@ fl0r yeap, Valentin menyebutkannya di Valid JSON Responsebagian.
Dmitry Rekun

20

Ini adalah jawaban yang terlambat untuk pertanyaan yang dijawab dengan sangat baik ini, tetapi saya ingin menambahkan solusi cut-to-the-chase ini bagi mereka yang hanya membutuhkan cara sederhana untuk mendapatkan data komponen mereka dengan panggilan AJAX.

Dengan semua versi Joomla, kemungkinan pihak ketiga, dan peretasan yang saya temukan selama beberapa hari di Google, ini adalah pendekatan paling sederhana yang dapat saya lakukan - dan umpan balik sangat dihargai.

  1. Menambahkan fungsi executeke pengontrol utama saya yang ada
  2. Membuat subkontrol dengan fungsi publik untuk tugas yang ingin saya panggil dengan AJAX
  3. Menggunakan kelas dibangun di Joomla JResponseJson untuk menangani output ( itu sangat bagus! )

URL untuk memanggil / menjalankan tugas:

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

Pengontrol Utama Yang Dimodifikasi \ 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);
        }
    }
}

Subkontroller Baru \ 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 yang Diberikan

{
    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

Jawaban Valentin baik tetapi sedikit terlalu rumit jika yang perlu Anda lakukan adalah menambahkan 1 atau 2 panggilan ajax ke komponen yang sudah dibangun. Sangat mungkin untuk pergi tanpa membuat file controller.raw.phpatau terpisah view.raw.php.

Untuk melakukan panggilan ajax ini

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

Di jobsubkontroller

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

Jawaban Valentin bagus.

Saya lebih suka pengontrol json yang menangani pengodean dan penanganan kesalahan untuk ini saya membuat kelas dasar 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();
  }

}

Pengontrol ini diperluas oleh kelas pengontrol yang melakukan pekerjaan, seperti ini:

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

dan Anda memanggil permintaan seperti ini:

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

Hash token yang dihasilkan oleh JSession :: getFormToken (). Jadi panggilan lengkap yang lengkap bisa seperti ini:

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

Parameter kedua diatur ke "false" sehingga kita dapat menggunakan ini dalam panggilan javascript tanpa xml rewrite.


1
Bagus, tapi mengapa tidak menggunakan JResponseJsonkelas untuk menanganinya?
Dmitry Rekun

JResponseJson diperkenalkan di Joomla 3
Anibal

Tidak ada Joomla SE di mana saya bisa bertanya;)
Harald Leithner

4

Jika Anda 100% yakin tidak ada plugin pihak ketiga yang menambahkan output Javascript apa pun, json_encode murni berfungsi OK.

Tapi ... misalnya JomSocial menambahkan "" ke seluruh situs.

Jadi ... trik praktis, bungkus json_encode dengan tag, dan proses di sisi Javascript.

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

3

Anda dapat mengakses pengontrol secara langsung dengan menggunakan nama pengontrol di tugas:

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

akan memanggil: controller.raw.php (return is raw)

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

akan memanggil: controller.php (return adalah html jika Anda tidak menggunakan die;)

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.