Преобразование целого числа в столбец Excel (буква или буквенная комбинация) — полный пример PHP, модульный тест и пояснения

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

    /**
* 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, а в следующем посте объясним алгоритм получения столбца.

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

  • Сообщение об ошибке: использовать для возврата сообщения об ошибке
  • источник: содержит данные для отправки в файл Excel
  • Ряды: Используйте для возврата количества экспортированных строк данных
  • название: Имя для файла 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);
}

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

Заметка: Юнит тест будет включен в мой ответ.

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

-2

Решение

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

Столбец 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");

Функция принимает один параметр и утверждает, что значение является числовым и между соблюдением ограничений Excel:

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 буквах.

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

$first = floor($number / 26);

$second = $number % 26;

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

  • 27 = AA
  • 28 = AB
  • 51 = AY
  • 53 = BA

Если [число]% 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);
}

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

Если вы посмотрите внимательно, вы увидите, что из этого вытекает шаблон. Есть число, которое можно разделить на 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 для верхнего предела)).

Таким образом, кодирование для кодировки трех букв (ранее бесконечная последовательность if / else) можно возобновить в 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;
}

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

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

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

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

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

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

Будет ли сила со всеми вами,

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

-1

Другие решения

Других решений пока нет …