| 414 | Change the '''actionAdministration''' function the following way: |
| 415 | |
| 416 | {{{ |
| 417 | function actionAdministration () { |
| 418 | |
| 419 | if (!$GLOBALS['logged']['admin']) { // check access to the page |
| 420 | $this->_oTemplate->displayAccessDenied (); |
| 421 | return; |
| 422 | } |
| 423 | |
| 424 | $this->_oTemplate->pageStart(); // all the code below will be wrapped by the admin design |
| 425 | |
| 426 | $iId = $this->_oDb->getSettingsCategory(); // get our setting category id |
| 427 | if(empty($iId)) { // if category is not found display page not found |
| 428 | echo MsgBox(_t('_sys_request_page_not_found_cpt')); |
| 429 | $this->_oTemplate->pageCodeAdmin (_t('_me_blgg')); |
| 430 | return; |
| 431 | } |
| 432 | |
| 433 | bx_import('BxDolAdminSettings'); // import class |
| 434 | |
| 435 | $mixedResult = ''; |
| 436 | if(isset($_POST['save']) && isset($_POST['cat'])) { // save settings |
| 437 | $oSettings = new BxDolAdminSettings($iId); |
| 438 | $mixedResult = $oSettings->saveChanges($_POST); |
| 439 | } |
| 440 | |
| 441 | $oSettings = new BxDolAdminSettings($iId); // get display form code |
| 442 | $sResult = $oSettings->getForm(); |
| 443 | |
| 444 | if($mixedResult !== true && !empty($mixedResult)) // attach any resulted messages at the form beginning |
| 445 | $sResult = $mixedResult . $sResult; |
| 446 | |
| 447 | echo DesignBoxAdmin (_t('_me_blgg'), $sResult); // dsiplay box |
| 448 | |
| 449 | $this->_oTemplate->pageCodeAdmin (_t('_me_blgg')); // output is completed, admin page will be displaed here |
| 450 | } |
| 451 | }}} |
| 452 | |
| 453 | then add the following class method to the '''modules/me/bloggie/classes/MeBlggDb.php''' file: |
| 454 | |
| 455 | {{{ |
| 456 | function getSettingsCategory() { |
| 457 | return $this->getOne("SELECT `ID` FROM `sys_options_cats` WHERE `name` = 'My Bloggie' LIMIT 1"); |
| 458 | } |
| 459 | }}} |
| 460 | |
| 461 | Clarification: |
| 462 | |
| 463 | * the '''getSettingsCategory''' method is placed into '''MeBlggDb''' since all database queries must be in this file. |
| 464 | * the '''getOne''' method returns the value of '''ID''' field in the '''SELECT''' SQL query. There are other handy functions to get the data from database. Refer to '''inc/classes/BxDolDb.php''' for complete list. |
| 465 | * '''_oDb''' is automatically defined in the '''MeBlggDb''' class |
| 466 | * the '''MsgBox''' function wraps text in a nice message box |
| 467 | * the '''bx_import''' function automatically imports a class by its name, and it can load classes with '''BxDol''', '''BxBase''', '''BxTempl''' prefixes if they are correctly named and located. Also, it can load module classes if the module config is passed as the second parameter. |
| 468 | * the '''BxDolAdminSettings''' class is used to display and save settings. Just use it as shown above. Make a note that the '''saveSettings''' function returns a result message which we append at the beginning of the result string. |
| 469 | |
| 470 | |
| 471 | == 3.4. Adding a link to a newly created page to the admin modules sub-menu. == |
| 472 | |
| 473 | Replace the content of '''install.sql''' with the following code: |
| 474 | |
| 475 | |
| 476 | {{{ |
| 477 | -- settings |
| 478 | SET @iMaxOrder = (SELECT `menu_order` + 1 FROM `sys_options_cats` ORDER BY `menu_order` DESC LIMIT 1); |
| 479 | INSERT INTO `sys_options_cats` (`name`, `menu_order`) VALUES ('My Bloggie', @iMaxOrder); |
| 480 | SET @iCategId = (SELECT LAST_INSERT_ID()); |
| 481 | INSERT INTO `sys_options` (`Name`, `VALUE`, `kateg`, `desc`, `Type`, `check`, `err_text`, `order_in_kateg`, `AvailableValues`) VALUES |
| 482 | ('me_blgg_permalinks', 'on', 26, 'Enable friendly permalinks in Bloggie', 'checkbox', '', '', '0', ''), |
| 483 | ('me_blgg_date_format', 'Y-m-d H:i', @iCategId, 'Format for server date/time', 'digit', '', '', '1', ''), |
| 484 | ('me_blgg_enable_js_date', 'on', @iCategId, 'Show user time', 'checkbox', '', '', '2', ''); |
| 485 | |
| 486 | -- permalinks |
| 487 | INSERT INTO `sys_permalinks` VALUES (NULL, 'modules/?r=bloggie/', 'm/bloggie/', 'me_blgg_permalinks'); |
| 488 | |
| 489 | -- admin menu |
| 490 | SET @iMax = (SELECT MAX(`order`) FROM `sys_menu_admin` WHERE `parent_id` = '2'); |
| 491 | INSERT IGNORE INTO `sys_menu_admin` (`parent_id`, `name`, `title`, `url`, `description`, `icon`, `order`) VALUES |
| 492 | (2, 'me_blgg', '_me_blgg', '{siteUrl}modules/?r=bloggie/administration/', 'My Bloggie by Me', 'modules/me/bloggie/|icon.png', @iMax+1); |
| 493 | }}} |
| 494 | |
| 495 | and '''uninstall.sql''' with the following: |
| 496 | |
| 497 | {{{ |
| 498 | -- settings |
| 499 | SET @iCategId = (SELECT `ID` FROM `sys_options_cats` WHERE `name` = 'My Bloggie' LIMIT 1); |
| 500 | DELETE FROM `sys_options` WHERE `kateg` = @iCategId; |
| 501 | DELETE FROM `sys_options_cats` WHERE `ID` = @iCategId; |
| 502 | DELETE FROM `sys_options` WHERE `Name` = 'me_blgg_permalinks'; |
| 503 | |
| 504 | -- permalinks |
| 505 | DELETE FROM `sys_permalinks` WHERE `standard` = 'modules/?r=bloggie/'; |
| 506 | |
| 507 | -- admin menu |
| 508 | DELETE FROM `sys_menu_admin` WHERE `name` = 'me_blgg'; |
| 509 | }}} |
| 510 | |
| 511 | Also, we need to change this section in the '''modules/me/bloggie/install/config.php''' file, since we have modified the '''sys_permalinks''' database table: |
| 512 | |
| 513 | {{{ |
| 514 | 'install' => array( |
| 515 | 'update_languages' => 1, |
| 516 | 'execute_sql' => 1, |
| 517 | 'recompile_permalinks' => 1, |
| 518 | ), |
| 519 | 'uninstall' => array ( |
| 520 | 'update_languages' => 1, |
| 521 | 'execute_sql' => 1, |
| 522 | 'recompile_permalinks' => 1, |
| 523 | ), |
| 524 | }}} |
| 525 | |
| 526 | the '''recompile_permalinks''' instruction was added above. |
| 527 | |
| 528 | We need to specify permalinks, because they are needed for correct link representation in case of an enabled '''mod_rewrite''' module in Apache and when this module is disabled. To correctly enable the permalinks mechanism we need to specify several things: |
| 529 | |
| 530 | * add a setting option which enables or disables permalinks in the module. In our case we have added the '''me_blgg_permalinks''' setting option. Please note that we have added this option to a special category (category id is equal to "'''26'''"). |
| 531 | * add the record to the '''sys_permalinks''' database table where we specify the newly created setting option and two URLs: |
| 532 | * '''modules/?r=bloggie/''' - when permalinks are disabled |
| 533 | * '''m/bloggie/''' - when permalinks are enabled |
| 534 | * add '''recompile_permalinks''' in the '''modules/me/bloggie/install/config.php''' file. It tells the installer to recompile cache with permalinks when we install or uninstall the module. |
| 535 | |
| 536 | The link to admin Modules submenu is added at the end. We have specified: |
| 537 | |
| 538 | * "'''2'''" indicates that it will be added to the '''Modules''' admin menu |
| 539 | * '''me_blgg''' is an internal name. It is similar to a normal database prefix |
| 540 | * '''_me_blgg''' is the language key which is used to display the module title |
| 541 | * '''URL''' is specifiled without permalinks enabled, and it is transformed to mod_rewrite URL automatically, if permalinks are enabled. Also, we used '''siteUrl''' in the URL, but it will be replaced with the full site URL with the slash at the end. |
| 542 | * '''My Bloggie by Me''' is the module description. |
| 543 | * '''modules/me/bloggie/|icon.png''' is a menu icon. This icon must be placed into the '''modules/me/bloggie/templates/base/images/icons/''' folder and named '''icon.png'''. The size should be 16x16 pixels. |
| 544 | * '''@iMax+1''' is order. Order is calculated in the previous string, and in this case, it will be added to the end of the list - which is preferable behavior. |
| 545 | |
| 546 | |
| 547 | Full module re-installation is needed because we have modified the '''config.php''' and '''install.sql''' files. |
| 548 | |
| 549 | The module is completed and you can download resulted module here(TODO:bloggie2.zip) to compare with your own, or to find mistakes if something went wrong. |
| 550 | |
| 551 | == 4. Blog functionality. == |
| 552 | |
| 553 | I have prepared new package to not waste the time for things already explained. Please uninstall your current '''Bloggie''' module and delete it from the '''modules/me''' directory, and then download a new one from here(TODO:bloggie3.zip) and install it. I have just removed unnecessary things and added settings and language keys related to Blog functionality. |
| 554 | |
| 555 | Our Bloggie will consist of several pages: |
| 556 | |
| 557 | * the latest blog posts page (our module homepage) |
| 558 | * Blog post view |
| 559 | * Adding a blog post page |
| 560 | * Editing the Blog post page |
| 561 | |
| 562 | The main thing in this section is how to deal with forms, and includes several helpful hints.\ |
| 563 | |
| 564 | == 4.1. Creating the database structure. == |
| 565 | |
| 566 | We will have only one database table with blog posts: |
| 567 | |
| 568 | {{{ |
| 569 | CREATE TABLE `me_blgg_posts` ( |
| 570 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , |
| 571 | `title` VARCHAR( 255 ) NOT NULL , |
| 572 | `text` TEXT NOT NULL , |
| 573 | `author_id` INT UNSIGNED NOT NULL , |
| 574 | `added` INT UNSIGNED NOT NULL , |
| 575 | INDEX ( `author_id` ) |
| 576 | ); |
| 577 | }}} |
| 578 | |
| 579 | add the above lines to the beginning of the '''install.sql''' file. Also, we need to add a "drop" database to the beginning of the '''uninstall.sql''' file: |
| 580 | |
| 581 | {{{ |
| 582 | DROP TABLE `me_blgg_posts`; |
| 583 | }}} |
| 584 | |
| 585 | Since you are aware of the basic SQL synatax, I will not go into a description of each symbol. In the general, our '''Bloggie''' will have '''title''' and '''text''', and other hidden fields are necessary too: |
| 586 | |
| 587 | * '''id''' - a unique identifier of each blog post. It is also the table primary key |
| 588 | * '''author_id''' - author's profile id |
| 589 | * '''added''' - blog post creation date/time |
| 590 | |
| 591 | I have indexed the '''author_id''' field because we may have a page with all user's posts in the future. |
| 592 | |
| 593 | == 4.2. Creating the add post page. == |
| 594 | |
| 595 | Add the following method to the '''MeBlggModule''' class: |
| 596 | |
| 597 | {{{ |
| 598 | function actionAdd () { |
| 599 | |
| 600 | if (!$GLOBALS['logged']['member'] && !$GLOBALS['logged']['admin']) { // check access to the page |
| 601 | $this->_oTemplate->displayAccessDenied (); |
| 602 | return; |
| 603 | } |
| 604 | |
| 605 | $this->_oTemplate->pageStart(); // all the code below will be wrapped by the user design |
| 606 | |
| 607 | bx_import ('BxTemplFormView'); // import forms class |
| 608 | |
| 609 | $oForm = new BxTemplFormView ($this->aForm); // create foprms class |
| 610 | |
| 611 | $oForm->initChecker(); // init form checker |
| 612 | |
| 613 | if ($oForm->isSubmittedAndValid ()) { // if form is submitted and not form errors were found, save form data |
| 614 | |
| 615 | $aValsAdd = array ( // add additional fields |
| 616 | 'added' => time(), |
| 617 | 'author_id' => $_COOKIE['memberID'], |
| 618 | ); |
| 619 | $iEntryId = $oForm->insert ($aValsAdd); // insert data to database |
| 620 | |
| 621 | if ($iEntryId) { // if post was successfully added |
| 622 | $sRedirectUrl = BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'view/' . $iEntryId; |
| 623 | header ('Location:' . $sRedirectUrl); // redirect to created post view page |
| 624 | exit; |
| 625 | } else { |
| 626 | MsgBox(_t('_Error Occured')); // if error occured display erroro message |
| 627 | } |
| 628 | |
| 629 | } else { |
| 630 | |
| 631 | echo $oForm->getCode (); // display form, if the form is not submiyyed or data is invalid |
| 632 | |
| 633 | } |
| 634 | |
| 635 | $this->_oTemplate->pageCode(_t('_me_blgg_page_title_add'), true); // output is completed, display all output above data wrapped by user design |
| 636 | } |
| 637 | }}} |
| 638 | |
| 639 | then modify the '''MeBlggModule''' class constructor the following way: |
| 640 | |
| 641 | {{{ |
| 642 | function MeBlggModule(&$aModule) { |
| 643 | parent::BxDolModule($aModule); |
| 644 | |
| 645 | $this->aForm = array( |
| 646 | |
| 647 | 'form_attrs' => array( |
| 648 | 'name' => 'form_bloggie', |
| 649 | 'action' => '', |
| 650 | 'method' => 'post', |
| 651 | ), |
| 652 | |
| 653 | 'params' => array ( |
| 654 | 'db' => array( |
| 655 | 'table' => 'me_blgg_posts', |
| 656 | 'key' => 'id', |
| 657 | 'submit_name' => 'submit_form', |
| 658 | ), |
| 659 | ), |
| 660 | |
| 661 | 'inputs' => array( |
| 662 | |
| 663 | 'title' => array( |
| 664 | 'type' => 'text', |
| 665 | 'name' => 'title', |
| 666 | 'caption' => _t('_me_blgg_form_caption_title'), |
| 667 | 'required' => true, |
| 668 | 'checker' => array ( |
| 669 | 'func' => 'length', |
| 670 | 'params' => array(3,255), |
| 671 | 'error' => _t ('_me_blgg_form_err_title'), |
| 672 | ), |
| 673 | 'db' => array ( |
| 674 | 'pass' => 'Xss', |
| 675 | ), |
| 676 | ), |
| 677 | |
| 678 | 'text' => array( |
| 679 | 'type' => 'textarea', |
| 680 | 'name' => 'text', |
| 681 | 'caption' => _t('_me_blgg_form_caption_text'), |
| 682 | 'required' => true, |
| 683 | 'html' => 2, |
| 684 | 'checker' => array ( |
| 685 | 'func' => 'length', |
| 686 | 'params' => array(20,64000), |
| 687 | 'error' => _t ('_me_blgg_form_err_text'), |
| 688 | ), |
| 689 | 'db' => array ( |
| 690 | 'pass' => 'XssHtml', |
| 691 | ), |
| 692 | ), |
| 693 | |
| 694 | 'submit' => array ( |
| 695 | 'type' => 'submit', |
| 696 | 'name' => 'submit_form', |
| 697 | 'value' => _t('_Submit'), |
| 698 | 'colspan' => true, |
| 699 | ), |
| 700 | |
| 701 | ), |
| 702 | ); |
| 703 | } |
| 704 | }}} |
| 705 | |
| 706 | The array we have placed into the constructor is our form description. The reason we have placed it in the description instead of the function is that we will reuse this array in the future when we create our edit post page. |
| 707 | |
| 708 | |
| 709 | The form description array can be described the following way: |
| 710 | |
| 711 | * form_attrs are regular HTML attributes which will be added to the <form> tag. |
| 712 | * params are special function parameters. This can have several parameters, but most important is the db sub-array which describes the table to save form data to. |
| 713 | |
| 714 | * table is the database table name to save data to |
| 715 | * key is the database primary key field (it is used to update data) |
| 716 | * submit_name is the name of the submit html form element and is used to determine automatically when the form is submitted. |
| 717 | |
| 718 | * the inputs array describes every form element, and each element consists of the following fields: |
| 719 | |
| 720 | * type is input type, like text, textarea, etc |
| 721 | * name is input the type name it also must match database field name |
| 722 | * caption is the indicated form element name |
| 723 | * required displays a red asterisk near the caption. Please note that it displays a red asterisk only. No real checking for mandatory fields is made if this field is true. For real checking see below. |
| 724 | * checker describes the checker function for the field. This is a place where real checking takes place. |
| 725 | * func is the checking function, like length, preg, avail, etc. |
| 726 | * params are checking function params. Params varies depending on the exact function. |
| 727 | * error is the message to display near the field if checking failed. |
| 728 | * db describes the database field to save input data to. The most important is the following parameter: |
| 729 | * pass is the function to pass data through, it validates data properly - to not allow an inappropriate value in a particular field. The value of this field may be Xss, XssHtml, Int, Float, Date, etc. |
| 730 | |
| 731 | This doesn't describe all the possible values of this array. For a complete list please refer to the '''inc/classes/BxDolForm.php''' file. |
| 732 | |