2015-10-01 39 views
-2

Предположим, что у нас есть такая функция, которая принимает PDOStatement (любой запрос) и автоматически генерирует файл excel (используя библиотеку PHPExcel):Конвертировать целое число в столбец Excel (комбинация букв или букв) - полный пример PHP, модульный тест и объяснение

/** 
* Create an Excel file from an opened PDOStatement. Return the path to access the Excel file 
* or an empty string if we were not able to create the Excel File 
* 
* 
* @param $errorMessage String to return the error message. 
* @param $source PDOStatement containing the data to export to Excel. 
* @param $rows Int Use to return the number of rows exported (the header row isn't counted). 
* @param $name String name to give to the Excel file (no need to specify the extension). 
* @param $columnName (optional) String Array used for the name of the row in the Excel file. 
* 
* @return String 
*/ 
public static function createExcelFromRS(&$errorMessage, PDOStatement &$source, &$rows , $name, array $columnName = array()){ 

    $errorMessage = ""; 

    $name = self::validateFileExtention($name, "xlsx"); 

    $path = realpath(dirname(__FILE__)) . '/Archive/' . $name; 

    $rows = 0; 

    $totalCols = 0; 


    $excel = new PHPExcel(); 

    $writer = PHPExcel_IOFactory::createWriter($excel, "Excel2007"); 

    $sheet = $excel->getActiveSheet(); 

    $sheet->setTitle($name); 


    while ($row = $source->fetch(PDO::FETCH_ASSOC)){ 

     if ($rows === 0){ 

      $columnName = self::validateColumnNameArray($columnName, $row); 

      $totalCols = count($row); 

      $sheet->getStyle('A1:' . self::convertNumberToExcelCol($totalCols) . '1')->getFont()->setBold(true)->setSize(12); 

      for ($column = 1; $column <= $totalCols; $column++){ 

       $sheet->getCell(self::convertNumberToExcelCol($column) . '1')->setValue($columnName[$column - 1]); 

       $sheet->getColumnDimension(self::convertNumberToExcelCol($column))->setAutoSize(true); 
      } 

      $rows = 1; 
     } 

     $rows++; 

     $column = 1; 

     foreach ($row as $field){ 

      $sheet->getCell(self::convertNumberToExcelCol($column) . $rows)->setValue($field); 

      $column++; 
     } 
    } 

    $writer->save($path); 

    unset($sheet, $writer, $excel); 


    if ($rows < 1){ 

     if (is_file($path)){ 

      unlink($path); 
     } 

     $errorMessage =str_replace("[TYPE]", "EXCEL", GeneralDbManager::getInstance()->getErrorMessage('NO_DATA_TO_EXPORT_FILE_ERR', 'There is no data to export to the [TYPE] file.'));  
    } 
    elseif(!is_file($path)){ 

     $errorMessage = str_replace(array("[TYPE]", "[NAME]"), array("EXCEL", $name), GeneralDbManager::getInstance()->getErrorMessage('EXPORT_NO_CREATED_FILE_ERR', 'We were not able to create the [TYPE] file: [NAME].')); 
    } 
    else{ 

     $rows --; 
    } 

    return (empty($errorMessage) ? $path : ""); 
} 

и мы хотим, чтобы преобразовать целое значение в столбце Excel с помощью функции convertNumberToExcelCol.

Давайте сначала объясним этот метод для создания файла excel, и следующее сообщение объяснит алгоритм, чтобы получить столбец.

Методы, принимает в качестве параметра:

  • ErrorMessage: использовать для возврата сообщения об ошибке,
  • источника: содержат данные, чтобы подтолкнуть к Ехчел
  • Rows: Использование для возврата количества экспортированных строк данных
  • имя: Название t o предоставить файлу excel
  • columnName: необязательный массив, используемый с именем для чтения человеком (или переводом). Если этот параметр опущен, метод использует имя поля из запроса.

Первые строки предназначены для инициализации параметров (PHP использует свободную типизацию, поэтому мы должны быть осторожны с параметрами).

Эта функция убедитесь, что имя есть действительное имя/расширение:

/** 
* Validate that the file $name has the proper file $extension 
* and return the fixed name with the proper extension 
* 
* Note: No modification will be made if the extension is not a string or is empty 
* 
* @param $name String file name with or without extension 
* @param $extension String example: csv, xls 
* 
* @return String 
*/ 
public static function validateFileExtention($name, $extension){ 

    if (is_string($extension)){ 

     $extension = "." . str_replace(".", "", $extension); 

     if (strlen($extension) > 1){ 

      if (!is_string($name) or empty($name) or strpos($name, ".") === 0){ 

       $name = "my_file" . $extension; 
      } 
      elseif(strpos(strtolower($name), $extension) === false){ 

       if (strrpos($name, ".") === false){ 

        $name .= $extension;  
       } 
       else{ 

        if (substr_count($name, ".") > 1){ 

         $name = str_replace(".", "", $name) . $extension; 
        } 
        else{ 

         $name = str_replace(substr($name, strrpos($name, ".")), $extension, $name); 
        } 
       } 
      } 
     } 
    } 

    return $name; 
} 

Затем мы открываем подключение к файлу Excel:

$excel = new PHPExcel(); 

$writer = PHPExcel_IOFactory::createWriter($excel, "Excel2007"); 

$sheet = $excel->getActiveSheet(); 

$sheet->setTitle($name); 

Эта функция гарантирует, что имя столбца массив имеет ту же длину, что и количество полей в массиве строк.

/** 
* Take the array containing the $columnName for data export (CSV, Excel) and make sure 
* that it is the number of entry as there are fields in $row. 
* 
* If column name are missing, we will use the column name used in the query. 
* 
* Return the merged array 
* 
* @param $columnName Array containing the column names 
* @param $row Array produce by fetch(PDO::FETCH_ASSOC). 
* 
* @return Array ($columnName) 
*/ 
private static function validateColumnNameArray(array &$columnName, array &$row){ 

    $buffer = array(); 

    $colPDO = count($row); 

    $count = count($columnName); 

    if ($count < $colPDO){ 

     foreach ($row as $key => $value){ 

      $buffer[] = $key; 
     } 

     for($index = $count; $index < $colPDO; $index++){ 

      $columnName[] = $buffer[$index]; 
     } 
    } 

    unset($buffer); 

    return $columnName; 
} 

Оба validateFileExtention и validateColumnNameArray предназначены для общего кода с функцией создания CSV:

/** 
* Create a CSV file from an opened PDOStatement. Return the path to access the CSV file 
* or an empty string if we were not able to create the CSV File 
* 
* 
* @param $errorMessage String to return the error message. 
* @param $source PDOStatement containing the data to export to CSV 
* @param $rows Int Use to return the number of rows exported (the header row isn't counted). 
* @param $name String name to give to the CSV file (no need to specify the extension). 
* @param $columnName (optional) String Array used for the name of the row in the CSV file. 
* 
* @return String 
*/ 
public static function createCSVFromRS(&$errorMessage, PDOStatement &$source, &$rows , $name, array $columnName = array()){ 

    $errorMessage = ""; 

    $name = self::validateFileExtention($name, "csv"); 

    $path = realpath(dirname(__FILE__)) . '/Archive/' . $name; 

    $rows = 0; 


    $file = fopen($path, "w"); 

    while ($row = $source->fetch(PDO::FETCH_ASSOC)){ 

     if ($rows === 0){ 

      fputcsv($file, array_map('utf8_decode',self::validateColumnNameArray($columnName, $row))); 
     } 

     fputcsv($file, array_map('utf8_decode',array_values($row))); 

     $rows++; 
    } 

    fclose($file); 


    if ($rows < 1){ 

     if (is_file($path)){ 

      unlink($path); 
     } 

     $errorMessage =str_replace("[TYPE]", "CSV", GeneralDbManager::getInstance()->getErrorMessage('NO_DATA_TO_EXPORT_FILE_ERR', 'There is no data to export to the [TYPE] file.')); 
    } 
    elseif(!is_file($path)){ 

     $errorMessage = str_replace(array("[TYPE]", "[NAME]"), array("CSV", $name), GeneralDbManager::getInstance()->getErrorMessage('EXPORT_NO_CREATED_FILE_ERR', 'We were not able to create the [TYPE] file: [NAME].')); 
    } 


    return (empty($errorMessage) ? $path : ""); 
} 

Если это первая строка добавляется в файл Excel, то мы устанавливаем основные форматирования:

if ($rows === 0){ 

      $columnName = self::validateColumnNameArray($columnName, $row); 

      $totalCols = count($row); 

      $sheet->getStyle('A1:' . self::convertNumberToExcelCol($totalCols) . '1')->getFont()->setBold(true)->setSize(12); 

      for ($column = 1; $column <= $totalCols; $column++){ 

       $sheet->getCell(self::convertNumberToExcelCol($column) . '1')->setValue($columnName[$column - 1]); 

       $sheet->getColumnDimension(self::convertNumberToExcelCol($column))->setAutoSize(true); 
      } 

      $rows = 1; 
     } 

С помощью метода getStyle мы устанавливаем строку заголовка жирным шрифтом и размером 12.

Метод getCOlumnDimension используется для установки автосохранения, поэтому пользователю не нужно изменять размер самого столбца при открытии файла.

Остальная часть цикла - перенос данных из массива строк в файл excel.

После циклов мы закрываем соединение и отключим использование переменной для управления Excel.

Затем идет управление ошибками:

if ($rows < 1){ 

     if (is_file($path)){ 

      unlink($path); 
     } 

     $errorMessage =str_replace("[TYPE]", "EXCEL", GeneralDbManager::getInstance()->getErrorMessage('NO_DATA_TO_EXPORT_FILE_ERR', 'There is no data to export to the [TYPE] file.'));  
    } 
    elseif(!is_file($path)){ 

     $errorMessage = str_replace(array("[TYPE]", "[NAME]"), array("EXCEL", $name), GeneralDbManager::getInstance()->getErrorMessage('EXPORT_NO_CREATED_FILE_ERR', 'We were not able to create the [TYPE] file: [NAME].')); 
    } 
    else{ 

     $rows --; 
    } 

Сообщения хранится в базе данных, поэтому мы можем предложить переведенное сообщение пользователя. Я использую общие теги [TYPE] и [NAME] в своем сообщении, которое я заменяю на соответствующий тип файла и имя файла.

Это позволяет мне повторно использовать это общее сообщение как в моем файле excel, так и в CSV (или независимо от того, какой файл) я создаю.

Если созданный файл пуст, я его удаляю. Эта операция является необязательной, но мне нравится очищать неиспользуемый файл с диска, как только я закончил с ним.

Другой способ обойти это использовать функцию, чтобы очистить каталог хранения:

/** 
* Clear all the archives (zip) files in the archive folder. 
*/ 
public static function emptyArchiveFolder(){ 

    $handle = NULL; 
    $path = realpath(dirname(__FILE__)) . '/Archive/'; 

    if (is_dir($path) and $handle = opendir($path)) { 

     while (false !== ($entry = readdir($handle))) { 

      $file = $path . $entry; 

      if (is_file($file)){ 

       unlink($file); 
      } 
     } 

     unset($handle); 
    } 

} 

Я лично только с помощью этой методики, когда я делаю процедуру автоматического резервного копирования моего исходного файла и базы данных в полночь , Запуск в течение дня увеличивает вероятность удаления файлов другим пользователем.

Вот почему я рассматриваю лучшую практику для удаления файлов, как только они будут отправлены пользователю через браузер, и оставьте методы очистки только для целей обслуживания.

Если ошибок нет, я уменьшаю количество строк на единицу, так как не хочу подсчитывать строку заголовка. Эта строка может быть удалена, если вы рассматриваете строку заголовка как строку данных.

Наконец методы возвращают путь для доступа к вновь созданному файлу:

return (empty($errorMessage) ? $path : ""); 

, но только если не было никакой ошибки. Итак, если функция возвращает пустую строку, это означает, что произошла ошибка.

PHP, будучи свободным, может возвращать все, включая логическое или даже сообщение об ошибке, но я предпочитаю всегда возвращать один и тот же тип данных для цели постоянства. Мои личные любимые методы - это логические значения возврата и переменная сообщения об ошибке, переданная по ссылке. Так что я могу использовать такой код:

$errorMessage = ""; 

      if ($_SESSION["adminAccount"]->updateAccountInfo($errorMessage, 
                 (isset($_POST['FIRST_NAME_TEXT']) ? $_POST['FIRST_NAME_TEXT'] : $_SESSION["adminAccount"]->getFirstName()), 
                 (isset($_POST['LAST_NAME_TEXT']) ? $_POST['LAST_NAME_TEXT'] : $_SESSION["adminAccount"]->getLastName()), 
                 (isset($_POST['EMAIL_TEXT']) ? $_POST['EMAIL_TEXT'] : $_SESSION["adminAccount"]->getEmail()))){ 

       PageManager::displaySuccessMessage("Your account information were saved with success.", "USER_ACCOUNT_INFORMATION_SAVED"); 

      } 
      else{ 

       PageManager::displayErrorMessage($errorMessage);  
      } 

Таким образом, ошибка управляется изнутри методом класса, а сообщение успеха можно регулировать базу на контекст просмотра. Значение логического возврата используется для определения того, нужно ли отображать сообщение об ошибке или сообщение об успешном завершении.

Примечание: Единичный тест будет включен в мой ответ.

Джонатан Родитель-Левек из Монреаля

+0

Я даю полное кодирование для автоматического создания файла csv и файла excel. Включите объяснение, как написать сложный алгоритм для преобразования значения числа в столбце excel. Подтвердите все, выполнив единичный тест. Программирование на 12 часов, 3 объяснения, и людям это не нравится. Сумасшедший мир, хе ... –

ответ

-1

Теперь вот метод, позволяющий преобразовать целое число в столбце Excel.

первенствовать колонок может быть комбинацией одного до трех букв до 16383 (XFD), который является ограничением тока для столбцов в файле Excel:

https://support.office.com/en-nz/article/Excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3

Я использую вместе с моей функцией является массив содержащий все английские буквы:

public static $letters = array(1 => "A", 2 => "B", 3=> "C", 4 => "D", 5 => "E", 6 => "F", 7 => "G", 8=> "H", 9=> "I", 10 => "J", 11 =>"K", 12 => "L", 13 => "M", 14 => "N", 15=> "O", 16 => "P", 17 => "Q", 18 => "R", 19 => "S", 20 => "T", 21 => "U", 22 => "V", 23 => "W", 24 => "X", 25 => "Y", 26 => "Z"); 

функции принимать один параметр и утверждать, что значение является числовым и между уважением превосходит ограничения:

public static function convertNumberToExcelCol($number){ 

    $column = ""; 

    if (is_numeric($number) and $number > 0 and $number < 16385){ 

Если число от 1 до 26 (столбцы A-Z), то это кусок торта. Мы просто получаем письмо непосредственно в массиве. Тест

$column = self::$letters[$number]; 

Давайте так:

for ($index = 1; $index < 27; $index++){ 

     $this->assertEquals(FileManager::$letters[$index], FileManager::convertNumberToExcelCol($index)); 
    } 

Если столбец, если между 27 и 702 (AA-ZZ), кодирование остается довольно просто:

if ($number % 26 === 0){ 

     $first = floor($number/26) - 1; 

     $second = 26; 
    } 
    else{ 

     $first = floor($number/26); 

     $second = $number % 26; 
    } 

    $column = self::$letters[$first] . self::$letters[$second]; 

Поскольку английский алфавит содержит 26 букв, весь алгоритм также находится на базе 26.

Для большинства значений мы можем просто получить первый l Etter пути округления вниз [числа]/26 и вторая буквы, используя все деление (оставшееся от деления) чисел: [число]% 26.

$first = floor($number/26); 

$second = $number % 26; 

Вот несколько примеров:

  • 27 = АА
  • 28 = АВ
  • 51 = АУ
  • 53 = ВА

Если [число]% 26 = 0, например: 52, 78, 104 и т. Д., То мы должны использовать немного различного кодирования.

Например, 52 = AZ, но 52/26 = 2 (первая буква) и 52% 26 = 0 (вторая буква).

2 = B и 0 не связаны в нашем массиве букв. Вот почему мы должны уменьшить значение на единицу для первой буквы и силу 26 как значение для второй буквы.

$first = floor($number/26) - 1; 

$second = 26; 

Время тестирования:

for ($first = 1; $first < 27; $first++){ 

     $temp = $first * 26; 

     for ($second = 1; $second < 27; $second++){ 
      $this->assertEquals(FileManager::$letters[$first] . FileManager::$letters[$second], FileManager::convertNumberToExcelCol($temp + $second)); 
     } 
    } 

Реальная проблема возникает, когда мы пытаемся управлять три буквы. Конечно, у вас, вероятно, не будет запроса с более чем 702 полями, но, ради полноты метода и некоторой реальной проблемы программирования, давайте рассмотрим, как это сделать!

Сначала я должен был попробовать-тестирования ошибки и в конечном итоге с помощью следующего кодирования:

elseif($number < 1379){ 

    $column = self::$letters[floor($number/702)] . self::convertNumberToExcelCol($number % 702 + 26); 
} 
elseif($number < 2028){ 

    $column = self::$letters[floor($number/676)] . self::convertNumberToExcelCol($number % 676); 
} 
elseif ($number < 2055){ 

    $column = self::$letters[floor($number/702)] . self::convertNumberToExcelCol($number % 702 + 52); 
} 
elseif($number < 2704){ 

    $column = self::$letters[floor($number/676)] . self::convertNumberToExcelCol($number % 676); 
} 
elseif ($number < 2731) { 

    $column = self::$letters[floor($number/702)] . self::convertNumberToExcelCol($number % 702 + 78); 
} 
elseif ($number < 3380) { 

    $column = self::$letters[floor($number/676)] . self::convertNumberToExcelCol($number % 676);  
} 
elseif ($number < 3407){ 

    $column = self::$letters[floor($number/702)] . self::convertNumberToExcelCol($number % 702 + 104);  
} 

Да, это не серьезно, и вы можете пройти весь путь до 16К, как это ...

Если вы внимательно присмотритесь, вы увидите, что из этого рисунка. Есть число, которое можно разделить на 676, чтобы получить первую букву и по модулю 676, чтобы получить вторую и третью буквы. Например, 2027 = ДБЯ.

Второй шаблон - это числа, которые можно разделить на первую букву по модулю 702 + компенсация (26, 52, 78, 104, ...). Это число, например, 703 = AAA.

Конечно, 676 и 702 являются кратна 26.

Он взял меня довольно много расчета, но я пришел, чтобы поняли, что вторая модель всегда диапазон 27 чисел, и эти числа всегда производят число ниже 27 (0-26) по модулю этого числа.

elseif($number < 2028){ 

    $column = self::$letters[floor($number/676)] . self::convertNumberToExcelCol($number % 676); 
} 
elseif ($number < 2055){ 

К примеру:

  • 2028% 676 = 0
  • 2029% 676 = 1
  • ...
  • 2054% 676 = 26
  • 2055% 676 = 27 (в настоящее время вне допустимого диапазона)

Теперь, когда найден диапазон чисел с использованием алгоритма 702, мы должны определить, как вычислить компенсацию. Компенсация всегда 26 на основе, так что, вероятно, корреляция с этим ...

Для диапазона 2028-2054, компенсация из 52.

  • 2028/26 = 78
  • 2029/26 = 78,03846
  • ...
  • 2054/26 = 79

Для диапазона 2704-2730, компенсация из 78.

  • 2704/26 = 104
  • 2730/26 = 105

Как вы можете видеть, это правило в [компенсации] = [число]/26 - 26 (минус 1 для верхний предел)).

Таким образом, кодирование для кодирования для трех букв (ранее бесконечной череды если/другое) может быть возобновлено в 5 строк:

   if($number % 676 < 27){ 

        $compensation = floor($number/26) - 26; 

        $column = self::$letters[floor($number/702)] . self::convertNumberToExcelCol($number % 702 + ($compensation % 26 === 0 ? $compensation : $compensation - 1)); 
       } 
       else{ 
        $column = self::$letters[floor($number/676)] . self::convertNumberToExcelCol($number % 676); 
       } 

Функция возвращает комбинацию букв или пустую строку, если значение параметра недействительно.

Давайте проверим это как раз, чтобы убедиться, что я не обманываю вас:

 for ($first = 1; $first < 27; $first++){ 

     for ($second = 1; $second < 27; $second++){ 

      for ($third = 1; $third < 27; $third++){ 

       $temp = $first * 676 + (($second * 26) + $third); 

       if ($temp < 16385){ 

        $this->assertEquals(FileManager::$letters[$first] . FileManager::$letters[$second] . FileManager::$letters[$third], FileManager::convertNumberToExcelCol($temp)); 

       } 
       else{ 

        $this->assertEmpty(FileManager::convertNumberToExcelCol($temp + $index)); 
       } 
      } 
     } 
    } 

Вот полная функция:

/** 
* Convert a $number to the letter (or combination of letters) representing a column in excel. 
* Will return an empty string if $number is not a valid value. 
* 
* @param number Int must be is_numeric() and > 0 and < 16,385. 
* 
* @return String 
*/ 
public static function convertNumberToExcelCol($number){ 

    $column = ""; 

    if (is_numeric($number) and $number > 0 and $number < 16385){ 

     if ($number < 27){ 

      $column = self::$letters[$number]; 
     } 
     elseif ($number < 703){ 

      if ($number % 26 === 0){ 

       $first = floor($number/26) - 1; 

       $second = 26; 
      } 
      else{ 

       $first = floor($number/26); 

       $second = $number % 26; 
      } 

      $column = self::$letters[$first] . self::$letters[$second]; 
     } 
     else{ 

      if($number % 676 < 27){ 

       $compensation = floor($number/26) - 26; 

       $column = self::$letters[floor($number/702)] . self::convertNumberToExcelCol($number % 702 + ($compensation % 26 === 0 ? $compensation : $compensation - 1)); 
      } 
      else{ 
       $column = self::$letters[floor($number/676)] . self::convertNumberToExcelCol($number % 676); 
      } 
     } 
    } 


    return $column; 
} 

И, конечно же, как и обещал, вот модульного тестирования кода для создание файла excel/csv.

public function testvalidateFileExtention(){ 

    //invalid extension 
    $this->assertEquals("woot", FileManager::validateFileExtention("woot", true)); 

    $this->assertEquals("woot", FileManager::validateFileExtention("woot", "")); 

    $this->assertEquals("woot", FileManager::validateFileExtention("woot", ".")); 

    $this->assertEquals("woot.blu", FileManager::validateFileExtention("woot", ".b.l.u..")); 


    //invalid name 
    $this->assertEquals("my_file.blu", FileManager::validateFileExtention(true, ".blu")); 

    $this->assertEquals("my_file.blu", FileManager::validateFileExtention("", ".blu")); 

    $this->assertEquals("my_file.blu", FileManager::validateFileExtention(".woot", ".blu")); 

    $this->assertEquals("woot.blu", FileManager::validateFileExtention("w.o.o.t.", ".blu")); 


    //valid file name and extension 
    $this->assertEquals("woot.blu", FileManager::validateFileExtention("woot", "blu")); 

    $this->assertEquals("woot.blu", FileManager::validateFileExtention("woot", ".blu")); 

} 

public function testCreateCSVFromRS(){ 

    FileManager::emptyArchiveFolder(); 

    $errorMessage = ""; 
    $path = realpath(dirname(__FILE__)) . '/../Archive/woot.csv'; 
    $rows = 0; 


    //no data to export 
    $rs = $this->fetchData("SELECT id, field_id, field_value, language FROM error_message_table WHERE field_id='woot for loots'"); 

    $this->assertInstanceOf('PDOStatement', $rs); 


    $this->assertEmpty(FileManager::createCSVFromRS($errorMessage, $rs, $rows, "woot")); 

    $this->assertNotEmpty($errorMessage); 

    $this->assertEquals(0, $rows); 

    $this->assertFileNotExists($path); 


    //data, but missing columns in the header array 
    $rs = $this->fetchData("SELECT id, field_id, field_value, language FROM error_message_table LIMIT 100"); 

    $this->assertNotEmpty(FileManager::createCSVFromRS($errorMessage, $rs, $rows, "woot", array("homer", "simpson"))); 

    $this->assertInstanceOf('PDOStatement', $rs); 

    $this->assertEmpty($errorMessage); 

    $this->assertEquals(100, $rows); 

    $this->assertFileExists($path); 


    $handle = fopen($path, "r"); 

    $this->assertNotEquals(false, $handle); 

    $row = fgetcsv($handle); 


    $this->assertContains("homer", $row); 

    $this->assertNotContains("id", $row); 


    $this->assertContains("simpson", $row); 

    $this->assertNotContains("field_id", $row); 


    $this->assertContains("field_value", $row); 

    $this->assertContains("language", $row); 


    fclose($handle); 


    //data, changing all columns in the header array 
    $rs = $this->fetchData("SELECT id, field_id, field_value, language FROM error_message_table LIMIT 10"); 

    $this->assertNotEmpty(FileManager::createCSVFromRS($errorMessage, $rs, $rows, "woot", array("kyle", "eric", "kenny", "stan"))); 

    $this->assertInstanceOf('PDOStatement', $rs); 

    $this->assertEmpty($errorMessage); 

    $this->assertEquals(10, $rows); 

    $this->assertFileExists($path); 


    $handle = fopen($path, "r"); 

    $this->assertNotEquals(false, $handle); 

    $row = fgetcsv($handle); 


    $this->assertContains("kyle", $row); 

    $this->assertNotContains("id", $row); 


    $this->assertContains("eric", $row); 

    $this->assertNotContains("field_id", $row); 


    $this->assertContains("kenny", $row); 

    $this->assertNotContains("field_value", $row); 


    $this->assertContains("stan", $row); 

    $this->assertNotContains("language", $row); 


    fclose($handle); 

    unlink($path); 
} 

public function testConvertNumberToExcelCol(){ 

    //invalid paramter 
    $this->assertEmpty(FileManager::convertNumberToExcelCol("a")); 

    $this->assertEmpty(FileManager::convertNumberToExcelCol(array())); 

    $this->assertEmpty(FileManager::convertNumberToExcelCol(-1)); 

    $this->assertEmpty(FileManager::convertNumberToExcelCol(1000000000)); 


    //single letter 
    for ($index = 1; $index < 27; $index++){ 

     $this->assertEquals(FileManager::$letters[$index], FileManager::convertNumberToExcelCol($index)); 
    } 

    //double letters 
    for ($first = 1; $first < 27; $first++){ 

     $temp = $first * 26; 

     for ($second = 1; $second < 27; $second++){ 
      $this->assertEquals(FileManager::$letters[$first] . FileManager::$letters[$second], FileManager::convertNumberToExcelCol($temp + $second)); 
     } 
    } 

    //tripple letters 
    for ($first = 1; $first < 27; $first++){ 

     for ($second = 1; $second < 27; $second++){ 

      for ($third = 1; $third < 27; $third++){ 

       $temp = $first * 676 + (($second * 26) + $third); 

       if ($temp < 16385){ 

        $this->assertEquals(FileManager::$letters[$first] . FileManager::$letters[$second] . FileManager::$letters[$third], FileManager::convertNumberToExcelCol($temp)); 

       } 
       else{ 

        $this->assertEmpty(FileManager::convertNumberToExcelCol($temp + $index)); 
       } 
      } 
     } 
    } 
} 


public function testCreateExcelFromRS(){ 

    $errorMessage = ""; 
    $path = realpath(dirname(__FILE__)) . '/../Archive/woot.xlsx'; 
    $rows = 0; 


    //no data to export 
    $rs = $this->fetchData("SELECT id, field_id, field_value, language FROM error_message_table WHERE field_id='woot for loots'"); 

    $this->assertInstanceOf('PDOStatement', $rs); 


    $this->assertEmpty(FileManager::createExcelFromRS($errorMessage, $rs, $rows, "woot")); 

    $this->assertNotEmpty($errorMessage); 

    $this->assertEquals(0, $rows); 

    $this->assertFileNotExists($path); 


    //data, but missing columns in the header array 
    $rs = $this->fetchData("SELECT id, field_id, field_value, language FROM error_message_table LIMIT 100"); 

    $this->assertNotEmpty(FileManager::createExcelFromRS($errorMessage, $rs, $rows, "woot", array("homer", "simpson"))); 

    $this->assertInstanceOf('PDOStatement', $rs); 

    $this->assertEmpty($errorMessage); 

    $this->assertEquals(100, $rows); 

    $this->assertFileExists($path); 


    $reader = PHPExcel_IOFactory::createReaderForFile($path); 
    $reader->setReadDataOnly(true); 
    $excel = $reader->load($path); 


    $this->assertEquals("homer", $excel->getSheet(0)->getCell('A1')->getValue()); 

    $this->assertEquals("simpson", $excel->getSheet(0)->getCell('B1')->getValue()); 

    $this->assertEquals("field_value", $excel->getSheet(0)->getCell('C1')->getValue()); 

    $this->assertContains("language", $excel->getSheet(0)->getCell('D1')->getValue()); 

    $excel->disconnectWorksheets(); 

    unset($excel); 



    //data, changing all columns in the header array 
    $rs = $this->fetchData("SELECT id, field_id, field_value, language FROM error_message_table LIMIT 10"); 

    $this->assertNotEmpty(FileManager::createExcelFromRS($errorMessage, $rs, $rows, "woot", array("kyle", "eric", "kenny", "stan"))); 

    $this->assertInstanceOf('PDOStatement', $rs); 

    $this->assertEmpty($errorMessage); 

    $this->assertEquals(10, $rows); 

    $this->assertFileExists($path); 


    $reader = PHPExcel_IOFactory::createReaderForFile($path); 
    $reader->setReadDataOnly(true); 
    $excel = $reader->load($path); 


    $this->assertEquals("kyle", $excel->getSheet(0)->getCell('A1')->getValue()); 

    $this->assertEquals("eric", $excel->getSheet(0)->getCell('B1')->getValue()); 

    $this->assertEquals("kenny", $excel->getSheet(0)->getCell('C1')->getValue()); 

    $this->assertContains("stan", $excel->getSheet(0)->getCell('D1')->getValue()); 

    $excel->disconnectWorksheets(); 


    unlink($path); 
} 

private function fetchData($query, $db = "language_manager"){ 

    $_SESSION['domain'] = $db; 

    $errorMessage = ""; 

    $dbManager = GeneralDBManager::getInstance(); 

    $rs = $dbManager->fetchData($query . ";/*th1s 1s a v4l1d qu3ry*/", $errorMessage); 

    unset($dbManager); 

    return $rs; 
} 

Заключение: Пример кодирования позволяет автоматически генерировать первенствовать (или CSV) файл из любого запроса через PDO в одной строке кода.

В моей предыдущей работе отсутствие централизации привело к тому, что я написал бесчисленные функции (в VB6) для экспорта данных из программного обеспечения (GEM-CAR). Конечно, при написании базовой функции экспорта данных нет ничего эзотерического, но для каждого нового экспорта требуется написать новые функции. Каждая из функций сама по себе оказывается сложной задачей с течением времени.

С этими методами централизации требуется только одна строка кода для создания файла. Это означает, что вам нужно только изменить SQL-запрос, чтобы изменить содержимое файла (значения массива columnName, если вы хотите многоязычную поддержку или не показывать реальное имя ваших полей в своей базе данных).

Я могу быть утопией для себя, но я предполагаю, что вы прочитали все объяснение, прежде чем слепо вставить мою кодировку в свое программное обеспечение. Копирование/вставка кодирования непосредственно из Интернета на самом деле самое худшее, что можно сделать.

Не только вы не можете быть уверены, что не несёте бесполезный код, тесно связанный с его исходным контекстом, вы также можете быть уверены, что используете код тоже.

Хуже того, это может привести даже к нарушению безопасности в вашей системе при копировании всего модуля из неизвестного источника. Никогда нельзя быть уверенным в хорошем или плохого намерения пользователя Интернет ...

Shall сила будет с вами,

Джонатан Родитель-Левек из Монреаля