ฉันกำลังพัฒนาองค์ประกอบที่กำหนดเองสำหรับ Joomla! 3.x และต้องการโทร AJAX ภายในเพื่อเรียกข้อมูลบางอย่าง วิธีที่เหมาะสมในการทำคืออะไร?
ฉันกำลังพัฒนาองค์ประกอบที่กำหนดเองสำหรับ Joomla! 3.x และต้องการโทร AJAX ภายในเพื่อเรียกข้อมูลบางอย่าง วิธีที่เหมาะสมในการทำคืออะไร?
คำตอบ:
โปรดทราบว่าคำตอบนี้มีอายุสองสามปีแล้วและไม่ได้รับการอัปเดต อย่าลังเลที่จะแก้ไข / แสดงความคิดเห็นหากคุณคิดว่าบางสิ่งไม่ถูกต้องอีกต่อไป
แทบจะไม่มีวิธีที่เป็นทางการในการจัดการกับสิ่งนี้มันขึ้นอยู่กับความซับซ้อนและจำนวนที่คุณต้องการใช้รูปแบบ MVC ในการทำงาน
ด้านล่างนี้เป็นวิธีแก้ปัญหาที่เป็นไปได้สิ่งที่ควรใช้กับ Joomla 2.5 และ 3.x ไม่มีการแสดงรหัสสำหรับงานคัดลอก - วาง แต่เป็นแนวคิดทั่วไป
ก่อน Joomla! 3.2 componentสิ่งเดียวที่คุณจำเป็นต้องใช้ตัวอย่างด้านล่างนี้เป็น หลังจาก Joomla 3.2 (สำหรับงานที่มีความซับซ้อนต่ำ) คุณสามารถจัดการการร้องขอจากโมดูลและปลั๊กอิน
คุณURLสำหรับงานที่ต้องการที่จะมีลักษณะเช่นนี้
index.php?option=com_similar&task=abc&format=raw
คุณกว่าสร้างตัวควบคุมที่จะใช้มุมมองสมมติว่าAbcจะมีไฟล์ view.raw.html (เหมือนกับไฟล์มุมมองปกติ)
ด้านล่างคุณมีรหัสสำหรับสร้างการตอบกลับ HTML แบบดิบ:
/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";
หมายเหตุ: นี่เป็นวิธีแก้ปัญหาที่ฉันจะใช้ถ้าฉันต้องส่งคืน HTML (มันสะอาดกว่าและติดตามตรรกะของ Joomla!) สำหรับการส่งคืนข้อมูล JSON แบบง่าย ๆ ดูด้านล่างวิธีใส่ทุกอย่างในคอนโทรลเลอร์
หากคุณส่งคำขอ Ajax ไปที่ผู้ควบคุมย่อยเช่น:
index.php?option=com_similar&controller=abc&format=raw
กว่าชื่อ subcontroller คุณ (สำหรับมุมมองดิบ) abc.raw.phpจะต้องมีการ
ซึ่งหมายความว่าคุณจะ / อาจมีผู้ควบคุมบัญชีย่อย 2 คนชื่อ Abc
ถ้าคุณกลับ JSON ก็อาจทำให้ความรู้สึกที่จะใช้และformat=json abc.json.phpใน Joomla 2.5 ฉันมีปัญหาบางอย่างในการรับตัวเลือกนี้ให้ทำงาน (อย่างใดผลลัพธ์เสียหาย) ดังนั้นฉันจึงใช้ raw
หากคุณต้องการสร้างการตอบสนอง JSON ที่ถูกต้องให้ตรวจสอบหน้าเอกสารการสร้างเอาต์พุต 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);
โดยทั่วไปแล้วคุณจะใส่รหัสนี้ในตัวควบคุม (คุณจะเรียกรูปแบบที่จะส่งคืนข้อมูลที่คุณเข้ารหัส - สถานการณ์ทั่วไปมาก) หากคุณจำเป็นต้องดำเนินการเพิ่มเติมคุณยังสามารถสร้างมุมมอง JSON (view.json.php) ซึ่งคล้ายกับตัวอย่าง raw
ตอนนี้คำขอ Ajax ใช้งานได้อย่าเพิ่งปิดหน้านี้ อ่านด้านล่าง.
อย่าลืมตรวจสอบคำขอปลอม JSession::checkToken()เข้ามามีประโยชน์ที่นี่ อ่านเอกสารเกี่ยวกับวิธีเพิ่มการต่อต้านการปลอมแปลง CSRF ในแบบฟอร์ม
อาจเกิดขึ้นได้หากคุณไม่ส่งชื่อภาษาในคำขอ Joomla จะไม่แปลสตริงภาษาที่คุณต้องการ
ลองพิจารณาต่อท้าย lang param กับคำขอของคุณ (เช่น&lang=de)
ใหม่ใน Joomla 3.2! - ช่วยให้คุณสามารถจัดการคำขอโดยไม่ต้องสร้างส่วนประกอบ
Joomla! Ajax Interface - Joomla ตอนนี้ให้วิธีที่มีน้ำหนักเบาในการจัดการคำขอ Ajax ในปลั๊กอินหรือโมดูล คุณอาจต้องการใช้ Joomla! Ajax Interface หากคุณยังไม่มีส่วนประกอบหรือถ้าคุณต้องการที่จะขอจากโมดูลที่มีอยู่แล้ว
JRequestอะไร มันเลิกใช้แล้วหาก$this->inputฉันใช้ v3.x
                    JRequestผมจ่าหน้าความกังวลของคุณเกี่ยวกับ ขอบคุณ
                    Valid JSON Responseส่วน
                    นี่เป็นคำตอบที่ล่าช้าสำหรับคำถามที่ได้รับคำตอบเป็นอย่างดีนี้ แต่ฉันต้องการเพิ่มโซลูชันการไล่ล่าสำหรับผู้ที่ต้องการวิธีง่าย ๆ ในการเข้าถึงข้อมูลส่วนประกอบของพวกเขาด้วยการโทร AJAX
ด้วยทุกรุ่น Joomla, ความเป็นไปได้ของบุคคลที่สามและแฮ็กที่ฉันพบในช่วงเวลาหลายวันของ googling นี่เป็นวิธีที่ง่ายที่สุดที่ฉันสามารถหาได้ - และข้อเสนอแนะได้รับการชื่นชมอย่างแน่นอน
executeให้กับคอนโทรลเลอร์หลักที่มีอยู่ของฉันURL สำหรับโทร / สั่งงาน:
www.mysite.com/index.php?option=com_example&task=ForAjax.mytaskname
แก้ไขตัวควบคุมหลัก \ 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 \ 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();
    }
}
แสดงผล JSON เอาต์พุต
{
    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"
    }
}
              คำตอบ Valentin เป็นสิ่งที่ดี แต่ค่อนข้างซับซ้อนเกินไปหากคุณต้องทำคือเพิ่ม ajax 1 หรือ 2 สายไปยังส่วนประกอบที่สร้างขึ้นแล้ว มันเป็นไปได้ที่ดีที่สุดที่จะได้รับไปด้วยไม่ได้ทำแยกต่างหากcontroller.raw.phpหรือview.raw.phpไฟล์
ในการโทร ajax นี้
index.php?format=raw&option=com_example&controller=job&task=keep_alive&tokenhash=1
ในส่วนควบคุม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();
    }
}
              คำตอบของ Valentin นั้นดี
ฉันชอบคอนโทรลเลอร์ json ที่จัดการการเข้ารหัสและการจัดการข้อผิดพลาดสำหรับสิ่งนี้ฉันสร้างคลาสฐาน 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();
  }
}
คอนโทรลเลอร์นี้ขยายเพิ่มโดยคลาสคอนโทรลเลอร์ที่ทำงานได้ดังนี้:
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();
  }
}
และคุณเรียกคำขอเช่นนี้:
index.php?option=com_component&task=address.get&format=json&id=1234&tokenhash=1
โทเค็นแฮชสร้างโดย JSession :: getFormToken () ดังนั้นการโทรที่สมบูรณ์อาจมีลักษณะเช่นนี้:
$link = JRoute::_('index.php?option=com_component&task=address.get&format=json&id=1234&'.JSession::getFormToken().'=1', false);
พารามิเตอร์ที่สองถูกตั้งค่าเป็น "false" เพื่อให้เราสามารถใช้สิ่งนี้ในการเรียกใช้จาวาสคริปต์โดยไม่ต้องเขียน xml อีกครั้ง
JResponseJsonคลาสนี้จัดการมันล่ะ?
                    หากคุณแน่ใจว่า 100% ไม่มีปลั๊กอินของบุคคลที่สามที่เพิ่มเอาต์พุต Javascript ใด ๆ json_encode ล้วนๆก็ใช้ได้
แต่ ... ตัวอย่างเช่น JomSocial เพิ่ม "" ในเว็บไซต์ทั้งหมด
ดังนั้น ... เคล็ดลับที่มีประโยชน์ห่อ json_encode ด้วยแท็กและประมวลผลทางด้าน Javascript
echo '@START@' . json_encode(...) . '@END@';
              คุณสามารถเข้าถึงคอนโทรลเลอร์ได้โดยตรงโดยใช้ชื่อคอนโทรลเลอร์ในงาน:
index.php?option=com_similar&task=controller.abc&format=raw
จะโทร: controller.raw.php (return เป็น raw)
index.php?option=com_similar&task=controller.abc
จะโทร: controller.php (return เป็น html ถ้าคุณไม่ได้ใช้die;)