【发布时间】:2011-06-11 14:34:57
【问题描述】:
我正在为 MVC 应用程序 (Kohana/PHP) 编写 CSV/Excel-->MySQL 导入管理器。
我有一个名为“ImportManager”的控制器,它有一个名为“index”(默认)的操作,它在网格中显示特定的所有有效.csv 和.xls 文件目录并准备好导入。然后用户可以选择他想要导入的文件。
但是,由于.csv 文件导入一个 数据库表,.xls 文件导入多个 数据库表,我需要处理这个抽象。因此我创建了一个名为 SmartImportFile 的 helper 类 (是一个或多个)到我的收藏。这是我在 PHP 代码中的操作方法:
public function action_index()
{
$view = new View('backend/application/importmanager');
$smart_worksheets = array();
$raw_files = glob('/data/import/*.*');
if (count($raw_files) > 0)
{
foreach ($raw_files as $raw_file)
{
$smart_import_file = new Backend_Application_Smartimportfile($raw_file);
$smart_worksheets = $smart_import_file->add_smart_worksheets_to($smart_worksheets);
}
}
$view->set('smart_worksheets', $smart_worksheets);
$this->request->response = $view;
}
SmartImportFile 类如下所示:
class Backend_Application_Smartimportfile
{
protected $file_name;
protected $file_extension;
protected $file_size;
protected $when_file_copied;
protected $file_name_without_extension;
protected $path_info;
protected $current_smart_worksheet = array();
protected $smart_worksheets = array();
public function __construct($file_name)
{
$this->file_name = $file_name;
$this->file_name_without_extension = current(explode('.', basename($this->file_name)));
$this->path_info = pathinfo($this->file_name);
$this->when_file_copied = date('Y-m-d H:i:s', filectime($this->file_name));
$this->file_extension = strtolower($this->path_info['extension']);
$this->file_extension = strtolower(pathinfo($this->file_name, PATHINFO_EXTENSION));
if(in_array($this->file_extension, array('csv','xls','xlsx')))
{
$this->current_smart_worksheet = array();
$this->process_file();
}
}
private function process_file()
{
$this->file_size = filesize($this->file_name);
if(in_array($this->file_extension, array('xls','xlsx')))
{
if($this->file_size < 4000000)
{
$this->process_all_worksheets_of_excel_file();
}
}
else if($this->file_extension == 'csv')
{
$this->process_csv_file();
}
}
private function process_all_worksheets_of_excel_file()
{
$worksheet_names = Import_Driver_Excel::get_worksheet_names_as_array($this->file_name);
if (count($worksheet_names) > 0)
{
foreach ($worksheet_names as $worksheet_name)
{
$this->current_smart_worksheet['name'] = basename($this->file_name).' ('.$worksheet_name.')';
$this->current_smart_worksheet['kind'] = strtoupper($this->file_extension);
$this->current_smart_worksheet['file_size'] = $this->file_size;
$this->current_smart_worksheet['when_file_copied'] = $this->when_file_copied;
$this->current_smart_worksheet['table_name'] = $this->file_name_without_extension.'__'.$worksheet_name;
$this->assign_database_table_fields();
$this->smart_worksheets[] = $this->current_smart_worksheet;
}
}
}
private function process_csv_file()
{
$this->current_smart_worksheet['name'] = basename($this->file_name);
$this->current_smart_worksheet['kind'] = strtoupper($this->file_extension);
$this->current_smart_worksheet['file_size'] = $this->file_size;
$this->current_smart_worksheet['when_file_copied'] = $this->when_file_copied;
$this->current_smart_worksheet['table_name'] = $this->file_name_without_extension;
$this->assign_database_table_fields();
$this->smart_worksheets[] = $this->current_smart_worksheet;
}
private function assign_database_table_fields()
{
$db = Database::instance('import_excel');
$sql = "SHOW TABLE STATUS WHERE name = '".$this->current_smart_worksheet['table_name']."'";
$result = $db->query(Database::SELECT, $sql, FALSE)->as_array();
if(count($result))
{
$when_table_created = $result[0]['Create_time'];
$when_file_copied_as_date = strtotime($this->when_file_copied);
$when_table_created_as_date = strtotime($when_table_created);
if($when_file_copied_as_date > $when_table_created_as_date)
{
$this->current_smart_worksheet['status'] = 'backend.application.import.status.needtoreimport';
}
else
{
$this->current_smart_worksheet['status'] = 'backend.application.import.status.isuptodate';
}
$this->current_smart_worksheet['when_table_created'] = $when_table_created;
}
else
{
$this->current_smart_worksheet['when_table_created'] = 'backend.application.import.status.tabledoesnotexist';
$this->current_smart_worksheet['status'] = 'backend.application.import.status.needtoimport';
}
}
public function add_smart_worksheets_to(Array $smart_worksheets = array())
{
return array_merge($smart_worksheets, $this->get_smart_worksheets());
}
public function get_smart_worksheets()
{
if ( ! is_array($this->smart_worksheets))
{
return array();
}
return $this->smart_worksheets;
}
}
在代码审查中,有人告诉我最好不要有这样的辅助类,而是将大部分代码保留在控制器操作方法中本身。争论是您应该能够查看控制器操作中的代码并查看它的作用,而不是让它在自身之外调用外部帮助程序类。 我不同意。我的论点是:
- 您应该在任何时候创建一个帮助器类,它可以让代码更清晰,因为在这种情况下,它会抽象出一些文件有一个工作表或许多的事实 工作表,并允许将来轻松扩展,例如,如果我们还想从 sqlite 文件甚至 directories 中导入文件,这类抽象能够很好地处理这个问题。
- 将大部分代码从这个助手类移回控制器会迫使我在控制器中创建内部变量,这对这个特定的动作有意义,但可能有意义也可能没有意义控制器中的其他操作方法。
- 如果我在 C# 中对此进行编程,我会将这个帮助类设为 嵌套类,它实际上是一个 internal 数据结构,即在控制器类内部且仅可用于控制器类,但由于 PHP 不允许嵌套类,因此我需要在控制器“外部”调用一个类来帮助管理此抽象,以使代码清晰可读性强
根据您在 MVC 模式中的编程经验,是否应该将上述帮助程序类重构回控制器?
【问题讨论】:
-
控制器可以直接对视图进行操作,但不能渲染自身(这是视图的责任)。 “ImportMnager”不是控制器,而是视图。只需查看您的代码即可。
-
ImportManager不会呈现自己,而只是准备数据集合(要导入的工作表),然后视图会根据需要显示这些数据集合。所以ImportManager确实是一个控制器,它为它准备数据并决定哪个视图将显示该数据。
标签: php model-view-controller controller helpers