نوشتن ماژول در دروپال 7 - بخش پنج

By کوشا حسینی, 27 سپتامبر, 2013

ماژول نویسی دروپال بخش یک
ماژول نویسی دروپال بخش دو
ماژول نویسی دروپال بخش سه
ماژول نویسی دروپال بخش چهار
ماژول نویسی دروپال بخش شش
ماژول نویسی دروپال بخش هفت
ماژول نویسی دروپال بخش هشت

کاری که باید انجام بدیم، دریافت داده‌ها از فرمی که تعریف کردیم و نوشتن این داده‌ها در جدول پایگاه داده است (database table). برای اینکار توابع مختلفی وجود داره، که هرکدام رو جداگانه بررسی می‌کنیم.

نوشتن اطلاعات جدید در پایگاه داده‌ی دروپال

نام تابع مورد نظر، db_insert هست که برای اجرای queryهای ورود اطلاعات جدید، استفاده می‌شه. در استفاده پیشرفته‌ی اون میشه از sub-queryهای join هم استفاده کرد که نحوه‌ی انجامش رو در صفحه‌ی راهنمای این تایع می‌تونید ببینید. برای استفاده لازمه که نام جدول، نام فیلدهایی که نوشته می‌شن و مقدار اون‌ها رو تعیین کنیم. توجه کنید که اگر فیلدی به صورت NOT NULL تعریف کرده باشیم و داده‌ای برای اون تعریف نکنیم، با خطای پایگاه داده مواجه می‌شیم. این کار اجازه‌ی استفاده از بلوک‌های try-catch رو می‌ده.

در بخش‌های قبلی مقاله داده‌هایی که در فرم از کاربر دریافت کردیم به این صورت بود:

  $result = NULL;
  if (isset($form_state['clicked_button']) && $form_state['clicked_button']['#name'] == 'op') {
    $v = $form_state['values'];
    $result = _my_calculator_calculate($v['value_1'], $v['value_2'], $v['operation']);
  }

که به صورت پیش‌فرض مقدار result رو خالی در نظر می‌گرفت. کاری که انجام می‌دیم گسترش این بخش برای ذخیره‌ی نتیجه است. با نگاهی به ساختار جدول تعریفی، می‌بینیم فیلدهایی تعیین مقدارشون لازمه، uid به عنوان شناسه‌ی کاربر، و result به عنوان نتیجه‌ی محاسبه است. فیلد rid به خاطر auto increment بودن (خاصیت فیلدهای نوع serial)، به صورت خودکار در پایگاه داده محاسبه خواهد شد. پس قطعه کد ما به این صورت در خواهد آمد:

  $result = NULL;
  if (isset($form_state['clicked_button']) && $form_state['clicked_button']['#name'] == 'op') {
    $v = $form_state['values'];
    $result = _my_calculator_calculate($v['value_1'], $v['value_2'], $v['operation']);

    $fields = array(
      'uid' => $GLOBALS['user']->uid,
      'result' => $result,
    );

    $query = db_insert('my_calculator_result);
    $query->fields($fields);
    $query->execute();
  }

توضیحات:

  • تابع db_insert، با گرفتن نام جدول مورد نظر ما، شیئی (object) برای اتصال و انجام queryها در پایگاه داده می‌سازه. پس در نهاییت، $query یک شیئ خواهد بود.
  • متد fields از این شیئ، آرایه‌ای به صورت نام-فیلد=>مقدار-فیلد میگیره تا بعدا مقادیر اون وارد پایگاه داده بشوند. این نام=>مقدار ها رو در آرایه‌ی $fields تعریف کردیم. باید توجه کنیم که مقادیری که در کلیدهای آرایه‌ی $field قرار می‌دهیم متناسب با نوع مقداری باشد که در پایگاه داده‌ تعیین کردیم (مثلا مقدار فیلد result، نباید یک رشته‌ی حرفی شامل حروفی مثل E یا ... باشه، چون پایگاه داده انتظار یک مقدار عددی رو داره). در غیر این صورت با خطای پایگاه داده مواجه می‌شیم.
  • متد execute که برای همه‌ی اشیایی که توسط توابع پایگاه داده ساخته می‌شوند وجود داره، query موجود در شیئ پایگاه داده‌ی مارو اجرا می‌کنه. در واقع با اجرای این متد است که اطلاعات از شیئ به پایگاه داده ارسال میشن. اگر داده‌ای برای دریافت وجود داشته باشه، با اجرای متد execute آماده‌ی ارائه به کد ما می‌شه که در ادامه‌ی مقاله دریافت داده‌های پیدا شده توسط این متد رو بررسی می‌کنیم.

امکان خوبی که در توابع پایگاه داده‌ای دروپال در نظر گرفته شده اینه که همگی generative هستند، یعنی تایع fields پس از اجرا، باز خود شیئ پایگاه داده رو برمیگردونه، یعنی در عبارت بالا، نتیجه‌ی بازگردانده شده از عبارت $query->fields خود query خواهد بود، پس قابلیت اجرای دوباره‌ی متدها رو به صورت مستقیم روی این شیئ داریم و نیازی به تعیریف متغیر $query نیست. با مثال زیر همه چیز روشن‌تر خواهد شد:

// Boring, hard-to-read method:
$query = db_insert('my_calculator_result);
$query->fields($fields);
$query->execute();

// What actually happens:
// RESULT OF [ $qurey->fiedls($fields) ] IS EQUAL TO [ $qurty ];
// So:
$query = ((db_insert('my_calculator_result))->fields($fields))->execute();

// Or simpler:
$query = db_insert('my_calculator_result)->fields($fields)->execute();

// Written more readable, $query is removed because we don't need it.
db_insert('my_calculator_result')
  ->fields($fields)
  ->execute();

اگر وارد سایت شوید و مقداری رو در ماشین حساب ساده محاسبه کنید، با بررسی پایگاه داده خواهید دید که این مقدار در جدول مربوطه ذخیره شده.

خواندن اطلاعات از پایگاه داده

حالا که نتایج رو در پایگاه داده ذخیره می‌کنیم، می‌تونیم در مراجعات بعدی نتیجه‌‌ی محاسبات قبلی رو به کاربر نشون بدیم. برای این کار به این صورت عمل می‌کنیم که اگر مقداری توسط کاربر وارد نشده بود ($form_state خالی بود) نتیجه رو از پایگاه داده می‌خوانیم و در result قرار می‌دیم.
برای خواندن اطلاعات، تابعی به اسم db_select وجود داره که مسئول اجرای queryهای SELECT از پایگاه داده است. این تابع، نام جدولی که اطلاعات از اون خوانده می‌شه، نام فیلدهایی که نیاز داریم و نحوه‌ی دریافت اطلاعات رو از ما می‌گیره. نمونه‌ای از اجرای این کد به این صورت خواهد بود:

$query = db_select('my_calculator_result', 'mcr')
  ->condition('mcr.uid', $uid, '=')
  ->fields('mcr', array('result'))
  ->range(0, 1)
  ->execute();

توضیحات:

  • در خط اول، ما نام جدول و Aliasی که برای آن توسط query ما ساخته می‌شه رو تعیین کردیم. وجود هردوی آن‌ها الزامیه.
  • در خط دوم با متد condition، فیلدی از جدول alias شده برای بررسی (در اینجا uid از mcr به عنوان شناسه‌ی کاربر) ، مقداری برای مقایسه با آن (در اینجا $uid شامل شناسه‌ی کاربر جاری) و عملگر مقایسه که بر حسب داده‌ای که به این متد ارسال میشه (آرایه یا یک مقدار مشخص) می‌تونه همه‌ی عملگرهای مجاز در پایگاه‌های داده مثل IN یا <> یا LIKE یا .... باشه.
  • در خط سوم، فیلدهایی که از پایگاه داده خوانده می‌شن رو ذکر کردیم. نحوه‌ی صدا زدن این متد به این شکله که آرگومان اول نام alias جدول مورد نظر، و آرگومان دوم آرایه‌ای از فیلدها خواهد بود. اما چرا ذکر نام alias جدول لازمه؟ تابع db_query یا توابع مشابه اون مثل db_select، امکان اجرای queryهای شامل join در پایگاه داده رو دارند، پس ممکنه در یک query، چندین جدول وجود داشته باشه. نحوه‌ی پیاده‌سازی متد fields هم به این صورت بوده که با این قابلیت سازگار باشه پس همیشه انتظار داره نام جدولی که فیلدهای اون رو درخواست می‌کنیم از بین جداول موجود در query مشخص کنیم.
  • در خط چهارم تعداد مقادیر خوانده شده از پایگاه داده رو بین ۰ و ۱ تعیین کردیم، پس در صورت وجود ۲ رکورد، فقط رکورد اول بازگردانده خواهد شد.

اما نحوه‌ی استفاده از result به چه صورت خواهد بود؟ برای خواندن داده‌ها از پایگاه داده چندین روش وجود داره که فعلا فقط متد fetchAssoc() رو بررسی می‌کنیم. این متد داده‌ها رو از پایگاه داده خوانده و در یک آرایه به صورت کلید=>مقدار قرار می‌ده. نتیجه‌ی اجرای fetchAssoc روی query که نوشیتم، یک آرایه تک مقداره خواهد بود، که کلید آن نام فیلد انتخابی (result) و مقدار آن نتیجه‌ی مورد انتظار ما خواهد بود.

در چه صورتی لازمه ما مقدار ذخیره شده در پایگاه داده رو بخونیم؟ در صورتی که عملیاتی داخل فرم وارد نشده، یعنی تا وقتی که کاربر دکمه‌ی محاسبه رو کلیک نکرده، پس بخش else در عبارت اولین if جای مناسبی خواهد بود:

  if (isset($form_state['clicked_button']) && $form_state['clicked_button']['#name'] == 'op') {
    $v = $form_state['values'];
    $result = _my_calculator_calculate($v['value_1'], $v['value_2'], $v['operation']);

    $fields = array(
      'uid' => $GLOBALS['user']->uid,
      'result' => $result,
    );

    $query = db_insert('my_calculator_result);
    $query->fields($fields);
    $query->execute();
  }
  else {
    $query = db_select('my_calculator_result', 'mcr')
      ->condition('mcr.uid', $uid, '=')
      ->fields('mcr', array('result'))
      ->range(0, 1)
      ->execute();

    $result = $query->fetchAssoc();
    $result = $result['result'];
  }

توجه کنید که باگ کوچکی در کد ما وجود داره و اون زمانی هست که کاربری برای اولین بار به صفحه‌ی فرم مراجعه می‌کنه، به خاطر اینکه در فرم عبارت محاسباتی وارد نشده، کدهای ما سعی در خواندن جواب از پایگاه داده می‌کنه اما از آنجایی که در پایگاه داده داده‌ای برای کاربران جدید ذخیره نشده، خط آخر کد بالا با مشکل مواجه می‌شه. رفع این باگ رو به عهده‌ی شما می‌گذارم. 
کار جالبی که می‌تونید انجام بدید، ذخیره‌ی اعداد وارد شده در فیلدهای مختلف فرم و عملگر انتخابی در پایگاه داده است که نیازمند تغییر ساختار جدول پایگاه داده‌ی ماژول است، یا شاید هم تعریف یک جدول دیگر در پایگاه داده!

بررسی توابع db_merge و db_update برای جلوگیری از ورود چندین مقدار متفاوت به جدول my_calculator_result (که باگ اصلی در کد فعلی حساب می‌شه!) رو به مقاله‌ی بعدی موکول می‌کنم. فایل ماژول آماده شده در ضمیمه موجود است.

شاد و موفق باشید.

تگ های مطلب
دسته بندی مطلب