36
1 Lendr - A social library system with lending, tracking, wishlists and reviews Contents Lendr - A social library system with lending, tracking, wishlists and reviews ............ 1 Overview ....................................................................................................................................................... 3 Joomla! 3.0 Bootstrapped Component..................................................................................................... 3 Native Joomla! 3.0............................................................................................................................... 3 Responsive ........................................................................................................................................... 3 Made With Bootstrap ......................................................................................................................... 3 Libraries............................................................................................................................................... 3 Lending ................................................................................................................................................ 3 Reviews................................................................................................................................................. 3 The Purpose .................................................................................................................................................. 4 Beginning Development................................................................................................................................ 4 Step 0: Make Coffee ................................................................................................................................ 4 Step 1: Write basic component outline for files needed....................................................................... 4 Component Details .............................................................................................................................. 4 Basic Functions.................................................................................................................................... 4 Basic Files Needed............................................................................................................................... 5 Step 2: Write the Database table files ................................................................................................... 5 Step 3: Begin component folder and file creation ................................................................................ 6 Step 4: Write the install files, root file, controllers, and view controllers .......................................... 7 Install Files........................................................................................................................................... 7 Root file (lendr.php).......................................................................................................................... 10 Controllers ......................................................................................................................................... 11 View Controllers ............................................................................................................................... 13 Step 5: Create Models........................................................................................................................... 15 2 Beginning Development Wrap-up ....................................................................................................... 18 Functionality ............................................................................................................................................... 19 Step 1: Model File Details and Functions ........................................................................................... 19 Basic Files and Functions Needed.................................................................................................... 19 Step 2: Write the Models ...................................................................................................................... 20 Step 3: Incorporate Additional Resources .......................................................................................... 30 Gravatar............................................................................................................................................. 30 Open Library..................................................................................................................................... 30 Step 4: Start View Layouts and Styles ................................................................................................ 31 Writing the Files................................................................................................................................ 31 Remaining layouts............................................................................................................................. 36 Step 5: Javascript and CSS .................................................................................................................. 37 Conclusion ............................................................................................................................................. 40 More functionality ...................................................................................................................................... 40 Step 0: Make Coffee .............................................................................................................................. 40 Step 1: Create the modal windows ...................................................................................................... 41 Step 2: Writing lending & returning functionality ............................................................................ 45 Controller........................................................................................................................................... 45 Model.................................................................................................................................................. 46 Javascript ........................................................................................................................................... 47 Step 3: Adding wishlists, waitlists, and reviews ................................................................................. 47 Step 4: Searching books........................................................................................................................ 50 Step 5: Wrapping up............................................................................................................................. 57 Admin Configuration $ Cleanup.................................................................................................................. 57 Step 0: Make Coffee .............................................................................................................................. 57 Step 1: Writing the Admin Panel......................................................................................................... 58 Component Options .......................................................................................................................... 62 Step 2: Code Cleanup ........................................................................................................................... 65 Deletions............................................................................................................................................. 65 Book List View .................................................................................................................................. 68 Step 3: Menus and File Cleanup .......................................................................................................... 70 Create Menu Links ........................................................................................................................... 70

Lendr

Embed Size (px)

DESCRIPTION

Lendr - A social library system with lending, tracking, wishlists and reviews.pdf

Citation preview

  • 1

    Lendr - A social library system with lending, tracking, wishlists and reviews

    ContentsLendr - A social library system with lending, tracking, wishlists and reviews............1Overview.......................................................................................................................................................3

    Joomla!3.0BootstrappedComponent.....................................................................................................3

    Native Joomla! 3.0...............................................................................................................................3

    Responsive...........................................................................................................................................3

    Made With Bootstrap.........................................................................................................................3

    Libraries...............................................................................................................................................3

    Lending................................................................................................................................................3

    Reviews.................................................................................................................................................3

    ThePurpose..................................................................................................................................................4

    BeginningDevelopment................................................................................................................................4

    Step 0: Make Coffee................................................................................................................................4

    Step 1: Write basic component outline for files needed.......................................................................4

    Component Details..............................................................................................................................4

    Basic Functions....................................................................................................................................4

    Basic Files Needed...............................................................................................................................5

    Step 2: Write the Database table files...................................................................................................5

    Step 3: Begin component folder and file creation................................................................................6

    Step 4: Write the install files, root file, controllers, and view controllers..........................................7

    Install Files...........................................................................................................................................7

    Root file (lendr.php)..........................................................................................................................10

    Controllers.........................................................................................................................................11

    View Controllers...............................................................................................................................13

    Step 5: Create Models...........................................................................................................................15

    2

    Beginning Development Wrap-up.......................................................................................................18

    Functionality...............................................................................................................................................19

    Step 1: Model File Details and Functions...........................................................................................19

    Basic Files and Functions Needed....................................................................................................19

    Step 2: Write the Models......................................................................................................................20

    Step 3: Incorporate Additional Resources..........................................................................................30

    Gravatar.............................................................................................................................................30

    Open Library.....................................................................................................................................30

    Step 4: Start View Layouts and Styles................................................................................................31

    Writing the Files................................................................................................................................31

    Remaining layouts.............................................................................................................................36

    Step 5: Javascript and CSS..................................................................................................................37

    Conclusion.............................................................................................................................................40

    Morefunctionality......................................................................................................................................40

    Step 0: Make Coffee..............................................................................................................................40

    Step 1: Create the modal windows......................................................................................................41

    Step 2: Writing lending & returning functionality............................................................................45

    Controller...........................................................................................................................................45

    Model..................................................................................................................................................46

    Javascript...........................................................................................................................................47

    Step 3: Adding wishlists, waitlists, and reviews.................................................................................47

    Step 4: Searching books........................................................................................................................50

    Step 5: Wrapping up.............................................................................................................................57

    AdminConfiguration$Cleanup..................................................................................................................57

    Step 0: Make Coffee..............................................................................................................................57

    Step 1: Writing the Admin Panel.........................................................................................................58

    Component Options..........................................................................................................................62

    Step 2: Code Cleanup...........................................................................................................................65

    Deletions.............................................................................................................................................65

    Book List View..................................................................................................................................68

    Step 3: Menus and File Cleanup..........................................................................................................70

    Create Menu Links...........................................................................................................................70

  • 3

    Remove unnecessary files and functions.........................................................................................71

    Step 4: Additional Suggestions.............................................................................................................71

    Overview

    Joomla! 3.0 Bootstrapped Component Interested in what Lendr can do? Check the features below.

    Native Joomla! 3.0

    Lendr is an extension written for the Joomla! CMS system and is a native component using the latest platform code available.

    Responsive

    Lendr allows you to use it on any device size. A fully responsive layout allows easy use on a mobile device, tablet or desktop computer.

    Made With Bootstrap

    Integration with Twitter Bootstrap allows Lendr to have a both a beautiful interface as well as standardized buttons and layouts.

    Libraries

    Add books to your library catalogs and keep track of your entire collection. Track information about all your books in one easy location.

    Lending

    Lend books to others easily. Track who has borrowed which book and request to be added to waitlists when books are unavailable.

    Reviews

    Share your thoughts, opinions and ratings about books you hold in your collection or that you have borrowed from another library.

    4

    ThePurpose

    Lendr is made available as a walk-through tutorial for Joomla! 3 component development.

    BeginningDevelopment

    Step 0: Make Coffee Again, it is important to start your day and project off right. Get into a pattern, a rhythm and soon youll find your creativity, focus, and coding skills to be at the ready when you sit down to begin work. Dont overlook the importance of being in the right frame of mind when you begin work.

    Step 1: Write basic component outline for files needed The first thing to do is to create a rough overview of the files, folders, database tables, and associated fields. For our component we will be creating the following system.

    Component Details

    Name: Lendr

    Component: com_lendr

    Description: Lendr is a bootstrapped Joomla! 3.0 component which will allow users to create a profile, add their books to their library collection, view other users libraries, request a book to borrow, add books to a wishlist, and sign up to be on a waitlist for a particular book.

    Basic Functions

    User accounts / basic profiles Books / Libraries for Users Wishlists for books desired Lending / Borrowing of a book Requesting to borrow a book Waitlists for a book already lent

    Now we should write down our basic structure of files needed. This will not be a comprehensive list and will most definitely be modified as we progress through the process. However, having a

  • 5

    starting outline will help to keep things somewhat on track. Here is the initial outline of key files needed for Lendr.

    Basic Files Needed

    Controllers Models Views Tables Misc. Save List Add Edit Lend Delete Wish Review Request Default

    Book Default Library Profile Review Waitlist Wishlist

    Book Wishlist Library Profile Waitlist Review

    Book Wishlist Library Waitlist Review

    Install Router XML

    Now that we have this written out and a rough outline we begin creating these files in our folder structure.

    Step 2: Write the Database table files We begin by creating the database table files. We store these in the table folder located in the frontside of our component. Please refer back to the first article in this series to recall how your local environment should be configured. We create each of the files we described in our outline. Below is one of these files.

    /joomla_root/components/com_lendr/site/tables/book.php

    1.

  • 7

    11. controllers/ 12. helpers/ 13. language/ 14. models/ 15. tables/ 16. views/ 17. index.html 18. lendr.php 19. router.php 20. install.php 21. lendr.xml

    You can find the entire interactive layout in our Github repository.

    Each of these files and folders is important, though not all are required. We shall begin working through each of these files and the functions they contain. Along the way we will explain the purpose of each.

    Step 4: Write the install files, root file, controllers, and view controllers In this step we are going to add content to several files. First we will look at the install files, then we'll work with some controllers and finally we'll add our view controllers.

    Install Files

    The root level files are those files used by Joomla! during the install process. They are located outside the site and admin folders in your component folder. There is an XML file which is used to define the component details, and all associated files, menus, and languages; and there is also an install.php file. This install.php file holds a number of functions that run upon installation. The name is not specific but must be referenced properly in the XML file. The functions do not have to be utilized or even present but can be used to perform additional actions during the component install.

    Sample

    lendr.xml

    1. 2. COM_LENDR 3. 2013-01-31 4. Spark 5. [email protected] 6. http://lendr.websparkinc.com 7. Copyright Info 8. License Info 9. 1.0.0

    8

    10. COM_LENDR_DESCRIPTION

    This first block of details defines the component information. This information is displayed in the Joomla! Extension Manager and is also stored in the extensions database table.

    1. 2. 3. mysql.install.sql 4. 5.

    This block tells Joomla! where the SQL files are for the component. This is run by Joomla! during the installation process to create the necessary database tables. notice you can set your character set as well as the driver type to be used.

    You can also have an uninstall block with similar structure to define a SQL file to be run upon uninstall

    1. 2. assets 3. controllers 4. helpers 5. languages 6. models 7. tables 8. views 9. index.html 10. lendr.php 11. router.php 12.

    This block defines the folders that will be installed on the frontend of the Joomla! site in the components folder. It is not necessary to name every file but merely the folders and any root level files. All folders will be searched recursively and files added.

    1. install.php

    The script file can define the set of functions that are run upon installation. In our case we have named this file install.php.

    1. 2. languages/en-GB/en-GB.com_lendr.ini 3.

    The languages section defines the necessary language files. These will be installed in the languages folder under the appropriate language tag in the root of the Joomla! site. Here there are two language files, with one being a system language file for this component. This language file is used during the installation process and whenever information about your component is displayed while not within the component itself (e.g. the Extension Manager).

  • 9

    1. 2. COM_LENDR

    3. 4. COM_LENDR_SETTINGS 6.

    The next block defines the administrator side details both the admin menu as well as the admin side component files. Images can be referenced for the menu items. Image paths are related to the administrator component folder.

    Notice that a submenu can be defined but is not necessary.

    1. 2. controllers 3. languages 4. models 5. views 6. lendr.php 7. index.html 8. install.sql 9. 10. 11. 12. languages/en-GB/en-

    GB.com_lendr.ini 13. languages/en-GB/en-

    GB.com_lendr.sys.ini 14. 15. 16. 17.

    Also inside the administration tag are both a definition of the files and folders to be installed on the administrator side as well as the language file to be installed on the admin side. In our example we have added a folder tag, admin, to these elements to tell Joomla! which folder in the install package should be referenced for these. This can be named anything you desire. The system language file (second one) is explained in the next file description and walkthrough.

    See the entire lendr.xml file on Github. install.php

    1.

  • 11

    The lendr.php file in the root of the site folder is the first file recognized and read by Joomla! after installation. This file handles the redirection of tasks to other controllers, the loading of helper files, stylesheets, javascript, plugin libraries and other core pieces necessary throughout the entire component. The file below is the beginning of this main file. It will be expanded upon in future tutorials in this series.

    1.

  • 13

    22. 23. $viewClass = 'LendrViews' . ucfirst($viewName) .

    ucfirst($viewFormat); 24. $modelClass = 'LendrModels' . ucfirst($viewName); 25. 26. if (false === class_exists($modelClass)) 27. { 28. $modelClass = 'LendrModelsDefault'; 29. } 30. 31. $view = new $viewClass(new $modelClass, $paths); 32. $view->setLayout($layoutName); 33. 34. // Render our view. 35. echo $view->render(); 36. 37. return true; 38. } 39. }

    In our default controller we are accomplishing two things. First, we are providing the controller for the "default" action, typically this is the action triggered when no other task is defined. This still follows the Joomla! method for a single task per controller. This default controller will take the view, locate the appropriate view file, load the corresponding model and render the view. Joomla! 3 requires a model to be loaded with each view file loaded and so by following a standard naming convention between views and models we are able to link them and assign them without any extra code. If the model does not exist for some reason we load the default model.

    It's worth reviewing what SplPriorityQueue represents. In PHP this is an array which is an implementation of a special heap and sorts the data based on priority. The rest of the Lendr controllers will be defined as they are implemented.

    View Controllers

    Joomla! is a bit unique in how the views are handled. Joomla! makes use of a secondary controller to help in the rendering aspect of data and the assigning of variables to be used in the view layouts. This secondary controller is found in the views folder of the component and is often named similarly to the type of render desired. (e.g. html.php for rendering html, phtml.php for rendering a partial template, raw.php for rendering raw data, etc...). Below is one of the view controllers used by Lendr.

    Sample

    html.php joomla_root/components/com_lendr/views/book/html.php

    1.

  • 15

    Step 5: Create Models Joomla! models work like most MVC systems and handle the bulk of the data manipulation and data retrieval. Lendr models will be focused on heavily in the next tutorial so here we will look only at the general structure.

    Sample

    book.php joomla_root/components/com_lendr/models/book.php

    1.

  • 17

    59. protected function _getList($query, $limitstart = 0, $limit = 0) 60. { 61. $db = JFactory::getDBO(); 62. $db->setQuery($query, $limitstart, $limit); 63. $result = $db->loadObjectList(); 64. 65. return $result; 66. } 67. 68. /** 69. * Returns a record count for the query 70. * 71. * @param string $query The query. 72. * 73. * @return integer Number of rows for query 74. * 75. * @since 11.1 76. */ 77. protected function _getListCount($query) 78. { 79. $db = JFactory::getDBO(); 80. $db->setQuery($query); 81. $db->query(); 82. 83. return $db->getNumRows(); 84. } 85. 86. /* Method to get model state variables 87. * 88. * @param string $property Optional parameter name 89. * @param mixed $default Optional default value 90. * 91. * @return object The property where specified, the state object

    where omitted 92. * 93. * @since 11.1 94. */ 95. public function getState($property = null, $default = null) 96. { 97. if (!$this->__state_set) 98. { 99. // Protected method to auto-populate the model state. 100. $this->populateState(); 101. 102. // Set the model state set flag to true. 103. $this->__state_set = true; 104. } 105. 106. return $property === null ? $this->state : $this->state-

    >get($property, $default); 107. } 108. 109. /** 110. * Get total number of rows for pagination 111. */ 112. function getTotal() 113. {

    18

    114. if ( empty ( $this->_total ) ) 115. { 116. $query = $this->_buildQuery(); 117. $this->_total = $this->_getListCount($query); 118. } 119. 120. return $this->_total; 121. } 122. 123. /** 124. * Generate pagination 125. */ 126. function getPagination() 127. { 128. // Lets load the content if it doesn't already exist 129. if (empty($this->_pagination)) 130. { 131. $this->_pagination = new JPagination( $this->getTotal(), $this-

    >getState($this->_view.'_limitstart'), $this->getState($this->_view.'_limit'),null,JRoute::_('index.php?view='.$this->_view.'&layout='.$this->_layout));

    132. } 133. 134. return $this->_pagination; 135. } 136. }

    This default model incorporates some important functions that will be reused throughout the component. We will return to these functions in more detail in the following two tutorials.

    These Joomla! models are just two of the files that will be created with the Lendr component system. The other models are similar in nature and basic structure but will be written in more detail in the following tutorial.

    The rest of the Lendr models can be found in our Github repository.

    Beginning Development Wrap-up Now that we have created the basic folder structure of the component, written the database tables, install files, controllers, view controllers, and models our component should be installable. Of course while there is no functionality yet and the component merely creates an empty shell it does provide some sense of satisfaction to have an installable component. Be sure to examine our Github repository to view the other database tables, controllers, view controllers, and models which have not been written out here.

    Download

    Download the component as it exists to this point from the Github repository.

  • 19

    Download

    In the next tutorial we will dive into the actual functionality to be written to the various models.

    Functionality

    Youre going to need a strong cup of coffee today. In this tutorial we will be covering the details of the models and views needed for the Lendr component series weve begun in previous tutorials. If youre just joining this series, I recommend reading the first article, and then follow up with the initial setup article before continuing with this tutorial. Done with those articles? Ready for the next? Make sure you are ready to go by having your system setup and your code editor fired up ready to begin writing code. And dont forget your espresso.

    Step 1: Model File Details and Functions Now that weve gotten our base files created and started writing our models we need to get into the good stuff. The first thing to do is to sort out the models we will be writing to and the functions that need to be added. Here is a brief overview of those models and functions:

    Basic Files and Functions Needed

    Model Functions

    Default

    save delete set get getItem listItems getState getTotal getPagination

    Book _buildQuery _buildWhere

    Wishlist _buildQuery _buildWhere

    Profile _buildQuery _buildWhere

    Library _buildQuery _buildWhere

    Waitlist _buildQuery _buildWhere

    20

    Model Functions

    Review _buildQuery _buildWhere

    Once weve defined a brief overview of the models and functions well need we can begin writing the models. Its very important to keep the following principle in mind during this process. Our list is fluid and dynamic. We are able to return to our list and add or remove functions as necessary. Dont be afraid to revisit this list repeatedly as we progress and evaluate things. Its possible we can simplify by adding a function to a particular model, or maybe we need to rewrite a more abstract function which we can add to the default model. One thing is sure, we dont want to rewrite the same code over and over, the minute we find were starting down that path its time to consider how we abstract the code to a common model. Lets start writing our models.

    Step 2: Write the Models There are a handful of models which make up this Lendr component but we dont have the time to write all of them out here. Well focus on several key models that will help to demonstrate the bulk of the component and leave a few of the secondary models in the associated GitHub repository for you to review on your own. Well start by writing the book model. As I began thinking where to start coding I decided to start with the most specific and working out to the library model and then the profile model. The reason for this is simple. The book is the smallest unit, a library is made up of books and a profile then contains a library. I trust that helps you understand why we begin with the book model and work out from there. The very first model well look at will be the default model. We use the default model to store some basic functions that we want to have available in all our models and since we write Object Oriented code we dont want to re-write the same functions in each model.

    Model Files

    default.php

    1.

  • 21

    15. First we set some class level variables. This will allow us to reference them easily throughout the file.

    16. 17. function __construct() 18. { 19. 20. parent::__construct(); 21. } 22. 23. public function store($data=null) 24. { 25. $data = $data ? $data : JRequest::get('post'); 26. $row = JTable::getInstance($data['table'],'Table'); 27. 28. $date = date("Y-m-d H:i:s"); 29. 30. // Bind the form fields to the table 31. if (!$row->bind($data)) 32. { 33. return false; 34. } 35. 36. $row->modified = $date; 37. if ( !$row->created ) 38. { 39. $row->created = $date; 40. } 41. 42. // Make sure the record is valid 43. if (!$row->check()) 44. { 45. return false; 46. } 47. 48. // Store the web link table to the database 49. if (!$row->store()) 50. { 51. return false; 52. } 53. 54. return $row; 55. }

    Because most of our models will be storing data in some way we are going to write a standard store function into our default model. We will extend this function as needed in various specific cases but here we do the basic store functionality. This function will include more error checking and reporting on those errors when we get into the clean-up portion of the tutorial series.

    1. /** 2. * Modifies a property of the object, creating it if it does not

    already exist. 3. * 4. * @param string $property The name of the property. 5. * @param mixed $value The value of the property to set. 6. *

    22

    7. * @return mixed Previous value of the property. 8. * 9. * @since 11.1 10. */ 11. public function set($property, $value = null) 12. { 13. $previous = isset($this->$property) ? $this->$property : null; 14. $this->$property = $value; 15. 16. return $previous; 17. } 18. 19. public function get($property, $default = null) 20. { 21. return isset($this->$property) ? $this->$property : $default; 22. }

    Often we will have class level variables in each of our models that we will need to set from various other locations. Rather than allowing those variables to be set directly by referencing them, we will use get and set functions to better control and clean variables as necessary. Currently these two functions do not incorporate any additional features.

    1. /** 2. * Build a query, where clause and return an object 3. * 4. */ 5. public function getItem() 6. { 7. $db = JFactory::getDBO(); 8. 9. $query = $this->_buildQuery(); 10. $this->_buildWhere($query); 11. $db->setQuery($query); 12. 13. $item = $db->loadObject(); 14. 15. return $item; 16. } 17. 18. /** 19. * Build query and where for protected _getList function and return a

    list 20. * 21. * @return array An array of results. 22. */ 23. public function listItems() 24. { 25. $query = $this->_buildQuery(); 26. $query = $this->_buildWhere($query); 27. 28. $list = $this->_getList($query, $this->limitstart, $this->limit); 29. 30. return $list; 31. }

  • 23

    These two functions are the basic functions for getting a single item and getting a list of items. Again, most models will need to retrieve a single row and multiple rows from the database. We will extend these functions as necessary in specific models.

    The _buildQuery and _buildWhere functions are not present in the default model. These functions are specific to each model and are available in each specific model. Note: We are using an underscore ( _ ) to identify protected functions.

    1. /** 2. * Gets an array of objects from the results of database query. 3. * 4. * @param string $query The query. 5. * @param integer $limitstart Offset. 6. * @param integer $limit The number of records. 7. * 8. * @return array An array of results. 9. * 10. * @since 11.1 11. */ 12. protected function _getList($query, $limitstart = 0, $limit = 0) 13. { 14. $db = JFactory::getDBO(); 15. $db->setQuery($query, $limitstart, $limit); 16. $result = $db->loadObjectList(); 17. 18. return $result; 19. } 20. 21. /** 22. * Returns a record count for the query 23. * 24. * @param string $query The query. 25. * 26. * @return integer Number of rows for query 27. * 28. * @since 11.1 29. */ 30. protected function _getListCount($query) 31. { 32. $db = JFactory::getDBO(); 33. $db->setQuery($query); 34. $db->query(); 35. 36. return $db->getNumRows(); 37. }

    These two functions are used for help in retrieving the list from the database and retrieving the count of the list returned by the query.

    1. /* Method to get model state variables 2. * 3. * @param string $property Optional parameter name 4. * @param mixed $default Optional default value 5. *

    24

    6. * @return object The property where specified, the state object where omitted

    7. * 8. * @since 11.1 9. */ 10. public function getState($property = null, $default = null) 11. { 12. if (!$this->__state_set) 13. { 14. // Protected method to auto-populate the model state. 15. $this->populateState(); 16. 17. // Set the model state set flag to true. 18. $this->__state_set = true; 19. } 20. 21. return $property === null ? $this->state : $this->state-

    >get($property, $default); 22. } 23. 24. /** 25. * Get total number of rows for pagination 26. */ 27. function getTotal() 28. { 29. if ( empty ( $this->_total ) ) 30. { 31. $query = $this->_buildQuery(); 32. $this->_total = $this->_getListCount($query); 33. } 34. 35. return $this->_total; 36. } 37. 38. /** 39. * Generate pagination 40. */ 41. function getPagination() 42. { 43. // Lets load the content if it doesn't already exist 44. if (empty($this->_pagination)) 45. { 46. $this->_pagination = new JPagination( $this->getTotal(), $this-

    >getState($this->_view.'_limitstart'), $this->getState($this->_view.'_limit'),null,JRoute::_('index.php?view='.$this->_view.'&layout='.$this->_layout));

    47. } 48. 49. return $this->_pagination; 50. } 51. }

    The final three functions at the end of the default model are used when dealing with pagination. These functions will be discussed in more detail in the subsequent tutorials as we begin implementation of pagination throughout the component.

  • 25

    book.php joomla_root/components/com_lendr/models/book.php

    1.

  • 27

    18. $this->_user_id = $app->input->get('user_id',JFactory::getUser()->id);

    19. }

    We set some default values for class level variables in our construct function. If we do not have a user_id set for the library class we are setting it to the current logged in users ID.

    1. function getItem() 2. { 3. $library = parent::getItem(); 4. 5. $bookModel = new LendrModelsBook(); 6. $bookModel->set('_user_id',$this->_user_id); 7. $library->books = $bookModel->listItems(); 8. 9. return $library; 10. }

    This is a great example of extending a base level class. Notice that we have a function named getItem. This is the same function name as is present in the default model. When the getItem function is called for the library model it will run this function. In this instance we have grabbed the basic details of the item (in this case a library object) by using the default getItem function, then we add to that object below. Notice we are using the set method to set the user_id on the book model.

    1. function listItems() 2. { 3. $bookModel = new LendrModelsBook(); 4. $libraries = parent::listItems(); 5. 6. $n = count($libraries); 7. 8. for($i=0;$i_library_id = $library->id; 13. $library->books = $bookModel->listItems(); 14. } 15. 16. return $libraries; 17. }

    Again, similar to the single item function we are first calling the listItems from the parent default model and then adding the books to the individual objects as well.

    Note: Do you see repeat code between the single and list functions? This means we could extract that code into a separate function and then simply call that function to reduce overall lines. We did not do that here simply for legibility and ease of understanding.

    1. protected function _buildQuery() 2. {

    28

    3. $db = JFactory::getDBO(); 4. $query = $db->getQuery(TRUE); 5. 6. $query->select("l.library_id, l.name, l.description"); 7. $query->from("#__lendr_libraries as l"); 8. 9. $query->select("u.username, u.name"); 10. $query->leftjoin("#__users as u ON u.id = l.user_id"); 11. 12. $query->select("p.*"); 13. $query->leftjoin("#__user_profiles as p on p.user_id = u.id"); 14. 15. return $query; 16. } 17. 18. 19. protected function _buildWhere(&$query) 20. { 21. 22. if(is_numeric($this->_user_id)) 23. { 24. $query->where('l.user_id = ' . (int) $this->_user_id); 25. } 26. 27. if(is_numeric($this->_library_id)) 28. { 29. $query->where('l.library_id = ' . (int) $this->_library_id); 30. } 31. 32. $query->where('l.published = '. (int) $this->_published); 33. 34. return $query; 35. } 36. 37. }

    As referenced in the default model and explained in the preceding book model. These two functions are the query and where pieces used by the default model for the single and list item functions.

    profile.php joomla_root/components/com_lendr/models/profile.php

    1.

  • 29

    13. $app = JFactory::getApplication(); 14. 15. //If no User ID is set to current logged in user 16. $this->_user_id = $app->input->get('profile_id',

    JFactory::getUser()->id); 17. 18. parent::__construct(); 19. } 20. 21. function getItem() 22. { 23. 24. $profile = JFactory::getUser($this->_user_id); 25. $userDetails = JUserHelper::getProfile($this->_user_id); 26. $profile->details = isset($userDetails->profile) ? $userDetails-

    >profile : array(); 27. 28. $libraryModel = new LendrModelsLibrary(); 29. $libraryModel->set('_user_id',$this->_user_id); 30. $profile->library = $libraryModel->getItem(); 31. 32. $waitlistModel = new LendrModelsWaitlist(); 33. $waitlistModel->set('_waitlist', TRUE); 34. $profile->waitlist = $waitlistModel->getItem(); 35. 36. $profile->isMine = JFactory::getUser()->id == $profile->id ? TRUE

    : FALSE; 37. 38. return $profile; 39. }

    In this function we have no reference to the parent getItem. The profile is unique in its structure and because we are building on the Joomla! 3 CMS we have the option of not including an extension specific set of tables and functions related to users and profiles.

    Lendr has very limited profile fields and only needs certain fields that are readily available in the Joomla! profile plugin (included by default in Joomla 3.)

    After retrieving the profile we then instantiate a couple additional models to grab associated data, specifically the library and waitlist model. In the future we will return to this function to add the wishlists and reviews.

    Important: Be sure to enable the Joomla! 3 profile plugin listed in the extension manager.

    1. protected function _buildQuery() 2. { 3. $db = JFactory::getDBO(); 4. $query = $db->getQuery(TRUE); 5. 6. $query->select("u.id, u.username, u.name, u.email,

    u.registerDate"); 7. $query->from("#__users as u"); 8. 9. $query->select("COUNT(b.book_id) as totalBooks");

    30

    10. $query->leftjoin("#__lendr_books as b on b.user_id = u.id"); 11. 12. $query->select("COUNT(r.review_id) as totalReviews"); 13. $query->leftjoin("#__lendr_reviews as r on r.user_id = u.id"); 14. 15. return $query; 16. }

    In this function we left join a few additional tables to include total number of books added by a user and total number of reviews written.

    1. protected function _buildWhere($query) 2. { 3. $query->group("u.id"); 4. 5. return $query; 6. } 7. 8. }

    Because we are counting rows from a joined table as a field in our results we need to group things by an ID field to make sure we get all possible results. Here we group by the user id field.

    Note: The additional models will be available in our GitHub repository and filled out in a later article.

    Step 3: Incorporate Additional Resources As we write this component there are certain aspects where it would be nice to incorporate third party features rather than reinventing the wheel. We have been able to simplify our styling and layouts by utilizing the Bootstrap classes available with Joomla! 3. Other handy resources that can be used include, Gravatar and Open Library. If you are unfamiliar with these tools you can read more about them on their respective websites. Below is a brief explanation of how they are used in Lendr.

    Gravatar

    Gravatar provides a simple way to retrieve an image or avatar associated with an email address. Lendr makes use of this to display profile pictures in an incredibly straightforward way. You will see the code necessary to make it happen when we write the view layouts in the step below.

    Open Library

    Open Library provides a great way to retrieve a book cover specific to an ISBN. This allows us to easily include a cover with each book without the hassle of maintaining storage space, image uploads etc. Open Library has several fields which can be used to reference the book cover and

  • 31

    return the image, Lendr makes use of the ISBN which is part of the Add Book form found below. You will find the code in the layouts below.

    Step 4: Start View Layouts and Styles The first thing we do will be to return to the entry point for the component. This is the default controller as we reference it within the root lendr.php file. After writing out our models its clear we need to update where the user starts. We have changed the following line of code in the default.php controller:

    joomla_root/components/com_lendr/controllers/default.php

    1. $layoutName = $app->input->getWord('layout', 'list');

    This will now send the user to the list view of the profiles. Thats the first view well look at. In our views folder we have a profile folder with the following structure in it:

    Folder Structure

    1. profile 2. tmpl 3. _entry.php 4. index.html 5. list.php 6. profile.php 7. html.php 8. index.html 9. phtml.php

    Writing the Files

    We will look first at the html.php file. This file is the default type we referenced by Joomla! and the current naming conventions. We saw the basic structure of these files in the previous article.

    Individual Files

    html.php joomla_root/components/com_lendr/views/profile/html.php

    1.

  • 33

    Note: This file is named specific to the folder structure that defines it. Note: Because this component uses the new MVC structure notice that we are extending JViewHTML with this class. Aside: Because we have called the view helper it is worth reviewing that file now. view.php joomla_root/components/com_lendr/helpers/view.php

    1.

  • 35

    11.

    As mentioned we are making use of the Gravatar API to display the profile image associated with their email address. Notice also the extensive use of Bootstrap styles and layout. This provides an enormous time saving opportunity.

    Note: Remember that we are viewing a partial template based on the file name. list.php joomla_root/components/com_lendr/views/profile/tmpl/list.php

    1.

    2. 3. 7.

    This file is the main file that the component will send users to by default. This was set previously in our default controller and referenced above. This list view has made use of the standard html.php file located in the profiles view folder and you will notice the use of the _profileListView partial template. To word this differently, we have called this view which loads up the container for our list of profiles. Inside this view we are then making a call to a partial template view (_entry.php) which will display each of the appropriate individual profile layouts.

    Note: Partial templates allow for blocks of html to be reused in multiple locations and all locations be updated by editing a single file. profile.php

    1.

  • 37

    Weve reviewed all the layouts in the profile tab but through the process weve found additional views called to be rendered within the profile layout. For the sake of the length of this article we will not list each view and the code found within. Instead, you can view the code associated with each of these view directly in the GitHub repository.

    Step 5: Javascript and CSS The last piece well look at in this article is the beginning of the Javascript and CSS associated with Lendr. Because Lendr uses Bootstrap and jQuery the modal window referenced in the previous step for adding a new book is included automatically and we dont have to write any specific Javascript functions to accomplish that. There are quite a few parts of the system though where we will need to write specific javascript code and there will also be times when specific CSS styles will be necessary. We will add the following helper file to address styles and javascript.

    joomla_root/components/com_lendr/helpers/style.php

    1.

  • 39

    1.

  • 41

    Step 1: Create the modal windows In this article we take a more of a relaxed approach and work on some additional features and detail work. First you will notice that weve added more modal windows. Weve done all our modal windows the same way (utilizing the Bootstrap technique). In order to give a bit more detail Ill explain the two options and then detail the option weve chosen. First you can load a view and layout via AJAX and using the typical Joomla method which although using a modal window loads an entire view file when a button or link is clicked. This has been historically the standard method for Joomla to load modal windows (think about them a bit like iframes). The second method is to load the modal window details onto the page when the page is initially loaded however the modal window (in essence, a div containing the view) is hidden by default on the page load and is not visible until activated by a link or button click.

    Ive chosen this second method for our modals within Lendr for a couple of reasons. By adding the modal div into the page on load but keeping it hidden this puts all the page load speed into the initial page load. While this may make you think the page will load slower initially this is a quite miniscule addition. On the other hand, by already loading the HTML into the page when the button or link is clicked the modal appears instantly (since it has already been loaded). This tends to make the page feel as though it has loaded incredibly fast. While it may be a personal preference, the quickness is one that I notice and therefore prefer. A second reason for choosing this modal loading method resides in the fact that there are only a few data fields being added to the modal. Because the requested data is minimal it is not a very difficult task to assign those variables to the modal on the fly instead of requesting an entire page via AJAX. Again, this is a bit of a personal preference in regards to speed.

    Lets look at the lines of code necessary to include a modal into our page. First, well look at the html.php file for the container view. This might also be considered the parent view for the modal window we plan to load.

    html.php /joomla_root/components/com_lendr/views/book/html.php

    1. 5. 6. 7. 8. 9. 10. 11. 12. 13.

  • 43

    16.

  • 45

    66. 67. 68. 69. 70. 71. 72. 73. 74. 75.

    This will then render the entire secondary view on the page, but because we have written our code using Bootstrap CSS the div will be hidden until actvated.

    I will continue to use this code repeatedly to load modal windows throughout Lendr. Youll notice there are two different calls I will make to load modals. One is a direct loading of a modal window (this is when no additional data is needed in the modal) and the second uses a javascript call to load the modal window (Ill use this second method when I want to add a variable to the modal before displaying it).

    You can find the rest of the modal files (similar in structure) in our Github repository.

    Step 2: Writing lending & returning functionality Now that we have our modal windows loading and displaying additional information we want to begin adding functionality to Lendr through the use of these modals. First well look at the actual core process of lending and returning. In case youre wondering, were not building any advanced tracking or monitoring system into Lendr (this may be something Ill look at in greater detail later if its requested). In Lendr well simply let you lend a book and mark it as returned when you receive it back. There are a couple of files related to the lending and returning process. Well look at each in more detail below:

    Controller

    First we shall review the lend.php controller file which serves as the main controller for both lending and returning.

    joomla_root/components/com_lendr/controllers/lend.php

    1.

  • 47

    Javascript

    This is the associated javascript functions used with lending and returning. As I mentioned earlier I am creating a function to first load the modal (so I can inject variables into the modal window). The second function is used to actually lend the book. I am using a jQuery AJAX call to pass the form data to the lend controller (listed above). If the controller/model executes successfully then the modal window is closed.

    joomla_root/components/com_lendr/assets/js/lendr.js

    1. function loadLendModal(book_id, borrower_id, borrower, waitlist_id) 2. { 3. jQuery("#lendBookModal").modal('show'); 4. jQuery('#borrower_name').html(borrower); 5. jQuery("#book_id").val(book_id); 6. jQuery("#borrower_id").val(borrower_id); 7. jQuery("#waitlist_id").val(waitlist_id); 8. } 9. 10. function lendBook() 11. { 12. var lendForm = {}; 13. jQuery("#lendForm :input").each(function(idx,ele){ 14. lendForm[jQuery(ele).attr('name')] = jQuery(ele).val(); 15. }); 16. 17. jQuery.ajax({ 18.

    url:'index.php?option=com_lendr&controller=lend&format=raw&tmpl=component',

    19. type:'POST', 20. data:lendForm, 21. dataType:'JSON', 22. success:function(data) 23. { 24. if ( data.success ) 25. { 26. jQuery("#lendBookModal").modal('hide'); 27. } 28. } 29. }); 30. }

    There are several different places where you may notice the lack of error messages. Well be writing all of these at once in our clean up article still to come.

    Step 3: Adding wishlists, waitlists, and reviews

    48

    There are three areas related to books that we are going to work on. The wishlist and waitlist functionality is pretty simple. Both of these will simply load a modal and add the specific book to either the wishlist or waitlist of the user. Again, this code is similar in most aspects to the other modal code and lender codes listed above. Because the review code has a bit more custom work than the other two well focus on the code involved with the review process.

    Note: You can review both the wishlist and waitlist code in the GitHub repository.

    Originally the intention was to utilize the review controller for the new reviews, however upon further thought I decided that technically a new review should follow the same add controller as other parts of the system. This involved a bit of a rewrite on the add controller to properly route the data to the correct model.

    A review is created from a modal window. The modal loads a form which holds the title and summary of the review. Hidden fields track the book and user submitting the review. The form for a new review is below.

    joomla_root/components/com_lendr/views/review/tmpl/_add.php

    1.

    2. 3. 4. 5. 6. 7. 8. 9.

  • 49

    Note: We are passing the table and other fields necessary to route to the appropriate model and function.

    Below is the javascript associated with the review process.

    joomla_root/components/com_lendr/assets/js/lendr.js

    1. //add a review 2. function addReview() 3. { 4. var reviewInfo = {}; 5. jQuery("#reviewForm :input").each(function(idx,ele){ 6. reviewInfo[jQuery(ele).attr('name')] = jQuery(ele).val(); 7. }); 8. 9. jQuery.ajax({ 10.

    url:'index.php?option=com_lendr&controller=add&format=raw&tmpl=component',

    11. type:'POST', 12. data:reviewInfo, 13. dataType:'JSON', 14. success:function(data) 15. { 16. if ( data.success ){ 17. console.log(data.html); 18. jQuery("#review-list").append(data.html); 19. jQuery("#newReviewModal").modal('hide'); 20. }else{ 21. 22. } 23. } 24. }); 25. 26. }

    In this function we perform a couple of actions. First, we use a nifty jQuery loop to get all the form data to pass through to the controller. After that submit the form and wait for the response. If the response is successful then we append the response to the review list and hide the modal window. This means I am passing the full html row back from the ajax call. Below is how that is handled in the updated controller.

    joomla_root/components/com_lendr/controllers/add.php

    1.

  • 51

    The search process is an interesting one to evaluate. There are again a couple of options that can be pursued. Either you can incorporate a full functioning search system into your component or you can take advantage of the system already built into Joomla in the Finder component, module, and plugins. While it may not be appropriate in all instances to use the Finder system, in the Lendr component we will take this opportunity to integrate with Finder. By integrating with Finder we will first simplify the amount of code and structure that must be added to Lendr, and secondly we will also be able to demonstrate the code necessary to create a plugin for a new content type with Finder.

    The plugin I write for Finder is a simple one and certainly does not demonstrate all the typical capabilities of the plugin system. Below is the XML file associated with the Finder plugin we are writing (I call it Smart Search - Books).

    books.xml joomla_root/plugins/finder/books/books.xml

    1. 2. 3. Smart Search - Books 4. Joomla! Project 5. March 2013 6. (C) 2005 - 2013 Open Source Matters. All rights

    reserved. 7. GNU General Public License version 2 or later; see

    LICENSE.txt 8. [email protected] 9. www.joomla.org 10. 3.0.0 11. 12. 13. books.php 14. index.html 15. 16.

    This XML file will just create the standard fields to be used when installing the Lendr Books plugin. The second file necessary for the search functionality is created below.

    books.php joomla_root/plugins/finder/books/books.php

    1.

  • 53

    66. * @var string 67. * @since 2.5 68. */ 69. protected $state_field = 'published'; 70. 71. /** 72. * Load the language file on instantiation. 73. * 74. * @var boolean 75. * @since 3.1 76. */ 77. protected $autoloadLanguage = true; 78. 79. /** 80. * Method to remove the link information for items that have been

    deleted. 81. * 82. * @param string $context The context of the action being

    performed. 83. * @param JTable $table A JTable object containing the record

    to be deleted 84. * 85. * @return boolean True on success. 86. * 87. * @since 2.5 88. * @throws Exception on database error. 89. */ 90. public function onFinderDelete($context, $table) 91. { 92. if ($context == 'com_lendr.book') 93. { 94. $id = $table->id; 95. } 96. elseif ($context == 'com_finder.index') 97. { 98. $id = $table->link_id; 99. } 100. else 101. { 102. return true; 103. } 104. // Remove the items. 105. return $this->remove($id); 106. } 107. 108. /** 109. * Method to determine if the access level of an item changed. 110. * 111. * @param string $context The context of the content passed to

    the plugin. 112. * @param JTable $row A JTable object 113. * @param boolean $isNew If the content has just been created 114. * 115. * @return boolean True on success. 116. * 117. * @since 2.5 118. * @throws Exception on database error.

    54

    119. */ 120. public function onFinderAfterSave($context, $row, $isNew) 121. { 122. // We only want to handle books here 123. if ($context == 'com_lendr.book') 124. { 125. // Check if the access levels are different 126. if (!$isNew && $this->old_access != $row->access) 127. { 128. // Process the change. 129. $this->itemAccessChange($row); 130. } 131. 132. // Reindex the item 133. $this->reindex($row->id); 134. } 135. return true; 136. } 137. 138. /** 139. * Method to reindex the link information for an item that has been

    saved. 140. * This event is fired before the data is actually saved so we are

    going 141. * to queue the item to be indexed later. 142. * 143. * @param string $context The context of the content passed to

    the plugin. 144. * @param JTable $row A JTable object 145. * @param boolean $isNew If the content is just about to be

    created 146. * 147. * @return boolean True on success. 148. * 149. * @since 2.5 150. * @throws Exception on database error. 151. */ 152. public function onFinderBeforeSave($context, $row, $isNew) 153. { 154. // We only want to handle books here 155. if ($context == 'com_lendr.book') 156. { 157. // Query the database for the old access level if the item isn't

    new 158. if (!$isNew) 159. { 160. $this->checkItemAccess($row); 161. } 162. } 163. 164. return true; 165. } 166. 167. /** 168. * Method to update the link information for items that have been

    changed

  • 55

    169. * from outside the edit screen. This is fired when the item is published,

    170. * unpublished, archived, or unarchived from the list view. 171. * 172. * @param string $context The context for the content passed to

    the plugin. 173. * @param array $pks A list of primary key ids of the

    content that has changed state. 174. * @param integer $value The value of the state that the

    content has been changed to. 175. * 176. * @return void 177. * 178. * @since 2.5 179. */ 180. public function onFinderChangeState($context, $pks, $value) 181. { 182. // We only want to handle articles here 183. if ($context == 'com_lendr.book') 184. { 185. $this->itemStateChange($pks, $value); 186. } 187. // Handle when the plugin is disabled 188. if ($context == 'com_plugins.plugin' && $value === 0) 189. { 190. $this->pluginDisable($pks); 191. } 192. } 193. 194. /** 195. * Method to index an item. The item must be a FinderIndexerResult

    object. 196. * 197. * @param FinderIndexerResult $item The item to index as an

    FinderIndexerResult object. 198. * @param string $format The item format 199. * 200. * @return void 201. * 202. * @since 2.5 203. * @throws Exception on database error. 204. */ 205. protected function index(FinderIndexerResult $item, $format =

    'html') 206. { 207. // Check if the extension is enabled 208. if (JComponentHelper::isEnabled($this->extension) == false) 209. { 210. return; 211. } 212. 213. $item->setLanguage(); 214. 215. $extension = ucfirst(substr($item->extension, 4)); 216. 217. $item->url = $this->getURL($item->id, $item->extension, $this-

    >layout);

    56

    218. $item->route = 'index.php?option='.$this->extension.'&view=book&layout='.$this->layout.'&id='.$item->book_id;

    219. 220. // Add the type taxonomy data. 221. $item->addTaxonomy('Type', 'Book'); 222. 223. // Add the language taxonomy data. 224. $item->addTaxonomy('Language', $item->language); 225. 226. // Index the item. 227. $this->indexer->index($item); 228. } 229. 230. /** 231. * Method to get the SQL query used to retrieve the list of books. 232. * 233. * @param mixed $sql A JDatabaseQuery object or null. 234. * 235. * @return JDatabaseQuery A database object. 236. * 237. * @since 2.5 238. */ 239. protected function getListQuery($sql = null) 240. { 241. $db = JFactory::getDbo(); 242. // Check if we can use the supplied SQL query. 243. $sql = $sql instanceof JDatabaseQuery ? $sql : $db-

    >getQuery(true); 244. $sql->select('b.book_id as id, b.title, b.author, b.summary,

    b.pages, b.publish_date'); 245. $sql->from('#__lendr_books AS b'); 246. $sql->where($db->quoteName('b.book_id') . ' > 1'); 247. 248. return $sql; 249. } 250. 251. /** 252. * Method to get a SQL query to load the published state 253. * 254. * @return JDatabaseQuery A database object. 255. * 256. * @since 2.5 257. */ 258. protected function getStateQuery() 259. { 260. $sql = $this->db->getQuery(true); 261. $sql->select($this->db->quoteName('b.book_id')); 262. $sql->select($this->db->quoteName('b.published') . ' AS

    book_state'); 263. $sql->from($this->db->quoteName('#__lendr_books') . ' AS b'); 264. 265. return $sql; 266. } 267. }

  • 57

    These functions are used by Finder to index the correct table, load the data and route it correctly in the search results. Because of the level of this tutorial I am not going to go into too much detail regarding each of these functions nor will I be loading up the secondary route helpers which are often used to make the component language specific and other additional features. If you are interested in learning more about the search plugin system leave a message in the comments or contact me for more information.

    Step 5: Wrapping up In this article weve covered quite a few functions, structural design, and additional ideas which can be applied to any other component. Weve looked at how to best utilize Bootstrap for modals, weve taken a deeper look at javascript functionality and use and then weve expanded our use beyond components to integration with a secondary plugin. I have purposely not included every file written or every function modified simply for the purpose of keeping the focus of this article on the thought process and concepts surrounding component development and not individual functions which may be more readily discerned from previous tutorials. If for any reason you have questions about any of the code written dont hesitate to ask.

    In the next article we will begin wrapping things up and finalizing the code. We will cover the administrator interface, proper use of live updates on the page when an AJAX call is completed, and we will begin cleaning up the code, removing unnecessary files, and looking at ways we can simplify or reduce our code.

    Download

    Download the component as it exists to this point from the Github repository.

    Download

    AdminConfiguration$Cleanup

    Step 0: Make Coffee Yes, you are correct. As with each development article previously we are going to begin with a fresh cup of coffee. Well start getting our minds ready for writing code and begin focusing on the tasks at hand. This article will hopefully not be as detailed as some of the previous articles and so I trust will not require an extra cup of coffee and with luck you may make it through the majority of this tutorial before you reach the end of your coffee.

    58

    Step 1: Writing the Admin Panel The Joomla administrator panel has a variety of uses currently and there are several different ways in which it can be used most effectively. It could be suggested that the administrator panel can be a unique opportunity for each component to use as needed. We have written Lendr to be a front-side application and most of the functionality and purpose of the component is utilized by front-end users. Because this is the case we will use the administrator panel in Lendr purely for additional functionality and some basic option settings. By doing so we will not have duplicate code stored in both the administrator component models, views, and controllers, and yet we will continue to be able to demonstrate proper code structure for the administrator side. Hopefully by following this approach you will be able to understand when and how the administrator panel can be used most effectively.

    The following files have been created for the administrator side code: a helper file, a controller, a model, a view, an access file, a config file, and our language file.

    We will work through each of these files in turn starting with the primary entry point: lendr.php.

    joomla_root/administrator/components/com_lendr/lendr.php

    1.

  • 59

    1.

  • 61

    Notice our language file is being used for all language strings. If we wanted an image to appear next to our component title we would simply pass a second reference when defining the title line.

    Note: Remember in previous articles when viewing the admin we had an error being displayed? Thats because we were not setting a page title and the Isis template was expecting one.

    In this function we also call our helper class. Now is a good time to review what that helper class does and how its used. This helper class contains a few useful functions for use throughout the component administration.

    Note: Note: It should be noted that we never included this helper directly but rather the Joomla auto-loader (as defined in the main lendr.php file) has found the file automatically based on our naming conventions and loaded it when we made the call. joomla_root/administrator/components/com_lendr/helpers/lendr.php

    1.

  • 63

    The data used for this view (when you navigate to the com_config page for the Lendr component) is pulled from one specific file. The config.xml file also stored within the root of the lendr component on the administrator side. Lets look at that file now.

    joomla_root/administrator/components/com_lendr/config.xml

    1. 2. 3. 7. 8. 13. 14. JNO 15. JYES 16. 17. 18. 23. 24. JNO 25. JYES 26. 27. 28. 33. 34. JNO 35. JYES 36. 37. 38. 43. 44. JNO 45. JYES 46. 47. 48. 49.

    64

    50. 54. 55. 61. 62.

    In this file you will see we have defined to fieldsets. These fieldsets correspond to the tabs located in the admin side when viewing the com_config options. The first fieldset displays the specific parameters we wish to allow to be configured by the admin users, and the second fieldset deals with the ability to see the options button.

    Note: You can define as many unique fieldsets (tabs) as you wish within your component.

    The following are important things to keep in mind when viewing and creating this file. First, you should use your language file to define all the appropriate strings. Secondly, you can, and should, define classes for your fields so they use the appropriate styles. You can define multiple types of fields as you would use in other parts of Joomla, in this particular instance we are mainly utilizing radio buttons to toggle either a yes or no value.

    Now we need to explore the code thats been added to the front side which utilizes these new parameters.

    Well look at two instances in particular. First, the option for a required_account. This option allows us to define whether or not a person should be logged in before being able to view Lendr. We implement this option in the following file.

    joomla_root/components/com_lendr/controllers/default.php

    1. // Line 11 - 19 2. $params = JComponentHelper::getParams('com_lendr'); 3. if ($params->get('required_account') == 1) 4. { 5. $user = JFactory::getUser(); 6. if ($user->get('guest')) 7. { 8. $app-

    >redirect('index.php',JText::_('COM_LENDR_ACCOUNT_REQUIRED_MSG')); 9. } 10. }

    We first get our parameters object using the Joomla Component Helper. Once we have those params we can then check to see if we are requiring the users to have an account. If we are then

  • 65

    we check to see if they are logged in and if they are not we send them to the index.php with a message to login before viewing Lendr.

    The other instance where well look at the usage of a parameter value is in the following view layout.

    joomla_root/components/com_lendr/views/book/tmpl/_entry.php

    1. // Line 43 - 48 2. 3.

  • 67

    20. return false; 21. } 22. }

    The deleting of a book is one example where we are soft deleting instead of permanently removing an object. The code is quite simple as shown above. We will locate the id of the book we wish to delete, we will then get an instance of the Book table and load the appropriate row. Once we have the row loaded we can easily set the published status to 0 and then store the result. If the row is stored successfully we will return a true value to the javascript, or if the store fails we will return a false.

    The second place we will look at for deleting an item is located in the waitlist model.

    joomla_root/components/com_lendr/models/waitlist.php

    1. /** 2. * Delete a book from a waitlist 3. * @param int ID of the book to delete 4. * @return boolean True if successfully deleted 5. */ 6. public function delete($id = null) 7. { 8. $app = JFactory::getApplication(); 9. $id = $id ? $id : $app->input->get('waitlist_id'); 10. 11. if (!$id) 12. { 13. if ($book_id = $app->input->get('book_id')) 14. { 15. $db = JFactory::getDbo(); 16. $user = JFactory::getUser(); 17. $query = $db->getQuery(true); 18. $query->delete() 19. ->from('#__lendr_waitlists') 20. ->where('user_id = ' . $user->id) 21. ->where('book_id = ' . $book_id); 22. $db->setQuery($query); 23. if($db->query()) { 24. return true; 25. } 26. } 27. 28. } else { 29. $waitlist = JTable::getInstance('Waitlist','Table'); 30. $waitlist->load($id); 31. 32. if ($waitlist->delete()) 33. { 34. return true; 35. } 36. } 37. 38. return false; 39. }

    68

    In this example we are actually hard deleting the row from the database table. The reason we do so in this case is because there does not exist a published column on this data and thus the option to delete is considered appropriate.

    As with the book deletion example earlier it is good to see that if we have a specific waitlist ID we can load that particular object and delete it directly. If however we do not have the specific waitlist ID we can look up the necessary row using the book ID and the user ID of the person and then deleting the associated row.

    In Lendr we handle deleting books through AJAX calls and as a result we want to automatically remove the associated row from the page we are viewing when the delete button is clicked. Here is the javascript used to handle the AJAX call and subsequent removal of the row.

    joomla_root/components/com_lendr/assets/js/lendr.js

    1. function deleteBook(book_id,type) 2. { 3. jQuery.ajax({ 4.

    url:'index.php?option=com_lendr&controller=delete&format=raw&tmpl=component',

    5. type:'POST', 6. data: 'book_id='+book_id+'&type='+type, 7. dataType: 'JSON', 8. success:function(data) 9. { 10. alert(data.msg); 11. if(data.success) 12. { 13. jQuery("tr#bookRow"+book_id).hide(); 14. } 15. } 16. }); 17. }

    Here we pass the book_id as well as the type - the type is important for use in the delete controller as we saw previously (remember: this is how we routed the task to the appropriate model). We then will display the resulting alert message generated by the delete controller and if the deletion is successful we will remove the associated row from the list view. We remove the row by merely hiding it via jQuery. The ID of the table row has been defined by bookRow and the ID of that particular book (which is a unique identifier).

    Book List View

    The list view for all books is the other item we need to clean up. This is pretty straightforward and not much code required to do so. First we need to modify the html.php view class for the books. This can be done by updating as follows.

    joomla_root/components/com_lendr/views/book/html.php

  • 69

    1. // Lines 8 - 19 2. 3. $layout = $this->getLayout(); 4. 5. $this->params = JComponentHelper::getParams('com_lendr'); 6. 7. //retrieve task list from model 8. $model = new LendrModelsBook(); 9. 10. if($layout == 'list') 11. { 12. $this->books = $model->listItems(); 13. $this->_bookListView =

    LendrHelpersView::load('Book','_entry','phtml'); 14. } else { 15. 16.

    Here we have added a call to get the layout variable and then we check to see which view we are loading. If we are in the list view then we want to display a list of all the available items otherwise well load the view the same way as before.

    Next well add a new list layout to display the books.

    joomla_root/components/com_lendr/views/book/tmpl/list.php

    1.

    2. 3. 4. 5. 6. 7. 8. 9. 10. 15. 16. 17.

    You should notice the similarity between this view and the library views we have written previously. The only difference is we are now loading all books in the system instead of those books associated with a particular library.

    70

    Step 3: Menus and File Cleanup There are two parts to this step we are going to review. The first part involves creating and defining possible menu links entry points to be used when creating menu links in the administrator panel. The second part will consist of some minor removal of unnecessary files and/or functions.

    Create Menu Links

    Its often necessary to create a menu link which can be added to a menu link to be displayed on the front side. Menu links are added through the administrator menu manager. When adding a new menu item you select the type of menu link you wish to add. We need to define those views we want to display in the menu type modal selection. There are two layouts we wish to add to the menu type options. First, we want to allow users to be able to link to a list of all profiles and secondly we want to be able to link to a list of all books.

    Menu links are based on associated metadata.xml files located within the various view folders within the component. Below is the example for the profile layout.

    joomla_root/components/com_lendr/views/profile/tmpl/list.xml

    1. 2. 3. 4. 5. 6. 7.

    Note: The name of this file should coordinate with the name of the layout file in the same directory.

    Notice that because we are linking to a layout we define a object if we were to link to a view instead then we would create a object. The language strings are stored in the admin system language file.

    The system language file for Lendr is below.

    joomla_root/administrator/languages/en-GB/en-GB.com_lendr.sys.ini

    1. COM_LENDR = Lendr 2. COM_LENDR_SETTINGS = Lendr Settings 3. COM_LENDR_PROFILE_LIST = Profile List 4. COM_LENDR_PROFILE_LIST_DESC = Display list of all profiles 5. COM_LENDR_BOOK_LIST = Book List 6. COM_LENDR_BOOK_LIST_DESC = Display list of all books

  • 71

    These strings are used for those areas that might refer to Lendr from outside of the actual Lendr component. This means these strings are always loaded throughout Joomla and not only when inside index.php?option=com_lendr. The menu type modal is one example when these strings are used. The administrator component menu is a second example.

    By adding this metadata.xml file to the appropriate folder we can now view this layout in the menu section list. The metadata file can also contain advanced options for adding additional parameters. (e.g. Adding the ability to select a particular book or profile for the menu link to be associated with).

    Remove unnecessary files and functions

    Weve done a fairly good job throughout this tutorial not adding unnecessary functions or files so there are relatively few things to remove. There are several controllers on the front side to remove that were never implemented in the scope of this tutorial and there were a couple of views that we also cleaned up from a layout perspective. For the most part this step is listed here mainly to serve as a reminder for future development to always be sure to release clean code.

    It is important for security, package distribution size, and general clean coding standards to be sure there are no extra files, folders, or functions existing that might pose a problem in the future. Remember its always a good idea to code for someone else. This means documenting your code correctly and removing anything thats not necessary and might be confusing in the future.

    Step 4: Additional Suggestions The following are a few additional suggestions which could be explored in future articles as add-ons to this series should there be interest in any or all of them. Some of these ideas are brand new cutting edge opportunities to provide new features to a Joomla 3.x component. If you are interested in seeing an article on one or more of these ideas, leave a message in the comments.

    Tags

    Tags is a new feature from Joomla 3.1. With tags there is the opportunity to assign tags to books and then be able to search and group books by those tags. Tagging will also allow for books to be assigned to multiple tags for each filtering and sorting.

    Categories

    Categories will provide the opportunity to add books to specific categories. This allows for large scale groupings and a demonstration of using the Joomla category structure and demonstrate the proper method for using Joomla categories.

    Web Services / JSON

    72

    Using a basic web services model we can demonstrate methods for retrieving data directly from the Lendr component without utilizing the standard component views and layouts. Retrieve the data in a JSON feed for use in other systems.

    Download

    Download the component as it exists to this point from the Github repository.

    Download