Joomla 2.5创建组件并保存数据

时间:2013-04-19 16:51:32

标签: joomla joomla2.5 admin

我一直在使用这个文档(我在网上找到的唯一一个)来构建一个组件: http://docs.joomla.org/Developing_a_Model-View-Controller_Component/2.5/Introduction

我可以在一定程度上理解它,但它确实缺乏任何定义。我创建的组件在一定程度上起作用,尽管我遇到了一些更棘手的问题。

基本上我需要组件只需加载一个设置区域来设置一些值,并通过它来改变这些值。以下是我所拥有的细节:

表单视图,从数据库加载表单数据。 工具栏设置用于保存/应用和取消。

这加载没有错误,并且根据我发现的joomla上的所有文档,通过在模型中连接JTable初始化JControllerForm实例,简单保存表单应该自动工作。然而,即使代码中的任何地方都没有引用到最后带有s的视图(主视图是tireapi,表单总是重定向到tireapis)。

这会导致500错误,因为没有设置该视图的地方。文档确实包含视图列表,但是我只需要编辑一行,因此列表毫无意义。我知道参数可以设置为组件而不是创建数据库字段,但我无法找到任何与之相关的文档。

我正在寻找的方法是如何阻止组件重定向到一个不存在的视图,并正确保存数据。链接到文档,不仅显示示例代码,而且描述函数及其工作方式将是有益的。

以下是一些代码,请随时指出我可能完全忽略的任何内容(我更新创建组件):

tireapi.php:

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');

// import joomla controller library
jimport('joomla.application.component.controller');

// Get an instance of the controller prefixed by TireAPI
$controller = JController::getInstance('TireAPI');

// Get the task
$jinput = JFactory::getApplication()->input;
$task = $jinput->get('task', "", 'STR' );

// Perform the Request task
$controller->execute($task);

// Redirect if set by the controller
$controller->redirect();
?>

Controller.php这样:

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');

// import Joomla controller library
jimport('joomla.application.component.controller');

class TireAPIController extends JController{
    function display($cachable = false){
        // set default view if not set
        $input = JFactory::getApplication()->input;
        $input->set('view', $input->getCmd('view', 'TireAPI'));

        // call parent behavior
        parent::display($cachable);
    }
}
?>

控制器/ tireapi.php:

<?php
// No direct access to this file
 defined('_JEXEC') or die('Restricted access');
// import Joomla controllerform library
jimport('joomla.application.component.controllerform');
class TireAPIControllerTireAPI extends JControllerForm{}
?>

模型/ tireapi.php:

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// import the Joomla modellist library
jimport('joomla.application.component.modeladmin');
class TireAPIModelTireAPI extends JModelAdmin{
    protected $settings; //define settings

    public function getTable($type = 'TireAPI', $prefix = 'TireAPITable', $config = array()){
        return JTable::getInstance($type, $prefix, $config);
    }

    public function getSettings(){ //grab settings from database
        if(!isset($this->settings)){
            $table = $this->getTable();
            $table->load(1);
            $this->settings = $table;
        }
        return $this->settings;
    }
    public function getForm($data = array(), $loadData = true){
    // Get the form.
        $form = $this->loadForm('com_tireapi.tireapi', 'tireapi',
            array('control' => 'jform', 'load_data' => $loadData));
        if (empty($form)){
            return false;
        }
        return $form;
    }
    protected function loadFormData(){
        // Check the session for previously entered form data.
        $data = JFactory::getApplication()->getUserState('com_tireapi.edit.tireapi.data', array());
        if (empty($data)){
            $data = $this->getSettings();
        }
        return $data;
    }
}
?>

表/ tireapi.php:

<?php
// No direct access
defined('_JEXEC') or die('Restricted access');

// import Joomla table library
jimport('joomla.database.table');
class TireAPITableTireAPI extends JTable
{
    function __construct( &$db ) {
        parent::__construct('#__tireapi', 'id', $db);
    }
}
?>

视图/ tireapi / view.html.php:

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');

// import Joomla view library
jimport('joomla.application.component.view');

class TireAPIViewTireAPI extends JView{
        function display($tpl = null){

            $form = $this->get('Form');
            $item = $this->get('Settings');

            // Check for errors.
            if(count($errors = $this->get('Errors'))){
                JError::raiseError(500, implode('<br />', $errors));
                return false;
            }
            // Assign data to the view
            $this->item = $item;
            $this->form = $form;

            $this->addToolBar();

            // Display the template
            parent::display($tpl);
        }
        protected function addToolBar() {
            $input = JFactory::getApplication()->input;
            JToolBarHelper::title(JText::_('COM_TIREAPI_MANAGER_TIREAPIS'));
            JToolBarHelper::apply('tireapi.apply');
            JToolBarHelper::save('tireapi.save');
            JToolBarHelper::cancel('tireapi.cancel');
        }
}
?>

视图/ tireapi / TMPL /如default.php:

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted Access');

// load tooltip behavior
JHtml::_('behavior.tooltip');
?>
<form action="<?php echo JRoute::_('index.php?option=com_tireapi&layout=edit&id='.(int) $this->item->id); ?>"
      method="post" name="adminForm" id="tireapi-form">
    <fieldset class="adminform">
            <legend><?php echo JText::_( 'COM_TIREAPI_DETAILS' ); ?></legend>
            <ul class="adminformlist">
    <?php foreach($this->form->getFieldset() as $field): ?>
                    <li><?php echo $field->label;echo $field->input;?></li>
    <?php endforeach; ?>
            </ul>
    </fieldset>
    <div>
        <input type="hidden" name="task" value="tireapi.edit" />
        <?php echo JHtml::_('form.token'); ?>
    </div>
</form>

这些都是我能想到的可能很重要的文件,请告诉我是否应该再包含这些文件。

更新: 现在我可以停止重定向问题,但不会保存数据。 我收到此错误: 您不得使用该链接直接访问该页面(#1)。

这是让这个极其基本的管理功能发挥作用的最后一道障碍。有任何想法吗? 为了澄清,我通过xml文件设置表单并正确加载,甚至用数据库中的适当数据填充它们。但是,当我点击“应用”时,它只是将我引导回上面列出错误的表单,而不保存。

2 个答案:

答案 0 :(得分:4)

您打开的主要问题是您希望它重定向到哪里? Joomla默认重定向到列表视图(通过向视图名称添加's',除非您直接指定列表视图)。

您可以通过以下几种方式覆盖此内容:

在您的控制器(controllers / tireapi.php)中,设置您自己的列表视图。我想你甚至可以做出同样的看法:

function __construct() {
    $this->view_list = 'tireapi';
    parent::__construct();
}

覆盖保存功能以更改保存后发生的重定向(再次在控制器中)。这可以通过将自然发生的重定向更改为其他内容来实现:

public function save($key = null, $urlVar = null) {
    $return = parent::save($key, $urlVar);
    $this->setRedirect(JRoute::_('index.php?option=com_tireapi&view=tireapi'));
    return $return;
}

其中一个应该为你做的伎俩。

**更新

要最初检查项目,您需要更改组件处理没有设置视图的方式。现在你只需设置视图,让我们重定向!更新后的controller.php如下。

<?php
// No direct access to this file
defined('_JEXEC') or die('Restricted access');

// import Joomla controller library
jimport('joomla.application.component.controller');

class TireAPIController extends JController{
    function display($cachable = false){
        // set default view if not set
        $input = JFactory::getApplication()->input;
        $view = $input->get('view');
        if (!$view) {
            JFactory::getApplication()->redirect('index.php?option=com_tireapi&task=tireapi.edit&id=1');
            exit();
        }

        // call parent behavior
        parent::display($cachable);
    }
}
?>

注意:如果不止一个人需要编辑它,这将非常有效,因为系统会在您打开组件时将其检出,如果您在保存后还将其重定向回此页面。因为那时它总是被检查到最后一个编辑它的人,所以下一个人将无法打开它。如果只有一个人编辑它,那就没问题了。

第二个注意:如果您不想破解结帐系统,您也可以在保存过程中忽略它,这基本上与黑客程度相同。

以下是libraries/joomla/application/component/中来自controllerform.php的保存功能的副本。这是正常运行的原因(因为你继承的地方。我已经检查了项目是否已经检查出来了。所以如果把它放在你的parent::save...位的tireapi.php控制器中,它就是将运行而不是你不必费心检查项目(即忽略所有的评论...)。(老实说,在你的情况下,你可以删除更多这个,但这是正在发生的事情在保存,顺便说一句!)

public function save($key = null, $urlVar = null)
{
    // Check for request forgeries.
    JSession::checkToken() or jexit(JText::_('JINVALID_TOKEN'));

    // Initialise variables.
    $app   = JFactory::getApplication();
    $lang  = JFactory::getLanguage();
    $model = $this->getModel();
    $table = $model->getTable();
    $data  = JRequest::getVar('jform', array(), 'post', 'array');
    $checkin = property_exists($table, 'checked_out');
    $context = "$this->option.edit.$this->context";
    $task = $this->getTask();

    // Determine the name of the primary key for the data.
    if (empty($key))
    {
        $key = $table->getKeyName();
    }

    // To avoid data collisions the urlVar may be different from the primary key.
    if (empty($urlVar))
    {
        $urlVar = $key;
    }

    $recordId = JRequest::getInt($urlVar);

    // Populate the row id from the session.
    $data[$key] = $recordId;

    // The save2copy task needs to be handled slightly differently.
    if ($task == 'save2copy')
    {
        // Check-in the original row.
        if ($checkin && $model->checkin($data[$key]) === false)
        {
            // Check-in failed. Go back to the item and display a notice.
            $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()));
            $this->setMessage($this->getError(), 'error');

            $this->setRedirect(
                JRoute::_(
                    'index.php?option=' . $this->option . '&view=' . $this->view_item
                    . $this->getRedirectToItemAppend($recordId, $urlVar), false
                )
            );

            return false;
        }

        // Reset the ID and then treat the request as for Apply.
        $data[$key] = 0;
        $task = 'apply';
    }

    // Access check.
    if (!$this->allowSave($data, $key))
    {
        $this->setError(JText::_('JLIB_APPLICATION_ERROR_SAVE_NOT_PERMITTED'));
        $this->setMessage($this->getError(), 'error');

        $this->setRedirect(
            JRoute::_(
                'index.php?option=' . $this->option . '&view=' . $this->view_list
                . $this->getRedirectToListAppend(), false
            )
        );

        return false;
    }

    // Validate the posted data.
    // Sometimes the form needs some posted data, such as for plugins and modules.
    $form = $model->getForm($data, false);

    if (!$form)
    {
        $app->enqueueMessage($model->getError(), 'error');

        return false;
    }

    // Test whether the data is valid.
    $validData = $model->validate($form, $data);

    // Check for validation errors.
    if ($validData === false)
    {
        // Get the validation messages.
        $errors = $model->getErrors();

        // Push up to three validation messages out to the user.
        for ($i = 0, $n = count($errors); $i < $n && $i < 3; $i++)
        {
            if ($errors[$i] instanceof Exception)
            {
                $app->enqueueMessage($errors[$i]->getMessage(), 'warning');
            }
            else
            {
                $app->enqueueMessage($errors[$i], 'warning');
            }
        }

        // Save the data in the session.
        $app->setUserState($context . '.data', $data);

        // Redirect back to the edit screen.
        $this->setRedirect(
            JRoute::_(
                'index.php?option=' . $this->option . '&view=' . $this->view_item
                . $this->getRedirectToItemAppend($recordId, $urlVar), false
            )
        );

        return false;
    }

    // Attempt to save the data.
    if (!$model->save($validData))
    {
        // Save the data in the session.
        $app->setUserState($context . '.data', $validData);

        // Redirect back to the edit screen.
        $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_SAVE_FAILED', $model->getError()));
        $this->setMessage($this->getError(), 'error');

        $this->setRedirect(
            JRoute::_(
                'index.php?option=' . $this->option . '&view=' . $this->view_item
                . $this->getRedirectToItemAppend($recordId, $urlVar), false
            )
        );

        return false;
    }

    // Save succeeded, so check-in the record.
    if ($checkin && $model->checkin($validData[$key]) === false)
    {
        // Save the data in the session.
        $app->setUserState($context . '.data', $validData);

        // Check-in failed, so go back to the record and display a notice.
        $this->setError(JText::sprintf('JLIB_APPLICATION_ERROR_CHECKIN_FAILED', $model->getError()));
        $this->setMessage($this->getError(), 'error');

        $this->setRedirect(
            JRoute::_(
                'index.php?option=' . $this->option . '&view=' . $this->view_item
                . $this->getRedirectToItemAppend($recordId, $urlVar), false
            )
        );

        return false;
    }

    $this->setMessage(
        JText::_(
            ($lang->hasKey($this->text_prefix . ($recordId == 0 && $app->isSite() ? '_SUBMIT' : '') . '_SAVE_SUCCESS')
                ? $this->text_prefix
                : 'JLIB_APPLICATION') . ($recordId == 0 && $app->isSite() ? '_SUBMIT' : '') . '_SAVE_SUCCESS'
        )
    );

    // Redirect the user and adjust session state based on the chosen task.
    switch ($task)
    {
        case 'apply':
            // Set the record data in the session.
            $recordId = $model->getState($this->context . '.id');
            $this->holdEditId($context, $recordId);
            $app->setUserState($context . '.data', null);
            $model->checkout($recordId);

            // Redirect back to the edit screen.
            $this->setRedirect(
                JRoute::_(
                    'index.php?option=' . $this->option . '&view=' . $this->view_item
                    . $this->getRedirectToItemAppend($recordId, $urlVar), false
                )
            );
            break;

        case 'save2new':
            // Clear the record id and data from the session.
            $this->releaseEditId($context, $recordId);
            $app->setUserState($context . '.data', null);

            // Redirect back to the edit screen.
            $this->setRedirect(
                JRoute::_(
                    'index.php?option=' . $this->option . '&view=' . $this->view_item
                    . $this->getRedirectToItemAppend(null, $urlVar), false
                )
            );
            break;

        default:
            // Clear the record id and data from the session.
            $this->releaseEditId($context, $recordId);
            $app->setUserState($context . '.data', null);

            // Redirect to the list screen.
            $this->setRedirect(
                JRoute::_(
                    'index.php?option=' . $this->option . '&view=' . $this->view_list
                    . $this->getRedirectToListAppend(), false
                )
            );
            break;
    }

    // Invoke the postSave method to allow for the child class to access the model.
    $this->postSaveHook($model, $validData);

    return true;
}

答案 1 :(得分:0)

这不是一个真正的答案,但你的问题也不是一个真正的问题(我必须阅读它3次)。

复数“s”(对于tireapis)的东西是Joomla!自动完成。你可以覆盖它。

我建议你看一下核心组件(比如com_banners)。

您需要做的是避免重定向。你应该只有“保存”按钮,这应该让你在同一页面上。 “保存并关闭”会将您重定向到复数页面。