اضافه کردن سرویس وب به یک افزونه

Adding a web service to a plugin
Adding a web service to a plugin

Adding a web service to a plugin

 شروع سریع

مثال

نگاهی به web service plugin template بیندازید. این افزونه شامل تابع وب سرویس hello_world است. برای آسان کردن مراحل تست ، افزونه با یک کلاینت تست در پوشه client/ توزیع می شود.

ساختار فایل

ساختار فایل در دو متن زیر توضیح داده شده است:

آموزش

ما یک وب سرویس را درون افزونه محلی ایجاد خواهیم کرد. این سرویس شامل یک تابع وب سرویس (local_myplugin_create_groups($groups است. این تابع وب سرویس یک گروه درون ،یک دوره مودل ایجاد خواهد کرد.

نوشتن داکیومنت های خاص

قبل از شروع برنامه نویسی، بیایید نیازهایمان را مشخص کنیم.
مشخصات عملکردی – functional specification
(local_myplugin_create_groups ($ groups لیستی از گروه ها را به عنوان پارامتر می گیرد و گروه های مشابه را با شناسه ی (Id) جدیدشان باز می گرداند. اگر روند ایجاد یک گروه با موفقیت انجام نشود، تابع وارد یک استثناء می شود و هیچ ایجاد جدیدی اتفاق نخواهد افتاد.

مشخصات فنی – technical specification

  • تابع مرکزیِ تابع خارجی، ()groups_create_group را از group/lib.php/  فراخوانی خواهد کرد.
  • انواع پارامترها: لیستی از object ها. این object ها با id / name / courseid گروه هستند.
  • انواع مقادیر بازگشتی : لیستی ار objectها (گروه ها) به همراه شناسه (Id) آن ها.
  • قابلیت های کاربر برای بررسی: moodle / course: managegroups

نوشتن یک تست کلاینت ساده – Write a simple test client

اولین کدی را که باید انجام دهید، یک وب سرویس تست کلاینت است. شما اغلب use cases هایی (موارد کاربردی) را کشف می کنید که در مورد آن فکر نکردید. ما هیچ کد تست کلاینتی را در اینجا نشان نمی دهیم، بلکه شما باید برای ایجاد یک سرویس دهنده وب به اینجا مراجعه کنید.

معرفی خدمات

این مرحله اختیاری است. شما می توانید یک سرویس شامل هر نوع تابع وب سرویس را از قبل ایجاد کنید، به طوری که دیگر لازم نیست مدیر Moodle آن را انجام دهد. سرویس مورد نظرتان را به مسیر local/myplugin/db/services.php/ اضافه کنید.

$services = array( ‘mypluginservice’ => array(

//the name of the web service

‘functions’ => array (‘local_myplugin_create_groups’),

//web service functions of this service

‘requiredcapability’ => ”,

//if set, the web service user need this capability to access

//any function of this service. For example: ‘some/capability:specified’

‘restrictedusers’ =>0,

//if enabled, the Moodle administrator must link some user to this service //into the administration

‘enabled’=>1,

//if enabled, the service can be reachable on a default installation

)

);

توجه داشته باشید: برای یک مدیر امکان add/remove (اضافه کردن / حذف) تابع، از یک سرویس از قبل ساخته شده وجود ندارد.

معرفی تابع وب سرویس

شما باید تابع های وب سرویس را در فایل local/myplugin/db/services.php مشخص کنید. Web service API را دنبال کنید.

$functions = array(

‘local_myplugin_create_groups’ => array(

//web service function name

‘classname’ => ‘local_myplugin_external’,

//class containing the external function

‘methodname’ => ‘create_groups’,

//external function name

‘classpath’ => ‘local/myplugin/externallib.php’,

//file containing the class/external function

‘description’ => ‘Creates new groups.’,

//human readable description of the web service function

‘type’ => ‘write’,

//database rights of the web service function (read, write)

‘services’ => array(MOODLE_OFFICIAL_MOBILE_SERVICE)

// Optional, only available for Moodle 3.1 onwards. List of built-in services (by shortname) where the function will be included. Services created manually via the Moodle interface are not supported. ),

);

توابع وب سرویس باید با قوانین نامگذاری (naming convention) مطابقت داشته باشند.

تعریف توابع خارجی – Write the external function descriptions

هر تابع وب سرویس به یک تابع خارجی (External Function) نگاشت می شود. توابع خارجی در External functions API توضیح داده شده است. هر تابع خارجی با دو تابع دیگر که پارامترها را توصیف می کند و مقادیر را برمیگرداند نوشته شده است. توصیف توابع توسط سرورهای وب سرویس برای موارد زیر استفاده می شود:

  • اعتبارسنجی پارامترهای تابع وب سرویس
  • اعتبار سنجی مقادیر بازگشتی تابع وب سرویس
  • ساختن فایل WSDL یا داکیومنت پروتکل های دیگر

این دو تابع توصیفی در فایل و کلاس یکسان در فایل local/myplugin/db/services.php قرار دارند.

بنابراین برای تابع وب سرویس ()local_myplugin_create_groups ، ما نیار به نوشتن یک کلاس با نام local_myplugin_external  در فایل local/myplugin/externallib.php داریم. کلاس شامل موارد زیر خواهد بود:

  • (…)create_groups
  • ()create_groups_parameters
  • ()create_groups_return

()create_groups_parameters

require_once(“$CFG->libdir/externallib.php”);

class local_myplugin_external extends external_api {

/**

* Returns description of method parameters *

@return external_function_parameters

*/

public static function create_groups_parameters() {

return new external_function_parameters( array( ‘groups’ => new external_multiple_structure( new external_single_structure( array( ‘courseid’ => new external_value(PARAM_INT, ‘id of course’), ‘name’ => new external_value(PARAM_TEXT, ‘multilang compatible name, course unique’), ‘description’ => new external_value(PARAM_RAW, ‘group description text’), ‘enrolmentkey’ => new external_value(PARAM_RAW, ‘group enrol secret phrase’), ) ) ) ) );

}

یک تابع وب سرویس بدون پارامتر، یک تابع توصیف پارامتر مانند نمونه زیر دارد:

/** * Returns description of method parameters *

@return external_function_parameters

*/

public static function functionname_parameters()

{

return new external_function_parameters( array( //if I had any parameters, they would be described here. But I don’t have any, so this array is empty. ) );

}

پارامتر می تواند به شرح زیر باشد:

  • a list => external_multiple_structure
  • an object => external_single_structure
  • a primary type => external_value

تابع ()create_groups ، انتظار یک پارامتر با نام groups را دارد، بنابراین باید کد را به طریق زیر بنویسیم :

/** * Returns description of method parameters *

@return external_function_parameters

*/

public static function create_groups_parameters() {

return new external_function_parameters( array( ‘groups’ => … ) );

}

این پارامتر “groups” شامل لیستی از گروه ها است. بنابراین به این طریق خواهیم نوشت:

‘groups’ => new external_multiple_structure( … )

شیء (لیست) external_multiple_structure، می تواند با موارد زیر ساخته شود:

  • (external_multiple_structure (list
  • (external_single_structure (object
  • (external_value (primary type

برای تابع ما  ، external_single_structure بدین صورت خواهد بود:

new external_single_structure( array( ‘courseid’ => …, ‘name’ => …, ‘description’ => …, ‘enrolmentkey’ => …, ) )

چیزی که ما به دست می آوریم :

‘groups’ => new external_multiple_structure( new external_single_structure( array( ‘courseid’ => …, ‘name’ => …, ‘description’ => …, ‘enrolmentkey’ => …, ) ) )

هر گروه مقادیر، یک (external_value (primary type است:

  • courseid یک عدد صحیح است.
  • name یک رشته است. (فقط متن ، نه تگ)
  • description یک رشته است.( هر چیزی ممکن است باشد)
  • enrolmentkey یک رشته است.( هر چیزی ممکن است باشد)

آن ها را به توضیحات (description) اضافه می کنیم:

‘groups’ => new external_multiple_structure(

new external_single_structure(

array(

‘courseid’ => new external_value(PARAM_INT, ‘id of course’), //the second argument is a human readable description text. This text is displayed in the automatically generated documentation.

‘name’ => new external_value(PARAM_TEXT, ‘multilang compatible name, course unique’),

‘description’ => new external_value(PARAM_RAW, ‘group description text’),

‘enrolmentkey’ => new external_value(PARAM_RAW, ‘group enrol secret phrase’),

)

)

)

()create_groups_returns

این تابع شبیه ()create_groups_parameters است، اما به جای توصیف پارامترها ، مقادیر بازگشتی را توصیف می کند:

public static function create_groups_returns() {

return new external_multiple_structure( new external_single_structure( array( ‘id’ => new external_value(PARAM_INT, ‘group record id’), ‘courseid’ => new external_value(PARAM_INT, ‘id of course’), ‘name’ => new external_value(PARAM_TEXT, ‘multilang compatible name, course unique’), ‘description’ => new external_value(PARAM_RAW, ‘group description text’), ‘enrolmentkey’ => new external_value(PARAM_RAW, ‘group enrol secret phrase’), ) ) );

}

مقادیر موردنیاز، اختیاری یا پیش فرض – Required, Optional or Default value

یک مقدار می تواند VALUE_REQUIRED, VALUE_OPTIONAL و یا VALUE_DEFAULT  باشد. که اگر مشخص نشده باشد ، به صورت پیشفرض VALUE_REQUIRED در نظر گرفته می شود.

‘yearofstudy’ => new external_value(PARAM_INT, ‘year of study’,VALUE_DEFAULT, 1979),

  • VALUE_REQUIRED – اگر مقداری (value) وجود نداشته باشد -> سرور یک پیام خطا را نمایش می دهد.
  • VALUE_OPTIONAL – اگر مقداری (value) وجود نداشته باشد -> مقدار نادیده گرفته می شود. توجه کنید که VALUE_OPTIONAL نمی تواند برای پارامتر های سطح بالا (top level) استفاده شود، بلکه تنها می تواند درون آرایه / اشیا ( array/object) برای تعریف کلید (key definition) استفاده شود. اگر شما نیاز به پارامترهای سطح بالای اختیاری داشته باشید باید از VALUE_DEFAULT استفاده کنید.
  • VALUE_DEFAULT – اگر مقداری (value) وجود نداشته باشد -> مقدار پیش فرض استفاده می شود.

توجه داشته باشید : به دلیل اینکه برخی از پروتکل های وب سرویس در مورد تعداد و نوع پارامترها محدودیت هایی را در نظر می گیرند ، امکان تعیین پارامتر اختیاری به عنوان یکی از پارامترهای برتر برای یک تابع وجود ندارد. به عنوان مثال :

نمونه ای که جذاب نیست :

public static function get_biscuit_parameters()

{

return new external_function_parameters( array( ‘chocolatechips’ => new external_value(PARAM_BOOL, PARAM_REQUIRED), ‘glutenfree’ => new external_value(PARAM_BOOL, PARAM_DEFAULT, false), ‘icingsugar’ => new external_value(PARAM_BOOL, VALUE_OPTIONAL), // ERROR! top level optional parameter!!! ) );

}

نمونه جذاب :

public static function get_biscuit_parameters()

{

return new external_function_parameters( array( ‘ifeellike’ => new external_single_structure( array( ‘chocolatechips’ => new external_value(PARAM_BOOL, VALUE_REQUIRED), ‘glutenfree’ => new external_value(PARAM_BOOL, PARAM_DEFAULT, false), ‘icingsugar’ => new external_value(PARAM_BOOL, VALUE_OPTIONAL), // ALL GOOD!! We have nested the params in a external_single_structure. ) ) ) );

}

پیاده سازی تابع خارجی

ما تابع وب سرویس مان را اعلام کردیم و پارامترهای عملکرد خارجی و مقادیر بازگشتی را تعریف کردیم. اکنون تابع خارجی را اجرا خواهیم کرد:

/**

* Create groups

* @param array $groups array of group description arrays (with keys groupname and courseid)

* @return array of newly created groups

*/

public static function create_groups($groups) { //Don’t forget to set it as static

global $CFG, $DB;

require_once(“$CFG->dirroot/group/lib.php”);

$params = self::validate_parameters(self::create_groups_parameters(), array(‘groups’=>$groups));

$transaction = $DB->start_delegated_transaction(); //If an exception is thrown in the below code, all DB queries in this code will be rollback.

$groups = array();

foreach ($params[‘groups’] as $group) {

$group = (object)$group;

if (trim($group->name) == ”) {

throw new invalid_parameter_exception(‘Invalid group name’);

}

if ($DB->get_record(‘groups’, array(‘courseid’=>$group->courseid, ‘name’=>$group->name))) {

throw new invalid_parameter_exception(‘Group with the same name already exists in the course’);

}

// now security checks

$context = get_context_instance(CONTEXT_COURSE, $group->courseid);

self::validate_context($context);

require_capability(‘moodle/course:managegroups’, $context);

// finally create the group

$group->id = groups_create_group($group, false);

$groups[] = (array)$group;

}

$transaction->allow_commit();

return $groups;

}

پارامترهای اعتبارسنجی – Parameter validation

$params = self::validate_parameters(self::create_groups_parameters(), array(‘groups’=>$groups));

تابع validate_parameters پارامترهای تابع خارجی را بر اساس توضیح (Description) اعتبارسنجی می کند. اگر پارامتر مورد نیاز وجود نداشته باشد و یا اگر بعضی از پارامترها گم شوند این تابع یک استثناء برمی گرداند. برای جلوگیری از هک های اساسی ، فراخوانی این تابع ضروری است.

مهم : پارامترهای تابع خارجی و نمایش آنها در توضیحات باید یکسان باشند. در این مثال ما فقط یک پارامتر به نام groups$  داریم.

Context and Capability checks

/// now security checks

$context = context_course::instance($group->courseid);

self::validate_context($context);

require_capability(‘moodle/course:managegroups’, $context);

توجه داشته باشید: ()validate_context در تمام توابع خارجی، قبل از کار بر روی هر داده ی متعلق به یک context مورد نیاز است. این تابع کنترل سلامت و امنیت را برای context ای که به تابع خارجی انتقال داده می شود، انجام می دهد و  PAGE$ و OUTPUT$ را برای رندر کردن مقدار بازگشتی تنظیم می کند. از ()require_login و ()PAGE->set_context$ در یک تابع خارجی استفاده نکنید.

استثنائات

شما می توانید استثنائات را فراخوانی کنید. سرورهای وب سرویس Moodle به صورت خودکار اداره می شوند.

//Note: it is good practice to add detailled information in $debuginfo,

// and only send back a generic exception message when Moodle DEBUG mode < NORMAL.

// It’s what we do here throwing the invalid_parameter_exception($debug) exception

throw new invalid_parameter_exception(‘Group with the same name already exists in the course’);

مقادیر بازگشتی صحیح

مقادیر بازگشتی توسط سرورهای وب سرویس مودل اعتبارسنجی می شوند:

  • مقادیر برگشتی شامل مقادیری است که تعریف نشده اند => این مقادیر از بین می رود.
  • مقادیر بازگشتی مقداری از مقادیر را از دست می دهند (VALUE_REQUIRED) => سرور خطایی را نشان خواهد داد.
  • نوع مقادیر بازگشتی با تعریفی که از مقادیر شده است، هماهنگ نیست (int != PARAM_ALPHA) => سرور خطایی را نشان خواهد داد.

توجه داشته باشید: تمام object هایی بازگشتی خود را به آرایه ها ارسال کنید.

در دسترس قرار دادن وب سرویس با استفاده از Apache Thrift – Making web service accessible through – Apache Thrift

این مرحله اختیاری است. اگر شما مایل به ایجاد SDK برای زبان های مختلف برنامه نویسی و سیستم عامل هایی که از فریم ورک Apache Thrift هستید، ابزار Moodle Thrift می تواند به شما کمک کند.

دو مرحله باید انجام شود:

  • فایل های thrift. برای Moodle API با استفاده از اسکریپت thriftgenerator تولید کنید.
  • مدیریت کننده thrift برای PHP تولید کنید و فایل های PHP تولید شده را در شاخه پلاگین اصلی تان کپی کنید.

همچنین توصیه می شود فایل های thrift خود را به توزیع افزونه مورد نظرتان اضافه کنید تا ایجاد پیوندهای کلاینت برای کاربران API شما آسان شود.

اکنون با این تنظیمات API وبِ پلاگین شما از طریق فریم ورک Apache Thrift در دسترس است.

Bump the plugin version

فایل local/myplugin/version.php را ویرایش کنید و ورژن پلاگین خود را افزایش دهید.

تخریب – Deprecation

فرایند تخریب(Deprecation) توابع خارجی متفاوت از تخریب (Deprecation) استاندارد است. اگر شما علاقه مند به تخریب (Deprecation) هر یک از توابع خارجی خود هستید، باید تابع FUNCTIONNAME_is_deprecated را در کلاس تابع خارجی خود ایجاد کنید. اگر تابع خارجی تخریب شود، درست (true) را برمی گرداند. بطور مثال:

/**

* Mark the function as deprecated.

* @return bool

*/

public static function create_groups_is_deprecated() {

return true;

}

منبع : سایت رسمی مودل

درباره مدیر محتوا

همچنین بررسی کنید

استفاده از وب سرویس ها در مودل

  این نوشته توضیح می دهد که چگونه یک مدیر می تواند یک وب سرویس (web …

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *