我一直在使用这个文档(我在网上找到的唯一一个)来构建一个组件: 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文件设置表单并正确加载,甚至用数据库中的适当数据填充它们。但是,当我点击“应用”时,它只是将我引导回上面列出错误的表单,而不保存。
答案 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)。
您需要做的是避免重定向。你应该只有“保存”按钮,这应该让你在同一页面上。 “保存并关闭”会将您重定向到复数页面。