Предположим, у нас есть такая функция, которая принимает 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, а в следующем посте объясним алгоритм получения столбца.
Методы принимает в качестве параметра:
Первые строки предназначены для инициализации параметров (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);
}
Таким образом, ошибка обрабатывается внутренне методом класса, и сообщение об успехе может быть скорректировано на основе контекста представления. Возвращаемое логическое значение используется для определения того, должны ли мы отображать сообщение об ошибке или сообщение об успехе.
Заметка: Юнит тест будет включен в мой ответ.
Джонатан Родитель-Левеск из Монреаля
Теперь вот метод, позволяющий преобразовать целое число в столбец Excel.
Столбец Excel может содержать от одной до трех букв до 16383 (XFD), что является текущим пределом для столбцов в файле Excel:
Я использую вместе с моей функцией массив, содержащий все английские буквы:
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;
Вот несколько примеров:
Если [число]% 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){
К примеру:
Теперь, когда диапазон чисел с использованием алгоритма 702 найден, мы должны определить, как рассчитать компенсацию. Компенсация всегда основана на 26, так что, вероятно, есть корреляция с этим …
Для диапазона 2028-2054 компенсация составляет 52.
Для диапазона 2704-2730 компенсация составляет 78.
Как видите, правило это [компенсация] = [число] / 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, если вы хотите многоязычную поддержку или не раскрываете настоящее имя ваших полей в вашей базе данных).
Я могу быть утопией для себя, но я предполагаю, что вы прочитали все объяснение, прежде чем слепо вставить мой код в свое программное обеспечение. Копирование / вставка кода непосредственно из Интернета — это на самом деле худшее, что можно сделать.
Мало того, что вы не можете быть уверены, что вы не несете бесполезный код, тесно связанный с его исходным контекстом, вы также можете быть уверены, что используете код должным образом.
Хуже того, это может привести к нарушению безопасности в вашей системе при копировании всего модуля из неизвестного источника. Никогда нельзя быть уверенным в хорошем или дурном намерении пользователя интернета …
Будет ли сила со всеми вами,
Джонатан Родитель-Левеск из Монреаля
Других решений пока нет …