我正在为一个MVC应用程序(Kohana / PHP)编写一个CSV / Excel – > MysqL导入管理器.
我有一个名为“ImportManager”的控制器,它有一个名为“index”(默认)的操作,它在网格中显示特定目录中的所有有效.csv和.xls文件,并准备导入.然后,用户可以选择要导入的文件.
但是,由于.csv文件导入到一个数据库表中,而.xls文件导入到多个数据库表中,我需要处理这种抽象.因此,我创建了一个名为SmartImportFile的帮助器类,我将每个文件发送到它.csv或.xls然后我得到这个“智能”对象,将该文件中的工作表(无论是一个还是多个)添加到我的集合中.这是我在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文件或甚至包含文件的目录导入,这个类抽象将能够很好地处理这个. >将大部分代码从此帮助程序类移回控制器将迫使我在控制器中创建对此特定操作有意义的内部变量,但可能对控制器内的其他操作方法有意义,也可能没有意义. >如果我在C#中编程,我会使这个帮助器类成为一个嵌套类,它实际上是一个内部数据结构,只能在控制器类中使用,但由于PHP不允许嵌套类,我需要调用控制器“外部”的一个类,用于帮助管理这种抽象,使代码清晰可读
根据您在MVC模式中编程的经验,上述辅助类是否应该重构为控制器? 解决方法: 控制器有两种方法:使其变薄或变厚.当我开始使用MVC进行冒险时,我犯了一个创建厚控制器的错误 – 现在我更喜欢尽可能地让它变薄.在我看来,你的解决方案很好.
以下是我将如何进一步重新设计代码:
class Backend_Application_SmartImport {
public function __construct( $raw_files ) {
}
public function process() {
foreach ($raw_files as $raw_file) {
// (...)
$oSmartImportFileInstance = $this->getSmartImportFileInstance( $smart_import_file_extension );
}
}
protected function getSmartImportFileInstance( $smart_import_file_extension ) {
switch ( $smart_import_file_extension ) {
case 'xml':
return new Backend_Application_SmartImportFileXml();
// (...)
}
}
}
abstract class Backend_Application_SmartImportFile {
// common methods for importing from xml or cvs
abstract function process();
}
class Backend_Application_SmartImportFileCVS extends Backend_Application_SmartImportFile {
// methods specified for cvs importing
}
class Backend_Application_SmartImportFileXls extends Backend_Application_SmartImportFile {
// methods specified for xls importing
}
我们的想法是让两个类负责处理从基类继承的xml和cvs.主类使用特殊方法来检测数据的处理方式(Strategy Pattern).控制器只是将文件列表传递给Backend_Application_SmartImport类的实例,并将处理方法的结果传递给视图.
我的解决方案的优点是代码更加分离,您可以轻松地以干净的方式添加新类型的处理,如xml,pdf等. (编辑:北几岛)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|