Преобразование Excel-файла в PHP класс

Преобразование Excel-файла в PHP класс

Преобразование Excel-файла в PHP класс

Доброго времени суток! В данной статье я покажу Вам как можно преобразовать Excel-файл
в PHP объект для дальнейшей работы с ним
.

Допустим у нас есть некий Excel-документ, например бухгалтерский баланс некой кредитной организации. И нам необходимо вытащить из его столбцов значения, которые нужно будет назначить соответствующим полям класса.

Для начала создадим файл composer.json со следующим содержимым:



{

    "autoload": {

        "psr-4": {

            "SampleApp\BanksReporting\": "src"

        }

    },

    "require": {

        "phpoffice/phpspreadsheet": "^1.20"

    }

}



Файловая структура проекта следующая:



.

├── files

│   ├── report_01102021.xlsx

│   └── report_01072021.xlsx

├── src

│   ├── BalanceSheet.php

│   ├── currentPeriodMapper.php

│   ├── previousPeriodMapper.php

│   └── read_excel.php

├── vendor

├── composer.json

└── composer.lock



Далее выполним команду в директории проекта для установки пакета phpoffice/phpspreadsheet:



$ composer install



Содержимое файла класса BalanceSheet. Его содержимое полностью зависит от структуры Вашего Excel-файла. В данном случае он такой:



<?php



    namespace SampleAppBanksReporting;



    class BalanceSheet

    {

        // метаданные отчета

        public $reportDate;

        public $bankName;

        public $postAddress;



        // активы

        public $moneyAssets;

        public $fundsInTheCentralBank;

        public $mandatoryReserves;

        public $fundsInCreditInstitutions;

        public $loanDebt;

        public $fixedAssets;

        public $requirementsForInterest;

        public $otherAssets;

        public $totalAssets;



        // пассивы

        public $loansOfTheCentralBank;

        public $fundsOfCreditInstitutions;

        public $fundsOfClientsNonCreditOrganizations;

        public $depositsOfIndividuals;

        public $debtObligationsIssued;

        public $iterestPaymentOobligations;

        public $otherLiabilities;

        public $provisionsForPpossibleLosses;

        public $totalObligations;



        // источники собственных средств

        public $fundsOfShareholders;

        public $sharesRepurchasedFromShareholders;

        public $seigniorage;

        public $revaluationOfFixedAssets;

        public $deferredExpenses;

        public $unusedProfitsOrOutstandingLossesOfPreviousYears;

        public $profitOrLossForTheReportingPeriod;

        public $totalSourcesOfOwnFunds;

        public $totalLiabilities;



        // забалансовые пассивы

        public $irrevocableObligations;

        public $guaranteesByBank;

    }



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

Файл для предыдущего периода:



<?php



    return [



        // metadata

        'reportDate'  => 'A1',

        'bankName'    => 'C2',

        'postAddress' => 'A3',



        // Cells

        'moneyAssets'               => 'D8',

        'fundsInTheCentralBank'     => 'D9',

        'mandatoryReserves'         => 'D10',

        'fundsInCreditInstitutions' => 'D11',

        'loanDebt'                  => 'D12',

        'fixedAssets'               => 'D13',

        'requirementsForInterest'   => 'D14',

        'otherAssets'               => 'D15',

        'totalAssets'               => 'D16',



        // Liabilities

        'loansOfTheCentralBank'                 => 'D18',

        'fundsOfCreditInstitutions'             => 'D19',

        'fundsOfClientsNonCreditOrganizations'  => 'D20',

        'depositsOfIndividuals'                 => 'D21',

        'debtObligationsIssued'                 => 'D22',

        'iterestPaymentOobligations'            => 'D23',

        'otherLiabilities'                      => 'D24',

        'provisionsForPpossibleLosses'          => 'D25',

        'totalObligations'                      => 'D26',



        // Sources of own funds

        'fundsOfShareholders'                  => 'D28',

        'sharesRepurchasedFromShareholders'    => 'D29',

        'seigniorage'                          => 'D30',

        'revaluationOfFixedAssets'             => 'D31',

        'deferredExpenses'                     => 'D32',

        'unusedProfitsOrOutstandingLossesOfPreviousYears' => 'D33',

        'profitOrLossForTheReportingPeriod'    => 'D34',

        'totalSourcesOfOwnFunds'               => 'D35',

        'totalLiabilities'                     => 'D36',



        // Off-balance sheet liabilities

        'irrevocableObligations' => 'D38',

        'guaranteesByBank' => 'D39',



    ];



Для текущего периода:



<?php



    return [



        // metadata

        'reportDate'  => 'A1',

        'bankName'    => 'C2',

        'postAddress' => 'A3',



        // Cells

        'moneyAssets'               => 'E8',

        'fundsInTheCentralBank'     => 'E9',

        'mandatoryReserves'         => 'E10',

        'fundsInCreditInstitutions' => 'E11',

        'loanDebt'                  => 'E12',

        'fixedAssets'               => 'E13',

        'requirementsForInterest'   => 'E14',

        'otherAssets'               => 'E15',

        'totalAssets'               => 'E16',



        // Liabilities

        'loansOfTheCentralBank'                 => 'E18',

        'fundsOfCreditInstitutions'             => 'E19',

        'fundsOfClientsNonCreditOrganizations'  => 'E20',

        'depositsOfIndividuals'                 => 'E21',

        'debtObligationsIssued'                 => 'E22',

        'iterestPaymentOobligations'            => 'E23',

        'otherLiabilities'                      => 'E24',

        'provisionsForPpossibleLosses'          => 'E25',

        'totalObligations'                      => 'E26',



        // Sources of own funds

        'fundsOfShareholders'                  => 'E28',

        'sharesRepurchasedFromShareholders'    => 'E29',

        'seigniorage'                          => 'E30',

        'revaluationOfFixedAssets'             => 'E31',

        'deferredExpenses'                     => 'E32',

        'unusedProfitsOrOutstandingLossesOfPreviousYears' => 'E33',

        'profitOrLossForTheReportingPeriod'    => 'E34',

        'totalSourcesOfOwnFunds'               => 'E35',

        'totalLiabilities'                     => 'E36',



        // Off-balance sheet liabilities

        'irrevocableObligations' => 'E38',

        'guaranteesByBank' => 'E39',



    ];





Обратите внимание, что значения E8, E9, E10 и т.д. — жестко заданные названия ячеек в которых лежат данные. Т.е. предполагается, что нужные значения будут лежать именно в этих ячейках, если нет, то вместо значения Вы получите null. Таким образом, структура разбираемого Excel-файла жестко задана.

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



<?php



    require __DIR__ . '/../vendor/autoload.php';



    // подключаем классы

    use SampleAppBanksReportingBalanceSheet;

    use PhpOfficePhpSpreadsheetReaderXlsx;

    use PhpOfficePhpSpreadsheetWorksheetWorksheet;

    use PhpOfficePhpSpreadsheetRichTextRichText;





    // получаем ссылки на ячейки листа

    function getCells(Worksheet $sheet)

    {

        return function(string $cellName) use ($sheet) {



            // получаем значение ячейки

            $cellValue = $sheet->getCell($cellName)->getValue();



            // если значение ячейки является объектом

            if ( $cellValue instanceof RichText ) {



                $richTextElements = $cellValue->getRichTextElements();

                $outputValue = '';



                // пробегаемся по всем элементам

                foreach($richTextElements as $richTextElement)

                {

                    // и объединяем их в одну строку

                    $outputValue .= trim($richTextElement->getText()) . ' ';

                }



                return $outputValue;

            }  



            return $cellValue;

        };

    }





    // конвертируем значения листа в нужный нам объекта

    function createBalanceFromSheet(Worksheet $sheet, array $period)

    {

        $cells = getCells($sheet);



        $balance = new BalanceSheet();

        // с помощью рефлексии

        $refClass = new ReflectionClass(BalanceSheet::class);

        // получаем все поля объекта

        $properties = $refClass->getProperties();



        // проходимся по каждому полю

        foreach($properties as $property) 

        {

            // смотрим, что это за поле

            switch($property->name)

            {

                // если дата

                case 'reportDate':

                    // получаем значение из Excel-файла, которое находится в ячейке возвращаемой из массива $period['reportDate']

                    // в данном случае такова специфика файла, что нужно вырезать часть строки

                    // полученное значение назначаем свойству класса

                    $balance->{$property->name} = trim(substr($cells($period['reportDate']), -12));    

                    break;



                case 'bankName':

                    $balance->{$property->name} = $cells($period['bankName']);    

                    break;



                case 'postAddress':

                    $balance->{$property->name} = trim(substr($cells($period['postAddress']), 32));

                    break;



                default:

                    $balance->{$property->name} = $cells($period[$property->name]);    

            };    

        }



        // возвращаем объект 

        return $balance;

    }





    // открываем первый лист Excel-файла

    $reader = new Xlsx();

    $spreadsheet = $reader->load('./files/report_01102021.xlsx');

    $sheet = $spreadsheet->getSheet(0);



    // массивы с адресами ячеек, где лежат данные

    $currentPeriod = require('currentPeriodMapper.php');

    $previousPeriod = require('previousPeriodMapper.php');



    // создаем объекты из листа отдельно для каждого периода

    // на этом этапе Вы уже может сохранить эти данные в базу например,

    // или провести какие либо с ними вычисления

    $currentBalance = createBalanceFromSheet($sheet, $currentPeriod);

    $previousBalance = createBalanceFromSheet($sheet, $previousPeriod);



    // преобразуем это все в JSON для отладки

    $json_c = json_encode($currentBalance, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

    $json_p = json_encode($previousBalance, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);



    // выводим в консоль

    print($json_c);

    print($json_p);



Таким образом в данной статье мы рассмотрели пример, то как можно вытащить данные из какого-либо отчета на PHP в структурированном виде. Что делать с этими данными дальше — зависит от Ваших задач. По ним например, можно сделать аналитику, загрузить в базу и т.д.

Источник

НЕТ КОММЕНТАРИЕВ

Оставить комментарий