it-swarm-vi.com

Cách thích hợp để thực hiện cuộc gọi AJAX trong thành phần là gì?

Tôi đang phát triển một thành phần tùy chỉnh cho Joomla! 3.x và muốn thực hiện một cuộc gọi AJAX bên trong nó để lấy một số dữ liệu. Cách thích hợp để làm điều đó là gì?

40
Dmitry Rekun

XIN LƯU Ý R ANNG TRẢ LỜI NÀY đã vài năm tuổi và chưa được cập nhật. Hãy chỉnh sửa/bình luận nếu bạn nghĩ rằng một cái gì đó không còn chính xác.

Trừu tượng

Hầu như không có cách nào thực sự chính thức để giải quyết vấn đề này, nó phụ thuộc nhiều vào độ phức tạp và mức độ bạn muốn dựa vào mẫu MVC để thực hiện công việc.

Dưới đây là một số giải pháp khả thi những gì nên hoạt động trong Joomla 2.5 và 3.x. Mã này không được trình bày cho một công việc sao chép - dán mà là một ý tưởng chung.

Trước Joomla! 3.2 điều duy nhất bạn cần sử dụng các ví dụ dưới đây là component. Sau Joomla 3.2 (đối với các tác vụ phức tạp thấp hơn), bạn có thể xử lý yêu cầu từ các mô-đun và plugin.


Phản hồi HTML chung (theo MVC kế thừa)

[~ # ~] url [~ # ~] của bạn cho tác vụ cần giống như thế này:

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

Bạn hơn là tạo bộ điều khiển sẽ sử dụng chế độ xem, giả sử Abc, sẽ chứa tệp view.raw.html (giống hệt với tệp xem bình thường).

Dưới đây bạn có mã để tạo phản hồi HTML thô:

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

/lượt xem/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);
    }
}

/lượt xem/abc/tmpl/default.php

<?php

echo "Hello World from /views/abc/tmpl/default.php";

Lưu ý: Đây là giải pháp tôi sẽ sử dụng nếu tôi phải trả về HTML (nó sạch hơn và tuân theo logic Joomla). Để trả về dữ liệu JSON đơn giản, hãy xem bên dưới cách đặt mọi thứ vào bộ điều khiển.

Kiểm soát viên

Nếu bạn thực hiện yêu cầu Ajax của mình với một bộ điều khiển con , như:

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

Hơn tên của trình điều khiển con của bạn (đối với chế độ xem thô) cần phải là abc.raw.php.

Điều này cũng có nghĩa là bạn sẽ/có thể có 2 người điều khiển phụ tên là Abc.

Nếu bạn trả về JSON, có thể có ý nghĩa khi sử dụng format=jsonabc.json.php. Trong Joomla 2.5. Tôi có một số vấn đề khiến tùy chọn này hoạt động (bằng cách nào đó đầu ra bị hỏng), vì vậy tôi đã sử dụng thô.


Phản hồi JSON hợp lệ (theo MVC mới/kế thừa)

Nếu bạn cần tạo phản hồi JSON hợp lệ , hãy xem trang tài liệu Tạo đầu ra 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);

Bạn thường sẽ đặt mã này vào bộ điều khiển (bạn sẽ gọi một mô hình sẽ trả về dữ liệu bạn mã hóa - một kịch bản rất phổ biến). Nếu bạn cần đưa nó đi xa hơn, bạn cũng có thể tạo chế độ xem JSON (view.json.php), tương tự như ví dụ thô.


Bảo vệ

Bây giờ yêu cầu Ajax đang hoạt động, chưa đóng trang. Đọc dưới đây.

Đừng quên kiểm tra các giả mạo yêu cầu. JSession::checkToken() có ích ở đây. Đọc tài liệu về Cách thêm CSRF chống giả mạo vào biểu mẫ


Trang web đa ngôn ngữ

Có thể xảy ra là nếu bạn không gửi tên ngôn ngữ trong yêu cầu, Joomla sẽ không dịch các chuỗi ngôn ngữ bạn muốn.

Xem xét nối thêm bằng cách nào đó lang param vào yêu cầu của bạn (như &lang=de).


Joomla! Giao diện Ajax

Mới trong Joomla 3.2! - cho phép bạn thực hiện các yêu cầu xử lý mà không cần xây dựng một thành phần

Joomla! Ajax Interface - Joomla hiện cung cấp một cách nhẹ nhàng để xử lý yêu cầu Ajax trong một plugin hoặc mô-đun. Bạn có thể muốn sử dụng Joomla! Giao diện Ajax nếu bạn chưa có thành phần hoặc nếu bạn cần thực hiện các yêu cầu từ mô-đun mà bạn đã có.

47
Valentin Despa

Đây là một câu trả lời muộn cho câu hỏi được trả lời rất tốt này, nhưng tôi muốn thêm giải pháp cắt xén này cho những người chỉ cần một cách đơn giản để lấy dữ liệu của các thành phần của họ bằng một cuộc gọi AJAX.

Với tất cả các phiên bản Joomla, khả năng của bên thứ 3 và các bản hack mà tôi đã tìm thấy trong nhiều ngày làm việc, đây là cách tiếp cận đơn giản nhất tôi có thể đưa ra - và phản hồi được DEFINATELY đánh giá cao.

  1. Đã thêm chức năng execute vào bộ điều khiển chính hiện có của tôi
  2. Tạo một bộ điều khiển con với chức năng công khai cho (các) tác vụ mà tôi muốn gọi bằng AJAX
  3. Đã sử dụng lớp Joomla JResponseJson tích hợp để xử lý đầu ra ( thật sự rất hay! )

RL để gọi/thực hiện tác vụ :

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

Bộ điều khiển chính đã sửa đổi\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);
        }
    }
}

Bộ điều khiển mới\com_example\controls\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();
    }
}

Kết xuất JSON được kết xuất

{
    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

Câu trả lời của Valentin là tốt nhưng hơi phức tạp một chút nếu tất cả những gì bạn cần làm là thêm 1 hoặc 2 cuộc gọi ajax vào một thành phần đã được xây dựng. Hoàn toàn có thể thoát khỏi việc không tách rời controller.raw.php hoặc là view.raw.php các tập tin.

Để thực hiện cuộc gọi ajax này

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

Trong bộ điều khiển con 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

Câu trả lời của Valentin là tốt.

Tôi thích một bộ điều khiển json xử lý mã hóa và xử lý lỗi cho việc này Tôi đã tạo một lớp cơ sở 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();
  }

}

Bộ điều khiển này được mở rộng bởi lớp trình điều khiển thực hiện công việc, đại loại như thế này:

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

và bạn gọi yêu cầu như thế này:

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

Hàm băm token được tạo bởi JSession :: getFormToken (). Vì vậy, cuộc gọi hoàn chỉnh hoàn chỉnh có thể giống như thế này:

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

Tham số thứ hai được đặt thành "false" để chúng tôi có thể sử dụng tham số này trong các cuộc gọi javascript mà không cần viết lại xml.

7
Harald Leithner

Nếu bạn chắc chắn 100% không có plugin bên thrid nào thêm bất kỳ đầu ra Javascript nào, thì json_encode thuần hoạt động.

Nhưng ... ví dụ JomSocial thêm "" vào toàn bộ trang.

Vì vậy, ... một mẹo hữu ích, bọc json_encode bằng các thẻ và xử lý nó ở phía Javascript.

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

Bạn có thể truy cập bộ điều khiển trực tiếp bằng cách sử dụng tên bộ điều khiển trong tác vụ:

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

sẽ gọi: control.raw.php (trả về là raw)

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

sẽ gọi: controller.php (return là html nếu bạn không sử dụng die;)

3
Dennis Heiden