בניית מודול CRUD
בניית הדרכה CRUD מודול
Section titled “בניית הדרכה CRUD מודול”מדריך זה מנחה אותך בבניית מודול CRUD (צור, קרא, עדכן, מחק) שלם עבור XOOPS. ניצור מודול “הערות” המאפשר למשתמשים לנהל הערות אישיות.
דרישות מוקדמות
Section titled “דרישות מוקדמות”- הושלם הדרכה של Hello-World-Module
- הבנה של מושגי PHP OOP
- ידע בסיסי SQL
סקירת מודול
Section titled “סקירת מודול”תכונות מודול הערות:
- צור, הצג, ערוך ומחק הערות
- ממשק ניהול אדמין
- הערות ספציפיות למשתמש
- ארגון קטגוריות
- פונקציונליות חיפוש
שלב 1: מבנה ספריות
Section titled “שלב 1: מבנה ספריות”צור את המבנה הבא ב-/modules/notes/:
/modules/notes/ /admin/ admin_header.php admin_footer.php index.php menu.php notes.php categories.php /assets/ /css/ style.css /images/ logo.png /class/ Note.php NoteHandler.php Category.php CategoryHandler.php Common/ Breadcrumb.php /include/ common.php install.php uninstall.php update.php /language/ /english/ admin.php main.php modinfo.php /sql/ mysql.sql /templates/ /admin/ notes_admin_index.tpl notes_admin_notes.tpl notes_admin_categories.tpl notes_index.tpl notes_view.tpl notes_edit.tpl notes_list.tpl index.php view.php edit.php xoops_version.phpשלב 2: סכימת מסד נתונים
Section titled “שלב 2: סכימת מסד נתונים”צור sql/mysql.sql:
-- Notes Module Database Schema
-- Categories TableCREATE TABLE `notes_categories` ( `catid` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, `description` TEXT, `weight` INT(5) NOT NULL DEFAULT 0, `created` INT(10) UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`catid`), KEY `idx_weight` (`weight`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Notes TableCREATE TABLE `notes_notes` ( `noteid` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `catid` INT(11) UNSIGNED NOT NULL DEFAULT 0, `uid` INT(11) UNSIGNED NOT NULL DEFAULT 0, `title` VARCHAR(255) NOT NULL, `content` TEXT NOT NULL, `status` TINYINT(1) NOT NULL DEFAULT 1, `created` INT(10) UNSIGNED NOT NULL DEFAULT 0, `updated` INT(10) UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`noteid`), KEY `idx_catid` (`catid`), KEY `idx_uid` (`uid`), KEY `idx_status` (`status`), KEY `idx_created` (`created`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;שלב 3: הגדרת מודול
Section titled “שלב 3: הגדרת מודול”צור xoops_version.php:
<?php/** * Notes Module - Module Definition */
if (!defined('XOOPS_ROOT_PATH')) { die('XOOPS root path not defined');}
$modversion = [];
// Basic Information$modversion['name'] = _MI_NOTES_NAME;$modversion['version'] = 1.00;$modversion['description'] = _MI_NOTES_DESC;$modversion['author'] = 'Your Name';$modversion['credits'] = 'XOOPS Community';$modversion['license'] = 'GPL 2.0 or later';$modversion['image'] = 'assets/images/logo.png';$modversion['dirname'] = 'notes';
// Requirements$modversion['min_php'] = '8.0';$modversion['min_xoops'] = '2.5.11';
// Admin$modversion['hasAdmin'] = 1;$modversion['adminindex'] = 'admin/index.php';$modversion['adminmenu'] = 'admin/menu.php';$modversion['system_menu'] = 1;
// Main$modversion['hasMain'] = 1;
// Submenu$modversion['sub'][] = [ 'name' => _MI_NOTES_MENU_LIST, 'url' => 'index.php',];$modversion['sub'][] = [ 'name' => _MI_NOTES_MENU_ADD, 'url' => 'edit.php',];
// Database$modversion['sqlfile']['mysql'] = 'sql/mysql.sql';$modversion['tables'] = [ 'notes_categories', 'notes_notes',];
// Templates$modversion['templates'][] = ['file' => 'notes_index.tpl', 'description' => ''];$modversion['templates'][] = ['file' => 'notes_view.tpl', 'description' => ''];$modversion['templates'][] = ['file' => 'notes_edit.tpl', 'description' => ''];$modversion['templates'][] = ['file' => 'notes_list.tpl', 'description' => ''];$modversion['templates'][] = ['file' => 'admin/notes_admin_index.tpl', 'description' => ''];$modversion['templates'][] = ['file' => 'admin/notes_admin_notes.tpl', 'description' => ''];$modversion['templates'][] = ['file' => 'admin/notes_admin_categories.tpl', 'description' => ''];
// Configuration$modversion['config'][] = [ 'name' => 'notes_per_page', 'title' => '_MI_NOTES_PERPAGE', 'description' => '_MI_NOTES_PERPAGE_DESC', 'formtype' => 'textbox', 'valuetype' => 'int', 'default' => 10,];
// Install/Update Functions$modversion['onInstall'] = 'include/install.php';$modversion['onUpdate'] = 'include/update.php';שלב 4: כיתות ישות
Section titled “שלב 4: כיתות ישות”ישות הערה
Section titled “ישות הערה”צור class/Note.php:
<?php/** * Note Entity Class */
declare(strict_types=1);
namespace XoopsModules\Notes;
use XoopsObject;
class Note extends XoopsObject{ /** * Constructor */ public function __construct() { parent::__construct(); $this->initVar('noteid', XOBJ_DTYPE_INT, null, false); $this->initVar('catid', XOBJ_DTYPE_INT, 0, false); $this->initVar('uid', XOBJ_DTYPE_INT, 0, true); $this->initVar('title', XOBJ_DTYPE_TXTBOX, '', true, 255); $this->initVar('content', XOBJ_DTYPE_TXTAREA, '', true); $this->initVar('status', XOBJ_DTYPE_INT, 1, false); $this->initVar('created', XOBJ_DTYPE_INT, 0, false); $this->initVar('updated', XOBJ_DTYPE_INT, 0, false); }
/** * Get formatted creation date */ public function getFormattedDate(string $format = 'Y-m-d H:i:s'): string { $timestamp = (int) $this->getVar('created'); return date($format, $timestamp); }
/** * Get the author's username */ public function getAuthorName(): string { $uid = (int) $this->getVar('uid'); if ($uid === 0) { return 'Anonymous'; }
$memberHandler = xoops_getHandler('member'); $user = $memberHandler->getUser($uid);
return $user ? $user->getVar('uname') : 'Unknown'; }
/** * Get category object */ public function getCategory(): ?Category { $catid = (int) $this->getVar('catid'); if ($catid === 0) { return null; }
/** @var CategoryHandler $categoryHandler */ $categoryHandler = xoops_getModuleHandler('category', 'notes'); return $categoryHandler->get($catid); }
/** * Get note as array for templates */ public function toArray(): array { return [ 'noteid' => $this->getVar('noteid'), 'catid' => $this->getVar('catid'), 'uid' => $this->getVar('uid'), 'title' => $this->getVar('title'), 'content' => $this->getVar('content', 's'), 'content_short' => $this->getVar('content', 's', 200), 'status' => $this->getVar('status'), 'created' => $this->getFormattedDate(), 'author' => $this->getAuthorName(), ]; }}מטפל הערות
Section titled “מטפל הערות”צור class/NoteHandler.php:
<?php/** * Note Handler Class */
declare(strict_types=1);
namespace XoopsModules\Notes;
use XoopsPersistableObjectHandler;use CriteriaCompo;use Criteria;
class NoteHandler extends XoopsPersistableObjectHandler{ /** * Constructor */ public function __construct(\XoopsDatabase $db = null) { parent::__construct( $db, 'notes_notes', Note::class, 'noteid', 'title' ); }
/** * Get notes by user ID * * @param int $uid User ID * @param int $limit Limit * @param int $start Start offset * @return Note[] */ public function getByUser(int $uid, int $limit = 0, int $start = 0): array { $criteria = new CriteriaCompo(); $criteria->add(new Criteria('uid', $uid)); $criteria->add(new Criteria('status', 1)); $criteria->setSort('created'); $criteria->setOrder('DESC'); $criteria->setLimit($limit); $criteria->setStart($start);
return $this->getObjects($criteria); }
/** * Get notes by category * * @param int $catid Category ID * @param int $limit Limit * @param int $start Start offset * @return Note[] */ public function getByCategory(int $catid, int $limit = 0, int $start = 0): array { $criteria = new CriteriaCompo(); $criteria->add(new Criteria('catid', $catid)); $criteria->add(new Criteria('status', 1)); $criteria->setSort('created'); $criteria->setOrder('DESC'); $criteria->setLimit($limit); $criteria->setStart($start);
return $this->getObjects($criteria); }
/** * Get recent notes * * @param int $limit Limit * @param int|null $uid Optional user ID filter * @return Note[] */ public function getRecent(int $limit = 10, ?int $uid = null): array { $criteria = new CriteriaCompo(); $criteria->add(new Criteria('status', 1));
if ($uid !== null) { $criteria->add(new Criteria('uid', $uid)); }
$criteria->setSort('created'); $criteria->setOrder('DESC'); $criteria->setLimit($limit);
return $this->getObjects($criteria); }
/** * Search notes * * @param string $query Search query * @param int|null $uid Optional user ID filter * @return Note[] */ public function search(string $query, ?int $uid = null): array { $criteria = new CriteriaCompo(); $criteria->add(new Criteria('status', 1));
// Search in title and content $searchCriteria = new CriteriaCompo(); $searchCriteria->add(new Criteria('title', '%' . $query . '%', 'LIKE'), 'OR'); $searchCriteria->add(new Criteria('content', '%' . $query . '%', 'LIKE'), 'OR'); $criteria->add($searchCriteria);
if ($uid !== null) { $criteria->add(new Criteria('uid', $uid)); }
$criteria->setSort('created'); $criteria->setOrder('DESC');
return $this->getObjects($criteria); }
/** * Count notes by user * * @param int $uid User ID * @return int */ public function countByUser(int $uid): int { $criteria = new CriteriaCompo(); $criteria->add(new Criteria('uid', $uid)); $criteria->add(new Criteria('status', 1));
return $this->getCount($criteria); }
/** * Save a note with automatic timestamps * * @param Note $note * @param bool $force * @return bool */ public function insert($note, $force = true): bool { $now = time();
if ($note->isNew()) { $note->setVar('created', $now); } $note->setVar('updated', $now);
return parent::insert($note, $force); }}ישות קטגוריה
Section titled “ישות קטגוריה”צור class/Category.php:
<?php/** * Category Entity Class */
declare(strict_types=1);
namespace XoopsModules\Notes;
use XoopsObject;
class Category extends XoopsObject{ /** * Constructor */ public function __construct() { parent::__construct(); $this->initVar('catid', XOBJ_DTYPE_INT, null, false); $this->initVar('name', XOBJ_DTYPE_TXTBOX, '', true, 255); $this->initVar('description', XOBJ_DTYPE_TXTAREA, '', false); $this->initVar('weight', XOBJ_DTYPE_INT, 0, false); $this->initVar('created', XOBJ_DTYPE_INT, 0, false); }
/** * Get category as array */ public function toArray(): array { return [ 'catid' => $this->getVar('catid'), 'name' => $this->getVar('name'), 'description' => $this->getVar('description', 's'), 'weight' => $this->getVar('weight'), ]; }}מטפל בקטגוריות
Section titled “מטפל בקטגוריות”צור class/CategoryHandler.php:
<?php/** * Category Handler Class */
declare(strict_types=1);
namespace XoopsModules\Notes;
use XoopsPersistableObjectHandler;use CriteriaCompo;use Criteria;
class CategoryHandler extends XoopsPersistableObjectHandler{ /** * Constructor */ public function __construct(\XoopsDatabase $db = null) { parent::__construct( $db, 'notes_categories', Category::class, 'catid', 'name' ); }
/** * Get all categories ordered by weight * * @return Category[] */ public function getAllOrdered(): array { $criteria = new CriteriaCompo(); $criteria->setSort('weight'); $criteria->setOrder('ASC');
return $this->getObjects($criteria); }
/** * Get categories as select options * * @return array */ public function getSelectOptions(): array { $options = [0 => _MD_NOTES_NO_CATEGORY]; $categories = $this->getAllOrdered();
foreach ($categories as $category) { $options[$category->getVar('catid')] = $category->getVar('name'); }
return $options; }
/** * Save category with automatic timestamp */ public function insert($category, $force = true): bool { if ($category->isNew()) { $category->setVar('created', time()); }
return parent::insert($category, $force); }}שלב 5: קובץ כלול נפוץ
Section titled “שלב 5: קובץ כלול נפוץ”צור include/common.php:
<?php/** * Common Include File */
declare(strict_types=1);
if (!defined('XOOPS_ROOT_PATH')) { die('XOOPS root path not defined');}
// Module constantsdefine('NOTES_DIRNAME', 'notes');define('NOTES_PATH', XOOPS_ROOT_PATH . '/modules/' . NOTES_DIRNAME);define('NOTES_URL', XOOPS_URL . '/modules/' . NOTES_DIRNAME);
// Load class filesrequire_once NOTES_PATH . '/class/Category.php';require_once NOTES_PATH . '/class/CategoryHandler.php';require_once NOTES_PATH . '/class/Note.php';require_once NOTES_PATH . '/class/NoteHandler.php';
/** * Get the Notes module helper */function notesHelper(): \Xmf\Module\Helper{ return \Xmf\Module\Helper::getHelper('notes');}
/** * Get note handler instance */function noteHandler(): \XoopsModules\Notes\NoteHandler{ return xoops_getModuleHandler('note', 'notes');}
/** * Get category handler instance */function categoryHandler(): \XoopsModules\Notes\CategoryHandler{ return xoops_getModuleHandler('category', 'notes');}שלב 6: דפי קצה
Section titled “שלב 6: דפי קצה”דף אינדקס
Section titled “דף אינדקס”צור index.php:
<?php/** * Notes Index - List User's Notes */
declare(strict_types=1);
use Xmf\Request;
require_once dirname(__DIR__, 2) . '/mainfile.php';require_once __DIR__ . '/include/common.php';
xoops_loadLanguage('main', 'notes');
// Require loginif (!$GLOBALS['xoopsUser']) { redirect_header(XOOPS_URL . '/user.php', 3, _NOPERM); exit;}
$uid = $GLOBALS['xoopsUser']->getVar('uid');$helper = notesHelper();$perPage = $helper->getConfig('notes_per_page');
// Get page number$start = Request::getInt('start', 0, 'GET');
// Get notes$noteHandler = noteHandler();$categoryHandler = categoryHandler();
$totalNotes = $noteHandler->countByUser($uid);$notes = $noteHandler->getByUser($uid, $perPage, $start);
// Prepare notes for template$notesArray = [];foreach ($notes as $note) { $notesArray[] = $note->toArray();}
// Get categories for filter$categories = $categoryHandler->getAllOrdered();$categoriesArray = [];foreach ($categories as $category) { $categoriesArray[] = $category->toArray();}
// Set template$GLOBALS['xoopsOption']['template_main'] = 'notes_index.tpl';require XOOPS_ROOT_PATH . '/header.php';
// Assign to template$xoopsTpl->assign([ 'notes' => $notesArray, 'categories' => $categoriesArray, 'total_notes' => $totalNotes, 'module_url' => NOTES_URL,]);
// Paginationif ($totalNotes > $perPage) { require_once XOOPS_ROOT_PATH . '/class/pagenav.php'; $nav = new \XoopsPageNav($totalNotes, $perPage, $start, 'start'); $xoopsTpl->assign('pagination', $nav->renderNav());}
require XOOPS_ROOT_PATH . '/footer.php';הצג את הדף
Section titled “הצג את הדף”צור view.php:
<?php/** * View Single Note */
declare(strict_types=1);
use Xmf\Request;
require_once dirname(__DIR__, 2) . '/mainfile.php';require_once __DIR__ . '/include/common.php';
xoops_loadLanguage('main', 'notes');
// Require loginif (!$GLOBALS['xoopsUser']) { redirect_header(XOOPS_URL . '/user.php', 3, _NOPERM); exit;}
$uid = $GLOBALS['xoopsUser']->getVar('uid');$noteid = Request::getInt('id', 0, 'GET');
if ($noteid <= 0) { redirect_header(NOTES_URL . '/index.php', 3, _MD_NOTES_NOT_FOUND); exit;}
$noteHandler = noteHandler();$note = $noteHandler->get($noteid);
if (!$note || $note->getVar('uid') != $uid) { redirect_header(NOTES_URL . '/index.php', 3, _NOPERM); exit;}
// Set template$GLOBALS['xoopsOption']['template_main'] = 'notes_view.tpl';require XOOPS_ROOT_PATH . '/header.php';
$xoopsTpl->assign([ 'note' => $note->toArray(), 'module_url' => NOTES_URL,]);
require XOOPS_ROOT_PATH . '/footer.php';עריכת עמוד (Create/Update)
Section titled “עריכת עמוד (Create/Update)”צור edit.php:
<?php/** * Create/Edit Note */
declare(strict_types=1);
use Xmf\Request;
require_once dirname(__DIR__, 2) . '/mainfile.php';require_once __DIR__ . '/include/common.php';
xoops_loadLanguage('main', 'notes');
// Require loginif (!$GLOBALS['xoopsUser']) { redirect_header(XOOPS_URL . '/user.php', 3, _NOPERM); exit;}
$uid = $GLOBALS['xoopsUser']->getVar('uid');$noteid = Request::getInt('id', 0, 'REQUEST');$op = Request::getString('op', 'form', 'REQUEST');
$noteHandler = noteHandler();$categoryHandler = categoryHandler();
// Get or create noteif ($noteid > 0) { $note = $noteHandler->get($noteid); if (!$note || $note->getVar('uid') != $uid) { redirect_header(NOTES_URL . '/index.php', 3, _NOPERM); exit; } $isNew = false;} else { $note = $noteHandler->create(); $note->setVar('uid', $uid); $isNew = true;}
// Handle form submissionif ($op === 'save') { // CSRF check if (!$GLOBALS['xoopsSecurity']->check()) { redirect_header(NOTES_URL . '/index.php', 3, implode('<br>', $GLOBALS['xoopsSecurity']->getErrors())); exit; }
// Get form data $title = Request::getString('title', '', 'POST'); $content = Request::getText('content', '', 'POST'); $catid = Request::getInt('catid', 0, 'POST');
// Validate $errors = []; if (empty($title)) { $errors[] = _MD_NOTES_ERR_TITLE_REQUIRED; } if (empty($content)) { $errors[] = _MD_NOTES_ERR_CONTENT_REQUIRED; }
if (!empty($errors)) { redirect_header( NOTES_URL . '/edit.php?id=' . $noteid, 3, implode('<br>', $errors) ); exit; }
// Set values $note->setVar('title', $title); $note->setVar('content', $content); $note->setVar('catid', $catid);
// Save if ($noteHandler->insert($note)) { redirect_header( NOTES_URL . '/view.php?id=' . $note->getVar('noteid'), 2, $isNew ? _MD_NOTES_CREATED : _MD_NOTES_UPDATED ); } else { redirect_header( NOTES_URL . '/edit.php?id=' . $noteid, 3, _MD_NOTES_ERR_SAVE ); } exit;}
// Handle deleteif ($op === 'delete' && $noteid > 0) { if (!$GLOBALS['xoopsSecurity']->check()) { redirect_header(NOTES_URL . '/index.php', 3, implode('<br>', $GLOBALS['xoopsSecurity']->getErrors())); exit; }
if ($noteHandler->delete($note)) { redirect_header(NOTES_URL . '/index.php', 2, _MD_NOTES_DELETED); } else { redirect_header(NOTES_URL . '/index.php', 3, _MD_NOTES_ERR_DELETE); } exit;}
// Display form$GLOBALS['xoopsOption']['template_main'] = 'notes_edit.tpl';require XOOPS_ROOT_PATH . '/header.php';
// Get categories for dropdown$categories = $categoryHandler->getSelectOptions();
$xoopsTpl->assign([ 'note' => $note->toArray(), 'categories' => $categories, 'is_new' => $isNew, 'module_url' => NOTES_URL, 'token' => $GLOBALS['xoopsSecurity']->getTokenHTML(),]);
require XOOPS_ROOT_PATH . '/footer.php';שלב 7: תבניות
Section titled “שלב 7: תבניות”תבנית אינדקס
Section titled “תבנית אינדקס”צור templates/notes_index.tpl:
<{* Notes Index Template *}>
<div class="notes-container"> <div class="notes-header"> <h1><{$smarty.const._MD_NOTES_MY_NOTES}></h1> <a href="<{$module_url}>/edit.php" class="btn btn-primary"> <{$smarty.const._MD_NOTES_ADD_NEW}> </a> </div>
<{if $notes}> <div class="notes-list"> <{foreach from=$notes item=note}> <div class="note-item"> <h3> <a href="<{$module_url}>/view.php?id=<{$note.noteid}>"> <{$note.title}> </a> </h3> <div class="note-meta"> <span class="date"><{$note.created}></span> </div> <div class="note-excerpt"> <{$note.content_short|truncate:200}> </div> <div class="note-actions"> <a href="<{$module_url}>/view.php?id=<{$note.noteid}>"> <{$smarty.const._MD_NOTES_VIEW}> </a> <a href="<{$module_url}>/edit.php?id=<{$note.noteid}>"> <{$smarty.const._MD_NOTES_EDIT}> </a> </div> </div> <{/foreach}> </div>
<{if $pagination}> <div class="notes-pagination"> <{$pagination}> </div> <{/if}> <{else}> <div class="notes-empty"> <p><{$smarty.const._MD_NOTES_NO_NOTES}></p> <a href="<{$module_url}>/edit.php" class="btn btn-primary"> <{$smarty.const._MD_NOTES_CREATE_FIRST}> </a> </div> <{/if}></div>הצג תבנית
Section titled “הצג תבנית”צור templates/notes_view.tpl:
<{* Note View Template *}>
<div class="note-view"> <div class="note-header"> <h1><{$note.title}></h1> <div class="note-meta"> <span class="date"><{$note.created}></span> <span class="author"><{$note.author}></span> </div> </div>
<div class="note-content"> <{$note.content}> </div>
<div class="note-actions"> <a href="<{$module_url}>/edit.php?id=<{$note.noteid}>" class="btn btn-secondary"> <{$smarty.const._MD_NOTES_EDIT}> </a> <a href="<{$module_url}>/index.php" class="btn btn-link"> <{$smarty.const._MD_NOTES_BACK_LIST}> </a> </div></div>ערוך תבנית
Section titled “ערוך תבנית”צור templates/notes_edit.tpl:
<{* Note Edit Template *}>
<div class="note-edit"> <h1> <{if $is_new}> <{$smarty.const._MD_NOTES_ADD_NEW}> <{else}> <{$smarty.const._MD_NOTES_EDIT_NOTE}> <{/if}> </h1>
<form action="<{$module_url}>/edit.php" method="post" class="note-form"> <{$token}> <input type="hidden" name="op" value="save"> <input type="hidden" name="id" value="<{$note.noteid}>">
<div class="form-group"> <label for="title"><{$smarty.const._MD_NOTES_TITLE}></label> <input type="text" name="title" id="title" class="form-control" value="<{$note.title}>" required> </div>
<div class="form-group"> <label for="catid"><{$smarty.const._MD_NOTES_CATEGORY}></label> <select name="catid" id="catid" class="form-control"> <{foreach from=$categories key=id item=name}> <option value="<{$id}>" <{if $note.catid == $id}>selected<{/if}>> <{$name}> </option> <{/foreach}> </select> </div>
<div class="form-group"> <label for="content"><{$smarty.const._MD_NOTES_CONTENT}></label> <textarea name="content" id="content" class="form-control" rows="10" required><{$note.content}></textarea> </div>
<div class="form-actions"> <button type="submit" class="btn btn-primary"> <{$smarty.const._MD_NOTES_SAVE}> </button> <a href="<{$module_url}>/index.php" class="btn btn-link"> <{$smarty.const._MD_NOTES_CANCEL}> </a> <{if !$is_new}> <button type="submit" name="op" value="delete" class="btn btn-danger" onclick="return confirm('<{$smarty.const._MD_NOTES_CONFIRM_DELETE}>');"> <{$smarty.const._MD_NOTES_DELETE}> </button> <{/if}> </div> </form></div>שלב 8: קובץ שפה
Section titled “שלב 8: קובץ שפה”צור language/english/main.php:
<?php/** * Main Language File */
// Page Titlesdefine('_MD_NOTES_MY_NOTES', 'My Notes');define('_MD_NOTES_ADD_NEW', 'Add New Note');define('_MD_NOTES_EDIT_NOTE', 'Edit Note');
// Form Labelsdefine('_MD_NOTES_TITLE', 'Title');define('_MD_NOTES_CONTENT', 'Content');define('_MD_NOTES_CATEGORY', 'Category');define('_MD_NOTES_NO_CATEGORY', '-- No Category --');
// Buttonsdefine('_MD_NOTES_SAVE', 'Save');define('_MD_NOTES_CANCEL', 'Cancel');define('_MD_NOTES_DELETE', 'Delete');define('_MD_NOTES_VIEW', 'View');define('_MD_NOTES_EDIT', 'Edit');define('_MD_NOTES_BACK_LIST', 'Back to List');
// Messagesdefine('_MD_NOTES_CREATED', 'Note created successfully.');define('_MD_NOTES_UPDATED', 'Note updated successfully.');define('_MD_NOTES_DELETED', 'Note deleted successfully.');define('_MD_NOTES_NOT_FOUND', 'Note not found.');define('_MD_NOTES_NO_NOTES', 'You have no notes yet.');define('_MD_NOTES_CREATE_FIRST', 'Create Your First Note');define('_MD_NOTES_CONFIRM_DELETE', 'Are you sure you want to delete this note?');
// Errorsdefine('_MD_NOTES_ERR_TITLE_REQUIRED', 'Title is required.');define('_MD_NOTES_ERR_CONTENT_REQUIRED', 'Content is required.');define('_MD_NOTES_ERR_SAVE', 'Error saving note.');define('_MD_NOTES_ERR_DELETE', 'Error deleting note.');שלב 9: ממשק ניהול
Section titled “שלב 9: ממשק ניהול”תפריט ניהול
Section titled “תפריט ניהול”צור admin/menu.php:
<?php$adminmenu = [];
$adminmenu[] = [ 'title' => _AM_NOTES_INDEX, 'link' => 'admin/index.php', 'icon' => 'home.png',];
$adminmenu[] = [ 'title' => _AM_NOTES_NOTES, 'link' => 'admin/notes.php', 'icon' => 'content.png',];
$adminmenu[] = [ 'title' => _AM_NOTES_CATEGORIES, 'link' => 'admin/categories.php', 'icon' => 'category.png',];ניהול הערות מנהל
Section titled “ניהול הערות מנהל”צור admin/notes.php:
<?php/** * Admin Notes Management */
declare(strict_types=1);
use Xmf\Request;
require_once __DIR__ . '/admin_header.php';
$op = Request::getString('op', 'list', 'REQUEST');$noteid = Request::getInt('id', 0, 'REQUEST');
$noteHandler = noteHandler();
switch ($op) { case 'delete': if ($noteid > 0) { $note = $noteHandler->get($noteid); if ($note && $noteHandler->delete($note)) { redirect_header('notes.php', 2, _AM_NOTES_DELETED); } else { redirect_header('notes.php', 3, _AM_NOTES_ERR_DELETE); } } break;
case 'list': default: $adminObject->displayNavigation('notes.php');
// Get all notes $criteria = new CriteriaCompo(); $criteria->setSort('created'); $criteria->setOrder('DESC'); $notes = $noteHandler->getObjects($criteria);
// Display table echo '<table class="outer">'; echo '<tr class="head"><th>' . _AM_NOTES_ID . '</th>'; echo '<th>' . _AM_NOTES_TITLE . '</th>'; echo '<th>' . _AM_NOTES_AUTHOR . '</th>'; echo '<th>' . _AM_NOTES_DATE . '</th>'; echo '<th>' . _AM_NOTES_ACTIONS . '</th></tr>';
foreach ($notes as $note) { echo '<tr class="even">'; echo '<td>' . $note->getVar('noteid') . '</td>'; echo '<td>' . $note->getVar('title') . '</td>'; echo '<td>' . $note->getAuthorName() . '</td>'; echo '<td>' . $note->getFormattedDate() . '</td>'; echo '<td>'; echo '<a href="notes.php?op=delete&id=' . $note->getVar('noteid') . '" '; echo 'onclick="return confirm(\'' . _AM_NOTES_CONFIRM_DELETE . '\');">'; echo _AM_NOTES_DELETE . '</a>'; echo '</td></tr>'; }
echo '</table>'; break;}
require_once __DIR__ . '/admin_footer.php';מזל טוב! בנית מודול CRUD שלם. מושגי מפתח מכוסים:
- עיצוב מסד נתונים - טבלאות עם קשרים
- מחלקות ישות - XoopsObject עם מאפיינים מוקלדים
- שיעורי מטפל - XoopsPersistableObjectHandler בשיטות מותאמות אישית
- דפי חזית - רשימה, הצג וערוך פונקציונליות
- טיפול בטפסים - CSRF הגנה ואימות
- ממשק ניהול - מסכי ניהול
- תבניות - Smarty תבניות עם היגיון
השלבים הבאים
Section titled “השלבים הבאים”- הוסף תכונות מתקדמות יותר (הערות, דירוגים, שיתוף)
- יישם את ../Patterns/Repository-Pattern לגישה נקייה יותר לנתונים
- החל ../Patterns/MVC-Pattern לארגון קוד טוב יותר
- הוסף ../Best-Practices/Testing עם PHPUnit
ראה גם: ../Module-Development | ../Patterns/MVC-Pattern | ../Patterns/Repository-Pattern