it-swarm-id.com

Apa cara yang tepat untuk melakukan panggilan komponen AJAX?

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?

40
Dmitry Rekun

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

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 Anda butuhkan untuk menggunakan contoh di bawah ini adalah 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 lawas)

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 Anda ke subkontrol , seperti:

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

Daripada nama subkontroler Anda (untuk tampilan mentah) harus 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=json Dan 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 menghasilkan respons JSON yang valid , periksa 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 tentang Cara menambahkan CSRF anti spoofing ke formulir


Situs multibahasa

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

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


Joomla! Antarmuka Ajax

Baru di Joomla 3.2! - memungkinkan Anda untuk 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.

47
Valentin Despa

Ini adalah jawaban terakhir untuk pertanyaan yang dijawab dengan sangat baik ini, tetapi saya ingin menambahkan solusi cut-to-the-chase ini bagi mereka yang hanya perlu 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 execute ke 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 benar-benar bagus! )

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

Subcontroller 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 Diubah

{
    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

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 memisahkan controller.raw.php atau view.raw.php file.

Untuk melakukan panggilan ajax ini

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

Dalam subkontroller 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

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.

7
Harald Leithner

Jika Anda 100% yakin tidak ada plugin pihak ketiga menambahkan output Javascript, 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 '@[email protected]' . json_encode(...) . '@[email protected]';
4
Anibal

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

3
Dennis Heiden