如何从 Moodle 换毛模板中调用 PHP 函数?

huangapple go评论72阅读模式
英文:

How to call a PHP function from Moodle mustache template?

问题

我正在尝试通过下拉菜单为 Moodle 区块插件内的课程构建一个筛选功能。根据我所了解的,应该按以下方式进行:

  1. 在模板中使用 select 元素
  2. 在 js 文件中处理 select 元素的 onchange 事件
  3. 从事件处理程序调用带有查询参数的 PHP 文件
  4. 在 PHP 函数中使用查询参数

到目前为止,我已成功实现了这个方法的前两个步骤,但是步骤 3 和 4 还没有完成。

当使用 .load() 函数调用带有查询参数的 PHP 文件时,它不会重定向到该页面,但直接在浏览器中打开 URL 时却有效。

为了筛选课程,我编写了一个 controller.php 文件来处理数据库请求。控制器在我的插件基础文件中是必需的。但是当我调用基础文件时,它显示它缺少它继承的 block_base 类。

现在我想知道我是否犯了错误,或者我是否选择了错误的方法。任何帮助都将不胜感激。

我使用了 这个答案 来帮助实现这个功能。

以下是我的代码:

filter.mustache

<select name="language-select" data-action="language-select">
  {{#languages}}
    <option value="{{.}}">{{.}}</option>
  {{/languages}}
</select>

filter.js

window.onload = init;

function init() {
    /* 加载基础插件文件并将语言作为查询参数发送 */
    $('[data-action="language-select"]').change(function() {
        console.log($('[data-action="language-select"]').val());
        $('[data-action="language-select"]').load('/blocks/course_overview_page/block_course_overview_page.php?language=' + $('[data-action="language-select"]').val());
    });
}

block_course_overview_page.php

require_once(__DIR__ . '/db/controller.php');
require_once($CFG->libdir . '/pagelib.php');

class block_course_overview_page extends block_base {
  public function get_content() {
    global $CFG, $OUTPUT, $PAGE;

    if ($this->content !== null) {
      return $this->content;
    }

    $this->content = new stdClass();

    /* 加载处理事件的 js 脚本 */
    $PAGE->requires->js(new moodle_url('/blocks/course_overview_page/js/filter.js'));

    $languageoptions = get_languages();

    /* 从查询参数获取语言 */
    $selectedlanguage = optional_param('language', 0, PARAM_INT);

    if ($selectedlanguage) {
      get_filtered_courses($selectedlanguage);
    }

    /* 数据对象用于包装模板内迭代的课程列表 */
    $data = (object)[
      'courses' => array_values(get_all_courses_for_overview()),
      'languages' => $languageoptions
    ];

    /* 渲染模板并传递数据 */
    $this->content->text = $OUTPUT->render_from_template('block_course_overview_page/cards', $data);

    return $this->content;
  }
}
英文:

I am trying to build a filter function via dropdown menus for courses inside a Moodle block plugin. From what I've learned, the way to go would be to

  1. Use select element in template
  2. Handle select element's onchange event in js file
  3. Call PHP file with query param from event handler
  4. Use query param in PHP function

So far I have succeeded to implement this approach apart from step 3 and 4.

When calling the PHP file with the load function .load(&#39;/blocks/course_overview_page/block_course_overview_page.php?language=&#39; + $(&#39;[data-action=&quot;language-select&quot;]&#39;).val()), it does not redirect to that page, but it works when I directly open the URL in the browser.

To filter the courses I have written a controller.php file to handle database requests. The controller is required in my plugin base file. But when I call the base file it displays the error that it's missing the block_base class that it extends from.

Now I wonder if I made a mistake or if I even chose the wrong approach. Any help is appreciated.

I used this answer to help implement this.

Here is my code:

filter.mustache

&lt;select name=&quot;language-select&quot; data-action=&quot;language-select&quot;&gt;
  {{#languages}}
    &lt;option value=&quot;{{.}}&quot;&gt;{{.}}&lt;/option&gt;
  {{/languages}}
&lt;/select&gt;

filter.js

window.onload = init;

function init() {

    /* load base plugin file and send language as query param */
    $(&#39;[data-action=&quot;language-select&quot;]&#39;).change(function() {
        console.log($(&#39;[data-action=&quot;language-select&quot;]&#39;).val());
        $(&#39;[data-action=&quot;language-select&quot;]&#39;).load(&#39;/blocks/course_overview_page/block_course_overview_page.php?language=&#39; + $(&#39;[data-action=&quot;language-select&quot;]&#39;).val());
    });

}

block_course_overview_page.php

require_once(__DIR__ . &#39;/db/controller.php&#39;);
require_once($CFG-&gt;libdir . &#39;/pagelib.php&#39;);

class block_course_overview_page extends block_base {
  public function get_content() {
    global $CFG, $OUTPUT, $PAGE;

    if ($this-&gt;content !== null) {
      return $this-&gt;content;
    }

    $this-&gt;content = new stdClass();

    /* load js script to handle events */
    $PAGE-&gt;requires-&gt;js(new moodle_url(&#39;/blocks/course_overview_page/js/filter.js&#39;));

    $languageoptions = get_languages();

    /* get language from query params */
    $selectedlanguage = optional_param(&#39;language&#39;,  0,  PARAM_INT);

    if ($selectedlanguage) {
      get_filtered_courses($selectedlanguage);
    }

    /* data object is necessary to wrap courses list for iteration inside template */
    $data = (object)[
      &#39;courses&#39; =&gt; array_values(get_all_courses_for_overview()),
      &#39;languages&#39; =&gt; $languageoptions
    ];

    /* render template and pass data */
    $this-&gt;content-&gt;text = $OUTPUT-&gt;render_from_template(&#39;block_course_overview_page/cards&#39;, $data);

    return $this-&gt;content;
  }

答案1

得分: 1

使用 Moodle Fragments API 通过 JS 调用 Mustache 中的 PHP 函数。

有关 Fragments 的更多信息,请阅读官方文档。
https://docs.moodle.org/dev/Fragment

以下是在 Moodle 中从 Mustache 调用 PHP 函数的示例。

  1. 在你的组件/插件的 lib.php 文件中创建一个 fragment 输出函数

替换你的组件和函数名称。

function YOUR_COMPONENT_output_fragment_FUNCTIONNAME() {
    // 你的函数代码在这里。
}

在你的情况下,应该是

function block_course_overview_output_fragment_filter($args) {
    // 你的代码在这里。
    $language = $args['language'];
}
  1. 从你的 mustache 文件中调用 fragment。在 filter.js 中包含你的 js 代码。

从 js 或 mustache 中调用 fragment。

Fragment.loadFragment("ComponentName", "PHPFunctionName", ContextID, args);

将以下代码添加到你的 mustache 文件的底部。

{{#js}}
require(['jquery', 'core/fragment'], function($, Fragment) {

    window.onload = init;

    function init() {
        /* 加载基础插件文件并将语言作为查询参数发送 */
        $('[data-action="language-select"]').change(function() {
            console.log($('[data-action="language-select"]').val());
            // 在模板渲染期间传递系统上下文 ID。
            var contextid = "{{contextid}}";
            var args = {
                "language": $('[data-action="language-select"]').val()
            };
            Fragment.loadFragment('block_course_overview', 'filter', contextid, args).then((html, js) => {
                // 你可以在变量 "html" 中获取返回的数据
                $('[data-action="language-select"]').html(html);
            })
        });
    }
})
{{/js}}
英文:

Use the Moodle Fragments API to call the php function from Mustache using JS.
For more about fragments. Please read the official documention.
https://docs.moodle.org/dev/Fragment

Here the example to call PHP function from Mustache in Moodle.

  1. Create a fragment output function in your component/plugin lib.php

Replace your component and function name.

function YOUR_COMPONENT_output_fragment_FUNCTIONNAME() {
   // Your function code goes here.
}

In your case, it should be

function block_course_overview_output_fragment_filter($args) {
  // Your code goes here.
  $language = $args[&#39;language];
}
  1. Call the fragment from your mustache. Included your js code from filter.js.

Fragment call from js or mustache.

Fragment.loadFragment(&quot;ComponentName&quot;, &quot;PHPFunctionName&quot;, ContextID, args);

Add the below code to the bottom of your mustache file.

{{#js}}
require([&#39;jquery&#39;, &#39;core/fragment&#39;], function($, Fragment) {

    window.onload = init;

    function init() {
        /* load base plugin file and send language as query param */
        $(&#39;[data-action=&quot;language-select&quot;]&#39;).change(function() {
            console.log($(&#39;[data-action=&quot;language-select&quot;]&#39;).val());
            // Pass the system context id during the template render.
            var contextid = &quot;{{contextid}}&quot;;
            var args = {
                &quot;language&quot;: $(&#39;[data-action=&quot;language-select&quot;]&#39;).val()
            };
            Fragment.loadFragment(&#39;block_course_overview&#39;, &#39;filter&#39;, contextid, args).then((html, js) =&gt; {
                // You can get the return data in variable &quot;html&quot;
                $(&#39;[data-action=&quot;language-select&quot;]&#39;).html(html);
            })
        });
    }
})
{{/js}}

答案2

得分: 0

以下是已翻译好的部分:

  1. 当前首选的方法(大多数时候核心使用的方法)是:

  2. 为您的插件创建一个 Web 服务(或者如果有合适的核心 Web 服务,则使用它)。

  3. 在您的插件 JavaScript 中(最好使用 ES6 语法编写,不使用 jQuery),导入 core/ajax 和 core/templates。例如:

import Templates from "core/templates";
import Ajax from "core/ajax";
  1. 从 JavaScript 调用您的服务并对结果执行一些操作(例如为视图渲染模板):
const request = {
    methodname: 'name_of_the_web_service',
    args: { some: params, go: here }
};

Ajax.call([request])[0]
    .then((result) => {
        return Templates.render('your_plugin/your_template_name', result);         
    })
    .then(({ html, js }) => {
        // 对已渲染的 HTML 和 JavaScript 执行一些操作。
    });

请注意,代码中的引号已根据需要进行了修复,以使其保持语法正确。

英文:

The preferred way to do this currently (and the way core does this most of the time):

  1. Create a web service for your plugin (or use an existing core web service if one is suitable).

  2. In your plugin js (which ideally would be written using ES6 syntax and would not be using JQuery), import core/ajax and core/templates. E.g.

    import Templates from &quot;core/templates&quot;;
    import Ajax from &quot;core/ajax&quot;;
    
  3. Call your service from the JS and do something with the result (like render a template for your view):

     const request = {
         methodname: &#39;name_of_the_web_service&#39;,
         args: {some: params, go: here}
     };
    
     Ajax.call([request])[0]
         .then((result) =&gt; {
             return Templates.render(&#39;your_plugin/your_template_name&#39;, result);         
                 .then(({html, js}) =&gt; {
                     // Do something with the rendered html and js.
                 });
         });
    

huangapple
  • 本文由 发表于 2023年5月10日 20:43:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76218582.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定