22分钟阅读时间 (4312字)

系列:开发Joomla! 3.0扩展 - 第5集:配置管理界面和代码清理

Série : développer une extension Joomla! 3.0 - Episode 5 : la configuration de l'administration et le nettoyage du code

大家好,欢迎来到我们系列编码课程的最后一部分。如果您跟随着前面的教程,您已经完成了创建Joomla 3.x原生扩展的所有必要步骤。这是一个漫长的过程,但我希望它是有益的和富有教育意义的。我很高兴有机会在先前的文章中与您分享关于Joomla扩展开发的技巧和窍门。在本教程的最后,我们将探讨一些最后的理念,进行一些清理,并讨论我们可以添加到未来的一些附加功能。那么,准备好深入到最后一篇关于Joomla! 3.x组件开发的文章吧...

第0步:准备你的咖啡

是的,就像往常一样,就像前面的每一篇文章一样,我们将首先准备一杯好咖啡。通过这个例行程序,我们为编写代码做好准备,并专注于要完成的任务。幸运的是,这篇文章不需要像以前的一些文章那样详细,我确信它不需要额外的咖啡。更好的是,也许,在你喝完这杯咖啡之前,你甚至可能已经看完了这篇教程的大部分内容。

第1步:编写管理面板

Joomla!管理面板提供了各种功能,以最大限度地提高其使用效率。管理面板允许定义所有组件的使用参数。
我们设计 Lendr 为一个 前端 应用程序,其中大部分功能都直接由访客定义。正是出于这个原因,我们仅将管理面板用于添加补充功能和一些基本选项设置。通过这种方式,我们避免了在每个组件的模型、视图和控制器的“管理”部分重复整个“站点”代码。
遵循这种方法,我希望您能够理解何时以及如何以最高效的方式使用管理面板。

因此,我们将创建用于管理部分的代码文件(注意:源文件夹为 administrator):一个帮助文件(helper)、一个控制器(controller)、一个模型(model)、一个视图(view)、一个访问文件、一个配置文件和我们的语言文件。

我们将逐一处理这些文件,首先从入口点开始:lendr.php

joomla_root/administrator/components/com_lendr/lendr.php

<?php // No direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
//load classes
JLoader::registerPrefix('Lendr', JPATH_COMPONENT_ADMINISTRATOR);
//Load plugins
JPluginHelper::importPlugin('lendr');
 
//application
$app = JFactory::getApplication();
 
// Require specific controller if requested
$controller = $app->input->get('controller','display');
// Create the controller
$classname  = 'LendrControllers'.ucwords($controller);
$controller = new $classname();
 
// Perform the Request task
$controller->execute();
              
此代码与前端代码相对类似,主要用于将流量正确地导向相应的控制器。

joomla_root/administrator/components/com_lendr/controllers/displays.php

<?php defined( '_JEXEC' ) or die( 'Restricted access' ); 
 
class LendrControllersDisplay extends JControllerBase
{
  public function execute()
  {
    // Get the application
    $app = $this->getApplication();
 
    // Get the document object.
    $document     = JFactory::getDocument();
 
    $viewName     = $app->input->getWord('view', 'statistics');
    $viewFormat   = $document->getType();
    $layoutName   = $app->input->getWord('layout', 'default');
    $app->input->set('view', $viewName);
 
    // Register the layout paths for the view
    $paths = new SplPriorityQueue;
    $paths->insert(JPATH_COMPONENT . '/views/' . $viewName . '/tmpl', 'normal');
 
    $viewClass  = 'LendrViews' . ucfirst($viewName) . ucfirst($viewFormat);
    $modelClass = 'LendrModels' . ucfirst($viewName);
    $view = new $viewClass(new $modelClass, $paths);
    $view->setLayout($layoutName);
    // Render our view.
    echo $view->render();
 
    return true;
  }
}

您第一眼就能看到此控制器与前端默认控制器的相似之处。我们用两个都执行相似的任务。
在这种情况下,我们以不同的方式设置默认视图,与前端不同。

接下来,我们将查看位于默认视图文件夹中的 html.php 文件(如前所述,默认视图名为 'statistics')。

joomla_root/administrator/components/com_lendr/views/statistics/html.php

<?php defined( '_JEXEC' ) or die( 'Restricted access' ); 
 
class LendrViewsStatisticsHtml extends JViewHtml
{
  function render()
  {
    $app = JFactory::getApplication();
   
    //retrieve task list from model
    $model = new LendrModelsStatistics();
    $this->stats = $model->getStats();
    $this->addToolbar();
    //display
    return parent::render();
  } 
    /**
     * Add the page title and toolbar.
     *
     * @since   1.6
     */
    protected function addToolbar()
    {
        $canDo  = LendrHelpersLendr::getActions();
        // Get the toolbar object instance
        $bar = JToolBar::getInstance('toolbar');
        JToolbarHelper::title(JText::_('COM_LENDR_STATISTICS'));
               
        if ($canDo->get('core.admin'))
        {
            JToolbarHelper::preferences('com_lendr');
        }
    }
}
              

此文件包含一些我们将详细研究的新元素。
首先,您会注意到我们继承了 JViewHtml 类。这使我们能够利用一些基本功能,您可以通过直接检查位于 Joomla! Libraries 文件夹中的 JViewHtml 类来找到这些功能。
然后,我们找到对模型的常规调用,用于加载视图所需的具体数据。

接下来,我们找到了一个新行。在此文件中调用了 addToolbar 函数,通常用于在网站的“管理”部分组件的工具栏中添加元素。由于我们的管理面板将非常基础且功能有限,我们的工具栏将仅提供一个元素。

最后,我们显示视图,就像之前为前端所做的那样。

addToolbar 命令,如之前所见,向我们的组件工具栏的子导航中添加按钮。由于我们不需要在我们的管理面板示例中包含一组完整的视图和函数,我们将创建一个唯一的按钮。
首先,我们将创建一个 Joomla! 标准工具栏类的实例,然后我们将把我们的标题和按钮分配给此实例。

您会注意到我们的语言文件用于所有字符串。如果您希望在组件标题旁边显示一个图像,您只需在定义标题行时添加第二个引用即可。

注意:请记住,在前面的文章中,在查看管理界面时出现了一个错误。这是因为我们没有为页面指定标题,而 Isis 模板要求必须指定。

在这个命令中,我们还调用了我们的helper类。这是回顾这个类的作用和如何使用它的好时机。这个helper类包含了一些对我们组件管理的有用函数。

注意:我们永远不会直接包含helper。这是Joomla!的auto-loader(如主文件lendr.php中定义)通过我们的命名约定检测和自动加载文件。

joomla_root/administrator/components/com_lendr/helpers/lendr.php

<?php
/**
 * @package     Joomla.Administrator
 * @subpackage  com_lendr
 *
 * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
 * @license     GNU General Public License version 2 or later; see LICENSE.txt
 */
defined('_JEXEC') or die;
/**
 * Lendr component helper.
 *
 * @package     Joomla.Administrator
 * @subpackage  com_lendr
 * @since       1.6
 */
class LendrHelpersLendr
{
  public static $extension = 'com_lendr';
  /**
   * @return  JObject
   */
  public static function getActions()
  {
    $user = JFactory::getUser();
    $result = new JObject;
    $assetName = 'com_lendr';
    $level = 'component';
    $actions = JAccess::getActions('com_lendr', $level);
    foreach ($actions as $action)
    {
      $result->set($action->name, $user->authorise($action->name, $assetName));
    }
    return $result;
  }
}

在这个helper中,我们目前有一个函数。函数getActions将使用位于组件根目录'administrator'中的access.xml文件。这是一个很棒的小功能,允许加载一个包含XML文件中现有值的对象。

花点时间看看这个access.xml文件,看看它是如何与组件中使用的功能相关联的。

joomla_root/administrator/components/com_lendr/access.xml

<?xml version="1.0" encoding="utf-8"?>
<access component="com_lendr">
  <section name="component">
    <action name="core.admin" title="JACTION_ADMIN" description="JACTION_ADMIN_COMPONENT_DESC" />
  </section>
</access>

考虑到本教程的需求,我们将有一个最小的access文件。基本上,我们只是想知道是否允许访问管理界面。我们将使用管理访问级别来确定用户是否有权查看组件管理子菜单的选项(我们在之前的教程中已经看到过这个元素)。
这里可以添加许多其他部分和动作,以及自定义动作。这个文件与Joomla!2.5的文件类似,如果您感兴趣,我建议您通过以下教程回顾其特性。

注意:您可以在以下位置查看有关Joomla! 2.5中access文件的信息:http://docs.joomla.org tutorial

这直接引出了我们步骤的第二部分:组件选项。

组件选项

我们组件的选项可以通过位于组件Lendr工具栏中的选项按钮访问。这是我们之前在关于html.php文件的章节中研究的按钮。访问检查canDo行允许添加一个"参数"("选项")按钮。这些参数还可以访问组件的全局选项配置。正如您可能在使用其他组件时发现的,所有的"参数"按钮都将用户重定向到组件的com_config和相应的视图。

用于此视图的数据(当您查看组件Lendrcom_config页面时)来自一个特定的文件。文件config.xml也位于组件Lendr根目录下的administrator部分。
让我们看看这个文件。

joomla_root/administrator/components/com_lendr/config.xml

<?xml version="1.0" encoding="utf-8"?>
<config>
  <fieldset name="component"
    label="COM_LENDR_OPTIONS"
    description="COM_LENDR_OPTIONS_DESC"
  >
    <field name="required_account" type="radio"
      default="0"
      class="btn-group"
      label="COM_LENDR_REQUIRED_ACCOUNT"
      description="COM_LENDR_REQUIRED_ACCOUNT_DESC">
      
      <option value="0">JNO</option>
      <option value="1">JYES</option>
    </field>
    <field name="new_reviews" type="radio"
      default="1"
      class="btn-group"
      label="COM_LENDR_ALLOW_NEW_REVIEWS"
      description="COM_LENDR_ALLOW_NEW_REVIEWS_DESC">
      
      <option value="0">JNO</option>
      <option value="1">JYES</option>
    </field>
    <field name="new_wishlists" type="radio"
      default="1"
      class="btn-group"
      label="COM_LENDR_ALLOW_NEW_WISHLISTS"
      description="COM_LENDR_ALLOW_NEW_WISHLISTS_DESC">
      
      <option value="0">JNO</option>
      <option value="1">JYES</option>
    </field>
    <field name="new_waitlists" type="radio"
      default="1"
      class="btn-group"
      label="COM_LENDR_ALLOW_NEW_WAITLISTS"
      description="COM_LENDR_ALLOW_NEW_WAITLISTS_DESC">
      
      <option value="0">JNO</option>
      <option value="1">JYES</option>
    </field>
  </fieldset>
  <fieldset name="permissions"
    description="JCONFIG_PERMISSIONS_DESC"
    label="JCONFIG_PERMISSIONS_LABEL"
  >
    <field name="rules" type="rules"
      component="com_lendr"
      filter="rules"
      validate="rules"
      label="JCONFIG_PERMISSIONS_LABEL"
      section="component" />
  </fieldset>
</config>

在这个文件中,您会注意到我们定义了两组字段(fieldsets)。这些组对应于在admin部分显示选项时出现的选项卡。第一个组显示我们希望管理员可以访问的特定参数,第二个组涉及参数按钮的可访问性。

注意:您可以为您的组件定义尽可能多的"fieldsets"选项卡。

在创建此文件时,需要记住一些重要事项。
首先,您必须使用并行语言文件来定义所有适当的字符字符串。
您还必须定义字段的类,以便它们使用适当的样式。
最后,您可以定义不同类型的字段,您可以在Joomla!的其它部分使用这些字段。在这个例子中,我们主要使用单选按钮来在“是”和“否”之间切换。

现在我们来探索添加到前端部分的代码,并使用这些新参数。

我们将特别关注两个实例。
第一个实例涉及一个必选账户选项:required_account。此选项允许我们定义用户在使用Lendr之前是否需要登录。
我们在下面的文件中实现此选项。

joomla_root/components/com_lendr/controllers/default.php

// Line 11 - 19
 $params = JComponentHelper::getParams('com_lendr');
    if ($params->get('required_account') == 1) 
    {
        $user = JFactory::getUser();
        if ($user->get('guest'))
        {
            $app->redirect('index.php',JText::_('COM_LENDR_ACCOUNT_REQUIRED_MSG'));
        }
    }

首先,我们使用组件的helper获取对象参数。一旦我们有了这些参数,我们就可以检查是否要求用户拥有账户。如果是这样,我们检查用户是否已登录,如果没有登录,我们将其重定向到index.php,并显示一条消息,要求用户登录才能访问Lendr。

另一个实例,我们将看到参数值的使用,位于以下显示视图。

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

Code

对于此检查,我们遵循与控制器相同的基原则。需要注意的是,我们在html.php渲染中调用组件helper以获取对象参数(params),而不是在这里集成它们。我们可以通过在视图中调用$this->params来证明这一点。

步骤2:代码清理

在这个步骤中,我们将简要关注代码清理的两个方面。
一方面,我们必须添加删除对象的功能,另一方面,我们必须提供一个列表视图来显示系统中所有的书籍。

数据删除

对象的删除可以通过不同的方式完成。在第一种情况下,我们不会真正删除数据库中的数据(尽管这可以相当容易地完成),然后在第二种情况下,我们将实际上完全删除数据。

实际上,通常隐藏信息而不实际删除网站上的数据是非常有用的。这允许我们恢复一个意外删除的元素。在Lendr中,最快速、最有效的方法来“删除”一个元素是简单地定义变量'publier'为0(零)。对于某些其他组件,将'publier'设置为0不一定意味着“可撤销”的删除,这就是为什么通常看到发布参数为-1。在我们的特定用例中,我们不使用publier = 0,因此通过将变量指定为0,我们将真正实现元素显示的可撤销删除。

joomla_root/components/com_lendr/controllers/delete.php

<?php defined( '_JEXEC' ) or die( 'Restricted access' ); 
 
class LendrControllersDelete extends JControllerBase
{
  public function execute()
  {
    $app = JFactory::getApplication();
    $return = array("success"=>false);
    
    $type = $app->input->get('type','waitlist');
   
    $modelName = 'LendrModels'.ucfirst($type);    
    $model = new $modelName();
    if ( $row = $model->delete() )
    {
      $return['success'] = true;
      $return['msg'] = JText::_('COM_LENDR_BOOK_DELETE_SUCCESS');
    }else{
      $return['msg'] = JText::_('COM_LENDR_BOOK_DELETE_FAILURE');
    }
    echo json_encode($return);
  }
}

在我们的删除控制器中(因为每个控制器都必须执行一个唯一任务),我们有一个将数据传递给适当模型以处理命令。在这里,我们根据变量JInput中的值配置模型名称。模型是我们实际删除元素的地方。

joomla_root/components/com_lendr/models/book.php

 /**
  * Delete a book
  * @param int      ID of the book to delete
  * @return boolean True if successfully deleted
  */
  public function delete($id = null)
  {
    $app  = JFactory::getApplication();
    $id   = $id ? $id : $app->input->get('book_id');
    $book = JTable::getInstance('Book','Table');
    $book->load($id);
    $book->published = 0;
    if($book->store()) 
    {
      return true;
    } else {
      return false;
    }
  }

删除一本书是使用“可逆删除”而不是对象永久删除的例子之一。正如您在上文所见,代码相当简单。我们将定位要删除的书的ID,然后获取Book表的实例并加载相应的行。一旦加载了行,我们可以轻松地将它的发布状态设置为0然后存储结果。如果行成功存储,我们将向JavaScript返回一个'true'值;如果在存储失败的情况下,我们将返回一个'false'值。

我们将处理的第二个删除元素的例子是在等待列表(waitlist)模型中。

joomla_root/components/com_lendr/models/waitlist.php

/**
  * Delete a book from a waitlist
  * @param int      ID of the book to delete
  * @return boolean True if successfully deleted
  */
  public function delete($id = null)
  {
    $app  = JFactory::getApplication();
    $id   = $id ? $id : $app->input->get('waitlist_id');
    if (!$id)
    {
      if ($book_id = $app->input->get('book_id')) 
      {
        $db = JFactory::getDbo();
        $user = JFactory::getUser();
        $query = $db->getQuery(true);
        $query->delete()
            ->from('#__lendr_waitlists')
            ->where('user_id = ' . $user->id)
            ->where('book_id = ' . $book_id);
        $db->setQuery($query);
        if($db->query()) {
          return true;
        }
      } 
    } else {
      $waitlist = JTable::getInstance('Waitlist','Table');
      $waitlist->load($id);
      if ($waitlist->delete()) 
      {
        return true;
      }      
    }
    return false;
  }

在这个例子中,我们将永久删除数据库表中的行。
我们这样做的原因很简单:数据库中没有用于发布的列。因此,永久删除选项是最合适的。

与前面的删除书籍例子一样,我们查看等待列表中是否有特定的ID。然后我们可以加载特定的对象并直接删除它。如果没有在等待列表中找到特定的ID,我们可以使用书的ID和用户的ID来搜索所需的行,然后删除相关的行。

Lendr中,我们通过AJAX调用处理书籍的删除,因此当删除按钮被触发时,我们想要自动立即删除我们正在查看的页面上的相关行。
以下是处理AJAX调用和删除行的javascript代码。

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

function deleteBook(book_id,type) 
{
  jQuery.ajax({
    url:'index.php?option=com_lendr&controller=delete&format=raw&tmpl=component',
    type:'POST',
    data: 'book_id='+book_id+'&type='+type,
    dataType: 'JSON',
    success:function(data)
    {
      alert(data.msg);
      if(data.success)
      {
        jQuery("tr#bookRow"+book_id).hide();
      }
    }
  });
}

在这里,我们传递了book_id以及type。正如我们之前看到的,类型对于控制器删除的使用很重要(记住:我们就是这样将任务导向适当的模型)。然后,我们将显示由控制器删除生成的结果消息并显示警报。如果删除成功,我们将从列表视图中删除相应的行。我们通过jQuery简单地隐藏行来删除它。行在表中的IDbookRow以及这本书的ID(这是一个唯一的标识符)定义。

书籍列表视图

我们需要重新引入的第二个元素是所有书籍的列表视图。这个步骤相当简单,只需要很少的代码。首先,我们需要修改书籍的视图html.php的类。这可以通过以下更新完成:

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

// Lines 8 - 19
    $layout = $this->getLayout();
    $this->params = JComponentHelper::getParams('com_lendr');
    //retrieve task list from model
    $model = new LendrModelsBook();
    if($layout == 'list')
    {
        $this->books = $model->listItems();
        $this->_bookListView = LendrHelpersView::load('Book','_entry','phtml');
    } else {
  …

在这里我们添加了一个调用以获取布局变量,然后我们检查以确定我们将加载哪个视图。如果我们在列表视图中,那么我们希望显示所有可用元素的列表。否则,我们将以先前相同的方式加载视图。

接下来,我们将添加一个新的列表布局以显示所有书籍。

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

<table cellpadding="0" cellspacing="0" width="100%" class="table table-striped">
  <thead>
    <tr>
      <th><?php echo JText::_('COM_LENDR_DETAILS'); ?></th>
      <th><?php echo JText::_('COM_LENDR_STATUS'); ?></th>
      <th><?php echo JText::_('COM_LENDR_ACTIONS'); ?></th>
    </tr>
  </thead>
  <tbody id="book-list">
    <?php for($i=0, $n = count($this->books);$i<$n;$i++) { 
            $this->_bookListView->book = $this->books[$i];
            $this->_bookListView->type = 'book';
            echo $this->_bookListView->render();
    } ?>
  </tbody>
</table>

您会注意到这个视图与我们之前制作的图书馆视图相似。唯一的区别是,这里我们将加载系统中的所有书籍,而不是特定图书馆的书籍。

第3步:菜单和文件清理

在这个步骤中,我们将回顾两个部分。
第一步是创建和定义可能的使用点,这些点将用于在管理面板中创建菜单链接。
第二步将包括删除一些无用文件和/或功能。

创建菜单链接

通常,创建一个以菜单链接形式存在的入口点,以便在前端显示是必不可少的。菜单链接通过菜单管理器添加到管理中。在添加新的菜单项时,您选择要添加的菜单链接类型。因此,我们需要定义我们希望在菜单链接选择窗口中显示的视图。我们希望向菜单类型选项中添加两种不同的显示类型。首先,我们希望用户能够创建一个指向所有配置文件的链接,其次,我们希望能够创建一个指向所有书籍的链接。

菜单链接基于放置在组件不同视图目录中的关联 metadata.xml 文件。以下是一个显示配置文件的示例

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

<?xml version="1.0" encoding="utf-8"?>
<metadata>
  <layout title="COM_LENDR_PROFILE_LIST">
    <message><![CDATA[COM_LENDR_PROFILE_LIST_DESC]]></message>
  </layout>
</metadata>
注意:此文件名必须与位于同一目录中的显示渲染文件名相匹配。

您会注意到,因为我们希望创建一个指向显示(布局)的链接,所以我们定义了一个 <layout> 对象。如果我们想创建一个指向视图的链接,我们会定义一个 <view> 对象。语言字符串存储在系统管理员的语言文件中。

以下是 Lendr 的系统语言文件。

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

COM_LENDR = Lendr
COM_LENDR_SETTINGS = Lendr Settings
COM_LENDR_PROFILE_LIST = Profile List
COM_LENDR_PROFILE_LIST_DESC = Display list of all profiles
COM_LENDR_BOOK_LIST = Book List
COM_LENDR_BOOK_LIST_DESC = Display list of all books

这些字符串将被用于组件以外的 Lendr 引用元素。这意味着这些字符串将始终由您的 Joomla! 网站加载,而不仅仅是 index.php?option=com_lendr 内部。例如,选择菜单类型窗口是一个可以使用的这些字符串的例子。组件的管理菜单是另一个例子。

通过在适当的目录中添加此 metadata.xml 文件,我们现在可以在菜单列表中看到此显示。元数据文件还可以包含用于添加额外设置的先进选项。例如,通过添加选择特定书籍或配置文件以关联菜单链接的可能性。

删除无用文件和功能

在整个教程中,我们做得很好,避免了添加无用功能和文件。因此,要删除的元素很少。有一些前端控制器,因为我们没有在本教程中实施它们。还有一些视图我们需要清理。
实际上,这一步主要是为了提醒您未来的开发,以便始终记住要清理您的代码。

出于安全、重量和更普遍地遵守编码标准的原因,最好确保没有无用的文件、目录或功能可能会在未来引起问题。
此外,始终假设您为第三方编写代码是一个好主意。这将迫使您充分和正确地注释您的代码,并删除所有可能在未来引起混淆的不必要内容。

第4步:附加建议

以下是一些额外的建议,可以在未来文章中进一步探索,作为本系列的补充。其中一些想法可以为Joomla!3.x的任何组件提供新的功能。如果您对其中任何一个想法感兴趣,请随时在评论中发给我消息。

标签

标签是Joomla! 3.1版本中提供的一项全新原生功能。通过使用标签(NDT:有时称为标签或关键词),我们现在可以为书籍分配关键词,并能够根据这些关键词进行搜索和分组。标签还可以将书籍与多个关键词相关联,每个关键词都可以进行筛选和排序。

类别

类别允许将书籍添加到特定的类别中。这可以实现更深入的专题分类,并使我们关注Joomla!中类别结构的用法以及适当使用这些类别的技术。

Web服务/JSON

使用基本的Web服务模型,我们可以描述从Lendr组件直接获取数据的方法,而无需使用组件的标准视图和布局。在JSON流中检索数据允许在其他系统中使用这些数据。

下载

从GitHub存储库下载组件(如当前阶段所示)

下载

下一篇文章:版本跟踪

正如我之前提到的,这篇文章是本系列关于编码的最后一篇。然而,在下一篇文章中,我们将讨论一些关于版本跟踪和组件支持的想法。我们将了解GitHub和分发方法,以及版本编号约定、更新计划等等。

访问完整的教程网站:http://lendr.sparkbuilt.com/

资源

lendr.sparkbuilt.com

本系列

 

一些发表在Joomla社区杂志上的文章代表了作者对特定主题的个人观点或经验,可能并不与Joomla项目官方立场一致

0
7月发布你的俳句
模块现代化
 

评论

已经注册? 在此登录
尚未发表评论。成为第一个发表评论的人

通过接受,您将访问https://magazine.joomla.net.cn/之外的第三方外部服务