├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE.txt
├── README.md
├── composer.json
├── phpunit.xml.dist
├── spec
└── Akeneo
│ └── Component
│ └── SpreadsheetParser
│ ├── Csv
│ ├── RowIteratorFactorySpec.php
│ ├── RowIteratorSpec.php
│ ├── SpreadsheetLoaderSpec.php
│ ├── SpreadsheetSpec.php
│ └── fixtures
│ │ ├── iso-8859-15.csv
│ │ ├── test.csv
│ │ └── with_options.csv
│ ├── SpreadsheetLoaderSpec.php
│ └── Xlsx
│ ├── ArchiveLoaderSpec.php
│ ├── ArchiveSpec.php
│ ├── ColumnIndexTransformerSpec.php
│ ├── DateTransformerSpec.php
│ ├── RelationshipsLoaderSpec.php
│ ├── RelationshipsSpec.php
│ ├── RowBuilderFactorySpec.php
│ ├── RowBuilderSpec.php
│ ├── RowIteratorFactorySpec.php
│ ├── RowIteratorSpec.php
│ ├── SharedStringsLoaderSpec.php
│ ├── SharedStringsSpec.php
│ ├── SpreadsheetLoaderSpec.php
│ ├── SpreadsheetSpec.php
│ ├── StylesLoaderSpec.php
│ ├── StylesSpec.php
│ ├── ValueTransformerFactorySpec.php
│ ├── ValueTransformerSpec.php
│ ├── WorksheetListReaderSpec.php
│ └── fixtures
│ ├── sharedStrings.xml
│ ├── sheet.xml
│ ├── styles.xml
│ ├── test.zip
│ ├── workbook.xml
│ └── workbook.xml.rels
├── src
├── Csv
│ ├── CsvParser.php
│ ├── RowIterator.php
│ ├── RowIteratorFactory.php
│ ├── Spreadsheet.php
│ └── SpreadsheetLoader.php
├── SpreadsheetInterface.php
├── SpreadsheetLoader.php
├── SpreadsheetLoaderInterface.php
├── SpreadsheetParser.php
└── Xlsx
│ ├── AbstractXMLDictionnary.php
│ ├── AbstractXMLResource.php
│ ├── Archive.php
│ ├── ArchiveLoader.php
│ ├── ColumnIndexTransformer.php
│ ├── DateTransformer.php
│ ├── Relationships.php
│ ├── RelationshipsLoader.php
│ ├── RowBuilder.php
│ ├── RowBuilderFactory.php
│ ├── RowIterator.php
│ ├── RowIteratorFactory.php
│ ├── SharedStrings.php
│ ├── SharedStringsLoader.php
│ ├── Spreadsheet.php
│ ├── SpreadsheetLoader.php
│ ├── Styles.php
│ ├── StylesLoader.php
│ ├── ValueTransformer.php
│ ├── ValueTransformerFactory.php
│ ├── WorksheetListReader.php
│ └── XlsxParser.php
└── tests
├── CsvTest.php
├── XlsxTest.php
└── fixtures
├── libreoffice.xlsx
├── msoffice.xlsm
├── msoffice.xlsx
├── test.csv
└── test.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | vendor
3 | composer.lock
4 | phpunit.xml
5 | ~$*.xlsx
6 | /nbproject
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | sudo: false
4 |
5 | cache:
6 | directories:
7 | - $HOME/.composer/cache/files
8 |
9 | php:
10 | - 5.4
11 | - 5.5
12 | - 5.6
13 | - 7.0
14 | - 7.1
15 | - 7.2
16 | - 7.3
17 |
18 | env:
19 | - COMPOSER_FLAGS='--prefer-dist'
20 |
21 | matrix:
22 | fast_finish: true
23 | include:
24 | - php: 5.4
25 | env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable' SYMFONY_DEPRECATIONS_HELPER=weak
26 | - php: 5.6
27 | env: COMPOSER_FLAGS='--prefer-dist' DEPENDENCIES=dev
28 |
29 | before_install:
30 | - if [ "$TRAVIS_PHP_VERSION" != "7.3" ]; then phpenv config-rm xdebug.ini; fi
31 | - composer self-update
32 | - if [ "$DEPENDENCIES" = "dev" ]; then composer config minimum-stability dev; fi;
33 |
34 | install:
35 | - composer update $COMPOSER_FLAGS
36 | - bin/simple-phpunit install
37 |
38 | script:
39 | - bin/phpspec run -f dot
40 | - bin/simple-phpunit -v
41 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CHANGELOG
2 |
3 | ## 1.2.0 (2016-03-25)
4 | - Use maintained versions of the symfony component
5 |
6 | ## 1.1.7 (2015-10-05)
7 | - Migrate to AkeneoLabs
8 |
9 | ## 1.1.6 (2015-08-12)
10 | - Compatible with Akeneo 1.4
11 |
12 | ## 1.1.5 (2014-09-02)
13 | ### Bug fixes
14 | - set default system encoding to UTF8
15 |
16 | ## 1.1.4 (2014-08-08)
17 | ## Improvements
18 | - Skip converting when reading CSV if source encoding is the same as target encoding
19 |
20 | ## 1.1.3 (2014-06-25)
21 | ### Bug fixes
22 | - Fixed non-static method error in XlsxParser (Github issue #6)
23 |
24 | ## 1.1.2 (2014-06-18)
25 | ### Bug fixes
26 | - first row index of CSV is 1 except of 0
27 |
28 | ## 1.1.1 (2014-06-15)
29 | ### Enhancements
30 | - XLSM extension support
31 |
32 | ## 1.1.0 (2014-06-09)
33 | ### Features
34 | - CSV support
35 |
36 | ### BC Breaks
37 | - WorkbookInterface is now SpreasheetInterface
38 | - WorkbookLoaderInterface is now SpreadsheetLoaderInterface
39 |
40 | ## 1.0.0 (2014-05-24)
41 | - Initial release
42 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Akeneo PIM
2 |
3 | The Open Software License version 3.0
4 |
5 | Copyright (c) 2014, Akeneo SAS.
6 |
7 | Full license is at: http://opensource.org/licenses/OSL-3.0
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Akeneo Spreadsheet Parser
2 | =========================
3 |
4 | This component is designed to extract data from spreadsheets, while being easy on resources, even for large files.
5 |
6 | The current version of the spreadsheet parser works with csv and xlsx files.
7 |
8 | [](https://travis-ci.org/akeneo-labs/spreadsheet-parser)
9 | [](https://scrutinizer-ci.com/g/akeneo-labs/spreadsheet-parser/?branch=master)
10 |
11 | Installing the package
12 | ----------------------
13 |
14 | From your application root:
15 |
16 | ```bash
17 | $ php composer.phar require --prefer-dist "akeneo-labs/spreadsheet-parser"
18 | ```
19 |
20 | Usage
21 | -----
22 |
23 | To extract data from an XLSX spreadsheet, use the following code:
24 |
25 | ```php
26 | use Akeneo\Component\SpreadsheetParser\SpreadsheetParser;
27 |
28 | $workbook = SpreadsheetParser::open('myfile.xlsx');
29 |
30 | $myWorksheetIndex = $workbook->getWorksheetIndex('myworksheet');
31 |
32 | foreach ($workbook->createRowIterator($myWorksheetIndex) as $rowIndex => $values) {
33 | var_dump($rowIndex, $values);
34 | }
35 | ```
36 |
37 | By using the CSV parser options, you can specify the format of your CSV file :
38 |
39 | ```php
40 | use Akeneo\Component\SpreadsheetParser\SpreadsheetParser;
41 |
42 | $workbook = SpreadsheetParser::open('myfile.csv');
43 |
44 | $iterator = $workbook->createRowIterator(
45 | 0,
46 | [
47 | 'encoding' => 'UTF-8',
48 | 'length' => null,
49 | 'delimiter' => ',',
50 | 'enclosure' => '"',
51 | 'escape' => '\\'
52 | ]
53 | );
54 |
55 |
56 | foreach ($workbook->createRowIterator(0) as $rowIndex => $values) {
57 | var_dump($rowIndex, $values);
58 | }
59 | ```
60 |
61 | Running the tests
62 | -----------------
63 |
64 | To run unit tests, use phpspec:
65 |
66 | ```bash
67 | $ php bin/phpspec run
68 | ```
69 |
70 | To run integration tests, use phpunit:
71 |
72 | ```bash
73 | $ phpunit
74 | ```
75 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "akeneo-labs/spreadsheet-parser",
3 | "description": "Akeneo Spreadsheet parser. Reads XLXS files from Microsoft Excel and Open Office",
4 | "keywords": ["akeneo", "excel", "xlsx", "reader", "parser", "spreadsheet"],
5 | "homepage": "http://akeneo.com",
6 | "license": "OSL-3.0",
7 | "authors": [
8 | {
9 | "name": "Antoine Guigan",
10 | "email": "antoine@akeneo.com",
11 | "homepage": "http://akeneo.com"
12 | },
13 | {
14 | "name": "Matthieu Viel",
15 | "email": "matthieu.viel@akeneo.com",
16 | "homepage": "http://akeneo.com"
17 | },
18 | {
19 | "name": "JM Leroux",
20 | "email": "jean-marie.leroux@akeneo.com"
21 | }
22 | ],
23 | "require": {
24 | "php": ">=5.4.0",
25 | "symfony/options-resolver": "~2.6 || ~3.0 || ^4.0"
26 | },
27 | "require-dev": {
28 | "phpspec/phpspec": "~2.0",
29 | "symfony/phpunit-bridge": "^4.2"
30 | },
31 | "autoload": {
32 | "psr-4": {
33 | "Akeneo\\Component\\SpreadsheetParser\\": "src"
34 | }
35 | },
36 | "extra": {
37 | "branch-alias": {
38 | "dev-master": "1.2.x-dev"
39 | }
40 | },
41 | "config": {
42 | "bin-dir": "bin"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
16 |
17 | ./tests
18 |
19 |
20 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Csv/RowIteratorFactorySpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith('spec\Akeneo\Component\SpreadsheetParser\Csv\StubRowIterator');
12 | }
13 |
14 | public function it_is_initializable()
15 | {
16 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Csv\RowIteratorFactory');
17 | }
18 |
19 | public function it_creates_row_iterators()
20 | {
21 | $iterator = $this->create('path', ['options']);
22 | $iterator->getPath()->shouldReturn('path');
23 | $iterator->getOptions()->shouldReturn(['options']);
24 | }
25 | }
26 |
27 | class StubRowIterator
28 | {
29 | protected $path;
30 | protected $options;
31 |
32 | public function __construct($path, $options)
33 | {
34 | $this->path = $path;
35 | $this->options = $options;
36 | }
37 |
38 | public function getOptions()
39 | {
40 | return $this->options;
41 | }
42 |
43 | public function getPath()
44 | {
45 | return $this->path;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Csv/RowIteratorSpec.php:
--------------------------------------------------------------------------------
1 | ['value', 'enclosed value', '15'],
11 | 2 => ['', 'value2', ''],
12 | 3 => ['é', 'è', '€']
13 | ];
14 |
15 | public function it_is_initializable()
16 | {
17 | $this->beConstructedWith('path', []);
18 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Csv\RowIterator');
19 | }
20 |
21 | public function it_parses_csv_files()
22 | {
23 | $this->beConstructedWith(__DIR__ . '/fixtures/test.csv', []);
24 | $this->rewind();
25 | foreach ($this->values as $i => $row) {
26 | $this->key()->shouldReturn($i);
27 | $this->valid()->shouldReturn(true);
28 | $this->current()->shouldReturn($row);
29 | $this->next();
30 | }
31 | $this->valid()->shouldReturn(false);
32 | }
33 |
34 | public function it_can_be_rewinded()
35 | {
36 | $this->beConstructedWith(__DIR__ . '/fixtures/test.csv', []);
37 | $this->rewind();
38 | $this->current()->shouldReturn($this->values[1]);
39 | $this->next();
40 | $this->rewind();
41 | $this->current()->shouldReturn($this->values[1]);
42 | }
43 |
44 | public function it_accepts_options()
45 | {
46 | $this->beConstructedWith(
47 | __DIR__ . '/fixtures/with_options.csv',
48 | [
49 | 'delimiter' => '|',
50 | 'enclosure' => "@"
51 | ]
52 | );
53 | $this->rewind();
54 | foreach ($this->values as $i => $row) {
55 | $this->key()->shouldReturn($i);
56 | $this->valid()->shouldReturn(true);
57 | $this->current()->shouldReturn($row);
58 | $this->next();
59 | }
60 | $this->valid()->shouldReturn(false);
61 | }
62 |
63 | public function it_converts_between_encodings()
64 | {
65 | $this->beConstructedWith(
66 | __DIR__ . '/fixtures/iso-8859-15.csv',
67 | [
68 | 'encoding' => 'iso-8859-15'
69 | ]
70 | );
71 | $values = [1 => ['é', 'è', '€']];
72 | $this->rewind();
73 | foreach ($values as $i => $row) {
74 | $this->key()->shouldReturn($i);
75 | $this->valid()->shouldReturn(true);
76 | $this->current()->shouldReturn($row);
77 | $this->next();
78 | }
79 | $this->valid()->shouldReturn(false);
80 | }
81 |
82 | public function it_skips_converting_when_not_necessary()
83 | {
84 | $this->beConstructedWith(
85 | __DIR__ . '/fixtures/with_options.csv',
86 | [
87 | 'delimiter' => '|',
88 | 'enclosure' => "@",
89 | 'encoding' => 'UTF8'
90 | ]
91 | );
92 | $this->rewind();
93 | foreach ($this->values as $i => $row) {
94 | $this->key()->shouldReturn($i);
95 | $this->valid()->shouldReturn(true);
96 | $this->current()->shouldReturn($row);
97 | $this->next();
98 | }
99 | $this->valid()->shouldReturn(false);
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Csv/SpreadsheetLoaderSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith(
13 | $rowIteratorFactory,
14 | 'spec\Akeneo\Component\SpreadsheetParser\Csv\StubSpreadsheet',
15 | 'sheet'
16 | );
17 | }
18 |
19 | public function it_is_initializable()
20 | {
21 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Csv\SpreadsheetLoader');
22 | }
23 |
24 | public function it_creates_spreadsheet_objects(RowIteratorFactory $rowIteratorFactory)
25 | {
26 | $spreadsheet = $this->open('path');
27 | $spreadsheet->getPath()->shouldReturn('path');
28 | $spreadsheet->getSheetName()->shouldReturn('sheet');
29 | $spreadsheet->getRowIteratorFactory()->shouldReturn($rowIteratorFactory);
30 | }
31 | }
32 |
33 | class StubSpreadsheet
34 | {
35 | protected $rowIteratorFactory;
36 | protected $sheetName;
37 | protected $path;
38 |
39 | public function __construct($rowIteratorFactory, $sheetName, $path)
40 | {
41 | $this->rowIteratorFactory = $rowIteratorFactory;
42 | $this->sheetName = $sheetName;
43 | $this->path = $path;
44 | }
45 |
46 | public function getRowIteratorFactory()
47 | {
48 | return $this->rowIteratorFactory;
49 | }
50 |
51 | public function getSheetName()
52 | {
53 | return $this->sheetName;
54 | }
55 |
56 | public function getPath()
57 | {
58 | return $this->path;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Csv/SpreadsheetSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($rowIteratorFactory, 'sheet', 'path');
14 | }
15 |
16 | public function it_is_initializable()
17 | {
18 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Csv\Spreadsheet');
19 | }
20 |
21 | public function it_returns_the_worksheet_list()
22 | {
23 | $this->getWorksheets()->shouldReturn(['sheet']);
24 | }
25 |
26 | public function it_creates_row_iterators(
27 | RowIteratorFactory $rowIteratorFactory,
28 | RowIterator $rowIterator1,
29 | RowIterator $rowIterator2
30 | ) {
31 | $rowIteratorFactory->create('path', ['options1'])->willReturn($rowIterator1);
32 | $rowIteratorFactory->create('path', ['options2'])->willReturn($rowIterator2);
33 |
34 | $this->createRowIterator(0, ['options1'])->shouldReturn($rowIterator1);
35 | $this->createRowIterator(1, ['options2'])->shouldReturn($rowIterator2);
36 | }
37 |
38 | public function it_finds_a_worksheet_index_by_name()
39 | {
40 | $this->getWorksheetIndex('sheet')->shouldReturn(0);
41 | }
42 |
43 | public function it_returns_false_if_a_worksheet_does_not_exist()
44 | {
45 | $this->getWorksheetIndex('sheet3')->shouldReturn(false);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Csv/fixtures/iso-8859-15.csv:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akeneo-labs/spreadsheet-parser/4be5fdae57363819dcd80e84ae875c6402213b1b/spec/Akeneo/Component/SpreadsheetParser/Csv/fixtures/iso-8859-15.csv
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Csv/fixtures/test.csv:
--------------------------------------------------------------------------------
1 | value,"enclosed value",15
2 | ,value2,
3 | é,è,€
4 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Csv/fixtures/with_options.csv:
--------------------------------------------------------------------------------
1 | value|@enclosed value@|15
2 | |value2|
3 | é|è|€
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/SpreadsheetLoaderSpec.php:
--------------------------------------------------------------------------------
1 | addLoader('extension', $loader)->addLoader('other_extension', $otherLoader);
18 | $loader->open('file.extension')->willReturn($spreadsheet);
19 | }
20 |
21 | public function it_is_initializable()
22 | {
23 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\SpreadsheetLoader');
24 | }
25 |
26 | public function it_uses_the_loader_corresponding_to_the_file_extension(
27 | SpreadsheetInterface $spreadsheet
28 | )
29 | {
30 | $this->open('file.extension')->shouldReturn($spreadsheet);
31 | }
32 |
33 | public function it_throws_an_exception_if_no_loader_is_available()
34 | {
35 | $this->shouldThrow('\InvalidArgumentException')->duringOpen('file');
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/ArchiveLoaderSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith('spec\Akeneo\Component\SpreadsheetParser\Xlsx\StubArchive');
12 | }
13 |
14 | public function it_is_initializable()
15 | {
16 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\ArchiveLoader');
17 | }
18 |
19 | public function it_loads_files()
20 | {
21 | $this->open('path')->getPath()->shouldReturn('path');
22 | }
23 | }
24 |
25 | class StubArchive
26 | {
27 | protected $path;
28 |
29 | public function __construct($path)
30 | {
31 | $this->path = $path;
32 | }
33 |
34 | public function getPath()
35 | {
36 | return $this->path;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/ArchiveSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith(__DIR__ . '/fixtures/test.zip');
12 | }
13 |
14 | public function it_is_initializable()
15 | {
16 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\Archive');
17 | }
18 |
19 | public function it_extracts_files()
20 | {
21 | $this->extract('file1')->shouldHaveFileContent("file1\n");
22 | }
23 |
24 | public function it_extracts_files_from_subfolders()
25 | {
26 | $this->extract('folder/file2')->shouldHaveFileContent("file2\n");
27 | }
28 |
29 | public function it_extracts_files_once()
30 | {
31 | $file = $this->extract('file1');
32 | $file->shouldHaveFileContent("file1\n");
33 | file_put_contents($file->getWrappedObject(), 'content');
34 | $this->extract('file1')->shouldHaveFileContent('content');
35 | }
36 |
37 | public function getMatchers()
38 | {
39 | return [
40 | 'haveFileContent' => function ($filepath, $content) {
41 | return $content === file_get_contents($filepath);
42 | }
43 | ];
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/ColumnIndexTransformerSpec.php:
--------------------------------------------------------------------------------
1 | shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\ColumnIndexTransformer');
12 | }
13 |
14 | public function it_transforms_single_letter_cell_names()
15 | {
16 | $this->transform('A1')->shouldReturn(0);
17 | $this->transform('D360')->shouldReturn(3);
18 | $this->transform('F2')->shouldReturn(5);
19 | }
20 |
21 | public function it_transforms_multiple_letter_cell_names()
22 | {
23 | $this->transform('AF1')->shouldReturn(31);
24 | $this->transform('BC11')->shouldReturn(54);
25 | $this->transform('AAN125')->shouldReturn(715);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/DateTransformerSpec.php:
--------------------------------------------------------------------------------
1 | shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\DateTransformer');
12 | }
13 |
14 | public function it_transforms_dates()
15 | {
16 | $this->transform('42001')->shouldReturnDate('2014-12-28 00:00');
17 | $this->transform('16.9473958333333')->shouldReturnDate('1900-01-15 22:44');
18 | $this->transform('37027.1041666667')->shouldReturnDate('2001-05-16 02:30');
19 | }
20 |
21 | public function getMatchers()
22 | {
23 | return [
24 | 'returnDate' => function ($date, $expected) {
25 | return $expected === $date->format('Y-m-d H:i');
26 | }
27 | ];
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/RelationshipsLoaderSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith('spec\Akeneo\Component\SpreadsheetParser\Xlsx\StubRelationships');
12 | }
13 |
14 | public function it_is_initializable()
15 | {
16 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\RelationshipsLoader');
17 | }
18 |
19 | public function it_loads_relationships()
20 | {
21 | $this->open('path')->getPath()->shouldReturn('path');
22 | }
23 | }
24 |
25 | class StubRelationships
26 | {
27 | protected $path;
28 |
29 | public function __construct($path)
30 | {
31 | $this->path = $path;
32 | }
33 |
34 | public function getPath()
35 | {
36 | return $this->path;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/RelationshipsSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith(__DIR__ . '/fixtures/workbook.xml.rels');
12 | }
13 |
14 | public function it_is_initializable()
15 | {
16 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\Relationships');
17 | }
18 |
19 | public function it_returns_worksheet_paths()
20 | {
21 | $this->getWorksheetPath('rId2')->shouldReturn('xl/worksheets/sheet1.xml');
22 | $this->getWorksheetPath('rId3')->shouldReturn('xl/worksheets/sheet2.xml');
23 | $this->getWorksheetPath('rId4')->shouldReturn('xl/worksheets/sheet3.xml');
24 | }
25 |
26 | public function it_returns_shared_strings_path()
27 | {
28 | $this->getSharedStringsPath()->shouldReturn('xl/sharedStrings.xml');
29 | }
30 |
31 | public function it_returns_styles_path()
32 | {
33 | $this->getStylesPath()->shouldReturn('xl/styles.xml');
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/RowBuilderFactorySpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith('spec\Akeneo\Component\SpreadsheetParser\Xlsx\StubRowBuilder');
13 | }
14 |
15 | public function it_is_initializable()
16 | {
17 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\RowBuilderFactory');
18 | }
19 |
20 | public function it_creates_row_builders()
21 | {
22 | $this->create()->shouldHaveType('spec\Akeneo\Component\SpreadsheetParser\Xlsx\StubRowBuilder');
23 | }
24 | }
25 |
26 | class StubRowBuilder
27 | {
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/RowBuilderSpec.php:
--------------------------------------------------------------------------------
1 | shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\RowBuilder');
12 | }
13 |
14 | public function it_builds_simple_rows()
15 | {
16 | $this->addValue(0, '0');
17 | $this->addValue(1, '1');
18 | $this->addValue(2, '2');
19 | $this->getData()->shouldReturn(['0', '1', '2']);
20 | }
21 |
22 | public function it_adds_missing_values()
23 | {
24 | $this->addValue(2, '2');
25 | $this->addValue(6, '6');
26 | $this->addValue(7, '7');
27 | $this->getData()->shouldReturn(['', '', '2', '', '', '', '6', '7']);
28 | }
29 |
30 | public function it_right_trims_empty_values()
31 | {
32 | $this->addValue(2, '2');
33 | $this->addValue(3, '');
34 | $this->addValue(4, '');
35 | $this->getData()->shouldReturn(['', '', '2']);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/RowIteratorFactorySpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith(
16 | $rowBuilderFactory,
17 | $columnIndexTransformer,
18 | 'spec\Akeneo\Component\SpreadsheetParser\Xlsx\StubRowIterator'
19 | );
20 | }
21 |
22 | public function it_is_initializable()
23 | {
24 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\RowIteratorFactory');
25 | }
26 |
27 | public function it_creates_row_iterators(
28 | RowBuilderFactory $rowBuilderFactory,
29 | ColumnIndexTransformer $columnIndexTransformer,
30 | ValueTransformer $valueTransformer,
31 | Archive $archive
32 | ) {
33 | $iterator = $this->create($valueTransformer, 'path', ['options'], $archive);
34 | $iterator->getPath()->shouldReturn('path');
35 | $iterator->getOptions()->shouldReturn(['options']);
36 | $iterator->getValueTransformer()->shouldReturn($valueTransformer);
37 | $iterator->getRowBuilderFactory()->shouldReturn($rowBuilderFactory);
38 | $iterator->getColumnIndexTransformer()->shouldReturn($columnIndexTransformer);
39 | }
40 | }
41 |
42 | class StubRowIterator
43 | {
44 | protected $rowBuilderFactory;
45 | protected $columnIndexTransformer;
46 | protected $valueTransformer;
47 | protected $path;
48 | protected $options;
49 |
50 | public function __construct($rowBuilderFactory, $columnIndexTransformer, $valueTransformer, $path, $options)
51 | {
52 | $this->rowBuilderFactory = $rowBuilderFactory;
53 | $this->columnIndexTransformer = $columnIndexTransformer;
54 | $this->valueTransformer = $valueTransformer;
55 | $this->path = $path;
56 | $this->options = $options;
57 | }
58 |
59 | public function getPath()
60 | {
61 | return $this->path;
62 | }
63 |
64 | public function getValueTransformer()
65 | {
66 | return $this->valueTransformer;
67 | }
68 |
69 | public function getRowBuilderFactory()
70 | {
71 | return $this->rowBuilderFactory;
72 | }
73 |
74 | public function getColumnIndexTransformer()
75 | {
76 | return $this->columnIndexTransformer;
77 | }
78 |
79 | public function getOptions()
80 | {
81 | return $this->options;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/RowIteratorSpec.php:
--------------------------------------------------------------------------------
1 | transform(Argument::that($startWith('A')))->willReturn(0);
29 | $columnIndexTransformer->transform(Argument::that($startWith('B')))->willReturn(1);
30 | $columnIndexTransformer->transform(Argument::that($startWith('C')))->willReturn(2);
31 | $columnIndexTransformer->transform(Argument::that($startWith('D')))->willReturn(3);
32 |
33 | $row = null;
34 | $rowBuilderFactory->create()->will(
35 | function () use ($rowBuilder, &$row) {
36 | $row = [];
37 |
38 | return $rowBuilder;
39 | }
40 | );
41 |
42 | $rowBuilder->addValue(Argument::type('int'), Argument::type('array'))->will(
43 | function ($args) use (&$row) {
44 | $row[$args[0]] = $args[1];
45 | }
46 | );
47 | $rowBuilder->getData()->will(
48 | function () use (&$row) {
49 | return $row;
50 | }
51 | );
52 | $this->beConstructedWith(
53 | $rowBuilderFactory,
54 | $columnIndexTransformer,
55 | $valueTransformer,
56 | __DIR__ . '/fixtures/sheet.xml',
57 | [],
58 | $archive
59 | );
60 | $valueTransformer->transform(Argument::type('string'), Argument::type('string'), Argument::type('string'))
61 | ->will(
62 | function ($args) {
63 | return $args;
64 | }
65 | );
66 | }
67 |
68 | public function it_is_initializable()
69 | {
70 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\RowIterator');
71 | }
72 |
73 | public function it_iterates_through_rows()
74 | {
75 | $values = [
76 | 1 => [0 => ['0', 's', '0'], 1 => ['1', 's', '0'], 3 => ['', '', '1']],
77 | 2 => [0 => ['2', 's', '0'], 1 => ['3', 's', '0'], 2 => ['4', 's', '0']],
78 | 4 => [0 => ['5', 'n', '0'], 2 => ['6', 'n', '1']],
79 | ];
80 |
81 | $this->rewind();
82 | foreach ($values as $key => $row) {
83 | $this->valid()->shouldReturn(true);
84 | $this->current()->shouldReturn($row);
85 | $this->key()->shouldReturn($key);
86 | $this->next();
87 | }
88 |
89 | $this->valid()->shouldReturn(false);
90 | }
91 |
92 | public function it_can_be_rewinded()
93 | {
94 | $this->rewind();
95 | $this->valid()->shouldReturn(true);
96 | $this->current()->shouldReturn([0 => ['0', 's', '0'], 1 => ['1', 's', '0'], 3 => ['', '', '1']]);
97 | $this->key()->shouldReturn(1);
98 | $this->next();
99 | $this->rewind();
100 | $this->valid()->shouldReturn(true);
101 | $this->current()->shouldReturn([0 => ['0', 's', '0'], 1 => ['1', 's', '0'], 3 => ['', '', '1']]);
102 | $this->key()->shouldReturn(1);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/SharedStringsLoaderSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith('spec\Akeneo\Component\SpreadsheetParser\Xlsx\StubSharedStrings');
13 | }
14 |
15 | public function it_is_initializable()
16 | {
17 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\SharedStringsLoader');
18 | }
19 |
20 | public function it_loads_shared_strings(Archive $archive)
21 | {
22 | $sharedStrings = $this->open('path', $archive);
23 | $sharedStrings->getPath()->shouldReturn('path');
24 | $sharedStrings->getArchive()->shouldReturn($archive);
25 | }
26 | }
27 |
28 | class StubSharedStrings
29 | {
30 | protected $path;
31 | private $archive;
32 |
33 | public function __construct($path, Archive $archive)
34 | {
35 | $this->path = $path;
36 | $this->archive = $archive;
37 | }
38 |
39 | public function getPath()
40 | {
41 | return $this->path;
42 | }
43 |
44 | public function getArchive()
45 | {
46 | return $this->archive;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/SharedStringsSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith(__DIR__ . '/fixtures/sharedStrings.xml');
12 | }
13 |
14 | public function it_is_initializable()
15 | {
16 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\SharedStrings');
17 | }
18 |
19 | public function it_returns_shared_strings()
20 | {
21 | $this->get(0)->shouldReturn('value1');
22 | $this->get(2)->shouldReturn(' ');
23 | $this->get(4)->shouldReturn('value3');
24 | $this->get(5)->shouldReturn('value4');
25 | }
26 |
27 | public function it_throws_an_exception_if_there_is_no_string()
28 | {
29 | $this->shouldThrow('\InvalidArgumentException')->duringGet(10);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/SpreadsheetLoaderSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith(
27 | $archiveLoader,
28 | $relationshipsLoader,
29 | $sharedStringsLoader,
30 | $stylesLoader,
31 | $worksheetListReader,
32 | $valueTransformerFactory,
33 | $rowIteratorFactory,
34 | 'spec\Akeneo\Component\SpreadsheetParser\Xlsx\StubSpreadsheet'
35 | );
36 | }
37 |
38 | public function it_is_initializable()
39 | {
40 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\SpreadsheetLoader');
41 | }
42 |
43 | public function it_creates_spreadsheet_objects(
44 | RelationshipsLoader $relationshipsLoader,
45 | SharedStringsLoader $sharedStringsLoader,
46 | StylesLoader $stylesLoader,
47 | WorksheetListReader $worksheetListReader,
48 | ValueTransformerFactory $valueTransformerFactory,
49 | RowIteratorFactory $rowIteratorFactory,
50 | ArchiveLoader $archiveLoader,
51 | Archive $archive
52 | ) {
53 | $archiveLoader->open('path')->willReturn($archive);
54 |
55 | $spreadsheet = $this->open('path');
56 | $spreadsheet->getArchive()->shouldReturn($archive);
57 | $spreadsheet->getSharedStringsLoader()->shouldReturn($sharedStringsLoader);
58 | $spreadsheet->getStylesLoader()->shouldReturn($stylesLoader);
59 | $spreadsheet->getRowIteratorFactory()->shouldReturn($rowIteratorFactory);
60 | $spreadsheet->getWorksheetListReader()->shouldReturn($worksheetListReader);
61 | $spreadsheet->getValueTransformerFactory()->shouldReturn($valueTransformerFactory);
62 | $spreadsheet->getRelationshipsLoader()->shouldReturn($relationshipsLoader);
63 | }
64 |
65 | public function it_caches_spreadsheet_objects(
66 | ArchiveLoader $archiveLoader,
67 | Archive $archive
68 | ) {
69 | $archiveLoader->open('path')->shouldBeCalledTimes(1)->willReturn($archive);
70 |
71 | $spreadsheet = $this->open('path');
72 | $spreadsheet->getArchive()->shouldReturn($archive);
73 | }
74 | }
75 |
76 | class StubSpreadsheet
77 | {
78 | protected $sharedStringsLoader;
79 | protected $worksheetListReader;
80 | protected $relationshipsLoader;
81 | protected $stylesLoader;
82 | protected $rowIteratorFactory;
83 | protected $valueTransformerFactory;
84 | protected $archive;
85 |
86 | public function __construct(
87 | Archive $archive,
88 | RelationshipsLoader $relationshipsLoader,
89 | SharedStringsLoader $sharedStringsLoader,
90 | StylesLoader $stylesLoader,
91 | WorksheetListReader $worksheetListReader,
92 | ValueTransformerFactory $valueTransformerFactory,
93 | RowIteratorFactory $rowIteratorFactory
94 | ) {
95 | $this->archive = $archive;
96 | $this->sharedStringsLoader = $sharedStringsLoader;
97 | $this->relationshipsLoader = $relationshipsLoader;
98 | $this->stylesLoader = $stylesLoader;
99 | $this->worksheetListReader = $worksheetListReader;
100 | $this->valueTransformerFactory = $valueTransformerFactory;
101 | $this->rowIteratorFactory = $rowIteratorFactory;
102 | }
103 |
104 | public function getSharedStringsLoader()
105 | {
106 | return $this->sharedStringsLoader;
107 | }
108 |
109 | public function getRowIteratorFactory()
110 | {
111 | return $this->rowIteratorFactory;
112 | }
113 |
114 | public function getArchive()
115 | {
116 | return $this->archive;
117 | }
118 |
119 | public function getWorksheetListReader()
120 | {
121 | return $this->worksheetListReader;
122 | }
123 |
124 | public function getRelationshipsLoader()
125 | {
126 | return $this->relationshipsLoader;
127 | }
128 |
129 | public function getValueTransformerFactory()
130 | {
131 | return $this->valueTransformerFactory;
132 | }
133 |
134 | public function getStylesLoader()
135 | {
136 | return $this->stylesLoader;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/SpreadsheetSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith(
38 | $archive,
39 | $relationshipsLoader,
40 | $sharedStringsLoader,
41 | $stylesLoader,
42 | $worksheetListReader,
43 | $valueTransformerFactory,
44 | $rowIteratorFactory
45 | );
46 | $archive->extract(Argument::type('string'))->will(
47 | function ($args) {
48 | return sprintf('temp_%s', $args[0]);
49 | }
50 | );
51 |
52 | $beCalledAtMostOnce = function ($calls, $object, $method) {
53 | if (count($calls) > 1) {
54 | throw new UnexpectedCallsException(
55 | 'Method should be called at most once',
56 | $method,
57 | $calls
58 | );
59 | }
60 | };
61 | $relationshipsLoader->open('temp_' . Spreadsheet::RELATIONSHIPS_PATH)
62 | ->should($beCalledAtMostOnce)
63 | ->willReturn($relationships);
64 |
65 | $relationships->getSharedStringsPath()->willReturn('shared_strings');
66 | $relationships->getStylesPath()->willReturn('styles');
67 |
68 | $sharedStringsLoader->open('temp_shared_strings', $archive)
69 | ->should($beCalledAtMostOnce)
70 | ->willReturn($sharedStrings);
71 |
72 | $stylesLoader->open(('temp_styles'), $archive)->willReturn($styles);
73 | $valueTransformerFactory->create($sharedStrings, $styles)->willReturn($valueTransformer);
74 |
75 | $worksheetListReader->getWorksheetPaths($relationships, 'temp_' . Spreadsheet::WORKBOOK_PATH)
76 | ->should($beCalledAtMostOnce)
77 | ->willReturn(['sheet1' => 'path1', 'sheet2' => 'path2']);
78 | }
79 |
80 | public function it_is_initializable()
81 | {
82 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\Spreadsheet');
83 | }
84 |
85 | public function it_returns_the_worksheet_list()
86 | {
87 | $this->getWorksheets()->shouldReturn(['sheet1', 'sheet2']);
88 | }
89 |
90 | public function it_creates_row_iterators(
91 | ValueTransformer $valueTransformer,
92 | RowIteratorFactory $rowIteratorFactory,
93 | RowIterator $rowIterator1,
94 | RowIterator $rowIterator2,
95 | Archive $archive
96 | ) {
97 | $rowIteratorFactory->create($valueTransformer, 'temp_path1', [], $archive)->willReturn($rowIterator1);
98 | $rowIteratorFactory->create($valueTransformer, 'temp_path2', [], $archive)->willReturn($rowIterator2);
99 |
100 | $this->createRowIterator(0)->shouldReturn($rowIterator1);
101 | $this->createRowIterator(1)->shouldReturn($rowIterator2);
102 | }
103 |
104 | public function it_finds_a_worksheet_index_by_name()
105 | {
106 | $this->getWorksheetIndex('sheet2')->shouldReturn(1);
107 | }
108 |
109 | public function it_returns_false_if_a_worksheet_does_not_exist()
110 | {
111 | $this->getWorksheetIndex('sheet3')->shouldReturn(false);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/StylesLoaderSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith('spec\Akeneo\Component\SpreadsheetParser\Xlsx\StubStyles');
13 | }
14 |
15 | public function it_is_initializable()
16 | {
17 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\StylesLoader');
18 | }
19 |
20 | public function it_loads_styles(Archive $archive)
21 | {
22 | $styles = $this->open('path', $archive);
23 | $styles->getPath()->shouldReturn('path');
24 | $styles->getArchive()->shouldReturn($archive);
25 | }
26 | }
27 |
28 | class StubStyles
29 | {
30 | protected $path;
31 | private $archive;
32 |
33 | public function __construct($path, Archive $archive)
34 | {
35 | $this->path = $path;
36 | $this->archive = $archive;
37 | }
38 |
39 | public function getPath()
40 | {
41 | return $this->path;
42 | }
43 |
44 | public function getArchive()
45 | {
46 | return $this->archive;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/StylesSpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith(__DIR__ . '/fixtures/styles.xml');
13 | }
14 |
15 | public function it_is_initializable()
16 | {
17 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\Styles');
18 | }
19 |
20 | public function it_returns_shared_strings()
21 | {
22 | $this->get(0)->shouldReturn(Styles::FORMAT_DEFAULT);
23 | $this->get(1)->shouldReturn(Styles::FORMAT_DATE);
24 | $this->get(2)->shouldReturn(Styles::FORMAT_DEFAULT);
25 | $this->get(3)->shouldReturn(Styles::FORMAT_DATE);
26 | $this->get(4)->shouldReturn(Styles::FORMAT_DATE);
27 | }
28 |
29 | public function it_throws_an_exception_if_there_is_no_style()
30 | {
31 | $this->shouldThrow('\InvalidArgumentException')->duringGet('bogus');
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/ValueTransformerFactorySpec.php:
--------------------------------------------------------------------------------
1 | beConstructedWith($dateTransformer, 'spec\Akeneo\Component\SpreadsheetParser\Xlsx\StubValueTransformer');
15 | }
16 |
17 | public function it_is_initializable()
18 | {
19 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\ValueTransformerFactory');
20 | }
21 |
22 | public function it_creates_value_transformers(
23 | DateTransformer $dateTransformer,
24 | SharedStrings $sharedStrings,
25 | Styles $styles
26 | ) {
27 | $transformer = $this->create($sharedStrings, $styles);
28 | $transformer->getSharedStrings()->shouldReturn($sharedStrings);
29 | $transformer->getDateTransformer()->shouldReturn($dateTransformer);
30 | $transformer->getStyles()->shouldReturn($styles);
31 | }
32 | }
33 |
34 | class StubValueTransformer
35 | {
36 | protected $dateTransformer;
37 | protected $sharedStrings;
38 | protected $styles;
39 |
40 | public function __construct($dateTransformer, $sharedStrings, $styles)
41 | {
42 | $this->sharedStrings = $sharedStrings;
43 | $this->dateTransformer = $dateTransformer;
44 | $this->styles = $styles;
45 | }
46 |
47 | public function getSharedStrings()
48 | {
49 | return $this->sharedStrings;
50 | }
51 |
52 | public function getDateTransformer()
53 | {
54 | return $this->dateTransformer;
55 | }
56 |
57 | public function getStyles()
58 | {
59 | return $this->styles;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/ValueTransformerSpec.php:
--------------------------------------------------------------------------------
1 | get('1')->willReturn(Styles::FORMAT_DEFAULT);
20 | $styles->get('2')->willReturn(Styles::FORMAT_DATE);
21 | $dateTransformer->transform(Argument::type('string'))->will(
22 | function ($args) {
23 | return 'date_' . $args[0];
24 | }
25 | );
26 | $sharedStrings->get(Argument::type('string'))->will(
27 | function ($args) {
28 | return 'shared_' . $args[0];
29 | }
30 | );
31 | $this->beConstructedWith($dateTransformer, $sharedStrings, $styles);
32 | }
33 |
34 | public function it_is_initializable()
35 | {
36 | $this->shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\ValueTransformer');
37 | }
38 |
39 | public function it_transforms_shared_strings()
40 | {
41 | $this->transform('1', ValueTransformer::TYPE_SHARED_STRING, '1')->shouldReturn('shared_1');
42 | }
43 |
44 | public function it_transforms_strings()
45 | {
46 | $this->transform('string', ValueTransformer::TYPE_STRING, '1')->shouldReturn('string');
47 | $this->transform('string', ValueTransformer::TYPE_INLINE_STRING, '1')->shouldReturn('string');
48 | $this->transform('string', ValueTransformer::TYPE_ERROR, '1')->shouldReturn('string');
49 | }
50 |
51 | public function it_right_trims_strings()
52 | {
53 | $this->transform(' string ', ValueTransformer::TYPE_STRING, '1')->shouldReturn(' string');
54 | $this->transform('string ', ValueTransformer::TYPE_SHARED_STRING, '1')->shouldReturn('shared_string');
55 | $this->transform(' string ', ValueTransformer::TYPE_INLINE_STRING, '1')->shouldReturn(' string');
56 | $this->transform(' string ', ValueTransformer::TYPE_ERROR, '1')->shouldReturn(' string');
57 | }
58 |
59 | public function it_transforms_numbers()
60 | {
61 | $this->transform('10.2', ValueTransformer::TYPE_NUMBER, '1')->shouldReturn(10.2);
62 | $this->transform('10.2', '', '1')->shouldReturn(10.2);
63 | }
64 |
65 | public function it_transforms_dates()
66 | {
67 | $this->transform('1', ValueTransformer::TYPE_NUMBER, '2')->shouldReturn('date_1');
68 | $this->transform('1', '', '2')->shouldReturn('date_1');
69 | }
70 |
71 | public function it_transforms_boolans()
72 | {
73 | $this->transform('1', ValueTransformer::TYPE_BOOL, null)->shouldReturn(true);
74 | $this->transform('0', ValueTransformer::TYPE_BOOL, '1')->shouldReturn(false);
75 | $this->transform('', ValueTransformer::TYPE_BOOL, '1')->shouldReturn(false);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/WorksheetListReaderSpec.php:
--------------------------------------------------------------------------------
1 | shouldHaveType('Akeneo\Component\SpreadsheetParser\Xlsx\WorksheetListReader');
14 | }
15 |
16 | public function it_returns_worksheet_paths(Relationships $relationships)
17 | {
18 | $relationships->getWorksheetPath(\Prophecy\Argument::type('string'))->will(
19 | function ($args) {
20 | return 'file_' . $args[0];
21 | }
22 | );
23 | $this->getWorksheetPaths($relationships, __DIR__ . '/fixtures/workbook.xml')->shouldReturn(
24 | [
25 | 'Worksheet1' => 'file_rId2',
26 | 'Worksheet2' => 'file_rId3',
27 | 'Worksheet3' => 'file_rId4',
28 | ]
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/fixtures/sharedStrings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | value1
5 |
6 |
7 | value2
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | value3value4
17 | value5
18 |
19 |
20 | values6
21 |
22 |
23 | value7
24 |
25 |
26 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/fixtures/sheet.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 0
20 |
21 |
22 | 1
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | 2
31 |
32 |
33 | 3
34 |
35 |
36 | 4
37 |
38 |
39 |
40 |
41 | 5
42 |
43 |
44 | 6
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | &C&A
55 | &CPage &P
56 |
57 |
58 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/fixtures/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/fixtures/test.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akeneo-labs/spreadsheet-parser/4be5fdae57363819dcd80e84ae875c6402213b1b/spec/Akeneo/Component/SpreadsheetParser/Xlsx/fixtures/test.zip
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/fixtures/workbook.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/spec/Akeneo/Component/SpreadsheetParser/Xlsx/fixtures/workbook.xml.rels:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/Csv/CsvParser.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 | class CsvParser
11 | {
12 | /**
13 | * @staticvar string the name of the format
14 | */
15 | const FORMAT_NAME = 'csv';
16 |
17 | /**
18 | * @staticvar string Spreadsheet class
19 | */
20 | const WORKBOOK_CLASS = 'Akeneo\Component\SpreadsheetParser\Csv\Spreadsheet';
21 |
22 | /**
23 | * @staticvar string RowIterator class
24 | */
25 | const ROW_ITERATOR_CLASS = 'Akeneo\Component\SpreadsheetParser\Csv\RowIterator';
26 |
27 | /**
28 | * @staticvar string The name of the sheet
29 | */
30 | const SHEET_NAME = 'default';
31 |
32 | /**
33 | * @var SpreadsheetLoader
34 | */
35 | private static $spreadsheetLoader;
36 |
37 | /**
38 | * Opens a CSV file
39 | *
40 | * @param string $path
41 | *
42 | * @return Spreadsheet
43 | */
44 | public static function open($path)
45 | {
46 | return static::getSpreadsheetLoader()->open($path);
47 | }
48 |
49 | /**
50 | * @return SpreadsheetLoader
51 | */
52 | public static function getSpreadsheetLoader()
53 | {
54 | if (!isset(self::$spreadsheetLoader)) {
55 | self::$spreadsheetLoader = new SpreadsheetLoader(
56 | static::createRowIteratorFactory(),
57 | static::WORKBOOK_CLASS,
58 | static::SHEET_NAME
59 | );
60 | }
61 |
62 | return self::$spreadsheetLoader;
63 | }
64 |
65 | /**
66 | * @return RowIteratorFactory
67 | */
68 | protected static function createRowIteratorFactory()
69 | {
70 | return new RowIteratorFactory(static::ROW_ITERATOR_CLASS);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/Csv/RowIterator.php:
--------------------------------------------------------------------------------
1 |
18 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
19 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
20 | */
21 | class RowIterator implements \Iterator
22 | {
23 | /**
24 | * @var string
25 | */
26 | protected $path;
27 |
28 | /**
29 | * @var array
30 | */
31 | protected $options;
32 |
33 | /**
34 | * @var resource
35 | */
36 | protected $fileHandle;
37 |
38 | /**
39 | * @var int
40 | */
41 | protected $currentKey;
42 |
43 | /**
44 | * @var array
45 | */
46 | protected $currentValue;
47 |
48 | /**
49 | * @var boolean
50 | */
51 | protected $valid;
52 |
53 | /**
54 | * Constructor
55 | *
56 | * @param string $path
57 | * @param array $options
58 | */
59 | public function __construct(
60 | $path,
61 | array $options
62 | ) {
63 | $this->path = $path;
64 | $resolver = new OptionsResolver;
65 | $this->setDefaultOptions($resolver);
66 | $this->options = $resolver->resolve($options);
67 | }
68 |
69 | /**
70 | * {@inheritdoc}
71 | */
72 | public function current()
73 | {
74 | return $this->currentValue;
75 | }
76 |
77 | /**
78 | * {@inheritdoc}
79 | */
80 | public function key()
81 | {
82 | return $this->currentKey;
83 | }
84 |
85 | /**
86 | * {@inheritdoc}
87 | */
88 | public function next()
89 | {
90 | $this->currentValue = fgetcsv(
91 | $this->fileHandle,
92 | $this->options['length'],
93 | $this->options['delimiter'],
94 | $this->options['enclosure'],
95 | $this->options['escape']
96 | );
97 | $this->currentKey++;
98 | $this->valid = (false !== $this->currentValue);
99 | }
100 |
101 | /**
102 | * {@inheritdoc}
103 | */
104 | public function rewind()
105 | {
106 | if ($this->fileHandle) {
107 | rewind($this->fileHandle);
108 | } else {
109 | $this->openResource();
110 | }
111 | $this->currentKey = 0;
112 | $this->next();
113 | }
114 |
115 | /**
116 | * {@inheritdoc}
117 | */
118 | public function valid()
119 | {
120 | return $this->valid;
121 | }
122 |
123 | /**
124 | * Sets the default options
125 | *
126 | * @param OptionsResolver $resolver
127 | */
128 | protected function setDefaultOptions(OptionsResolver $resolver)
129 | {
130 | $resolver->setDefined(['encoding']);
131 | $resolver->setDefaults(
132 | [
133 | 'length' => null,
134 | 'delimiter' => ',',
135 | 'enclosure' => '"',
136 | 'escape' => '\\'
137 | ]
138 | );
139 | }
140 |
141 | /**
142 | * Opens the file resource
143 | */
144 | protected function openResource()
145 | {
146 | $this->fileHandle = fopen($this->path, 'r');
147 | $currentEncoding = $this->getCurrentEncoding();
148 |
149 | if (isset($this->options['encoding']) && $currentEncoding !== $this->options['encoding']) {
150 | stream_filter_prepend(
151 | $this->fileHandle,
152 | sprintf(
153 | "convert.iconv.%s/%s",
154 | $this->options['encoding'],
155 | $this->getCurrentEncoding()
156 | )
157 | );
158 | }
159 | }
160 |
161 | /**
162 | * Returns the server encoding
163 | *
164 | * @return string
165 | */
166 | protected function getCurrentEncoding()
167 | {
168 | $locale = explode('.', setlocale(LC_CTYPE, 0));
169 |
170 | return isset($locale[1]) ? $locale[1] : 'UTF8';
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/Csv/RowIteratorFactory.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class RowIteratorFactory
13 | {
14 | /**
15 | * @var string
16 | */
17 | protected $iteratorClass;
18 |
19 | /**
20 | * Constructor
21 | *
22 | * @param string $iteratorClass the class for row iterators
23 | */
24 | public function __construct($iteratorClass)
25 | {
26 | $this->iteratorClass = $iteratorClass;
27 | }
28 |
29 | /**
30 | * Creates a row iterator for the XML given worksheet file
31 | *
32 | * @param string $path the path to the extracted XML worksheet file
33 | * @param array $options options specific to the format
34 | *
35 | * @return RowIterator
36 | */
37 | public function create($path, array $options)
38 | {
39 | return new $this->iteratorClass($path, $options);
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/Csv/Spreadsheet.php:
--------------------------------------------------------------------------------
1 |
11 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
13 | */
14 | class Spreadsheet implements SpreadsheetInterface
15 | {
16 | /**
17 | * @var RowIteratorFactory
18 | */
19 | protected $rowIteratorFactory;
20 |
21 | /**
22 | * @var string
23 | */
24 | protected $sheetName;
25 |
26 | /**
27 | * @var string
28 | */
29 | protected $path;
30 |
31 | /**
32 | * Constructor
33 | *
34 | * @param RowIteratorFactory $rowIteratorFactory
35 | * @param string $sheetName
36 | * @param string $path
37 | */
38 | public function __construct(RowIteratorFactory $rowIteratorFactory, $sheetName, $path)
39 | {
40 | $this->rowIteratorFactory = $rowIteratorFactory;
41 | $this->sheetName = $sheetName;
42 | $this->path = $path;
43 | }
44 |
45 | /**
46 | * {@inheritdoc}
47 | */
48 | public function getWorksheets()
49 | {
50 | return [$this->sheetName];
51 | }
52 |
53 | /**
54 | * {@inheritdoc}
55 | */
56 | public function createRowIterator($worksheetIndex, array $options = [])
57 | {
58 | return $this->rowIteratorFactory->create($this->path, $options);
59 | }
60 |
61 | /**
62 | * {@inheritdoc}
63 | */
64 | public function getWorksheetIndex($name)
65 | {
66 | return $this->sheetName === $name ? 0 : false;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/Csv/SpreadsheetLoader.php:
--------------------------------------------------------------------------------
1 |
11 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
13 | */
14 | class SpreadsheetLoader implements SpreadsheetLoaderInterface
15 | {
16 | /**
17 | * @var RowIteratorFactory
18 | */
19 | protected $rowIteratorFactory;
20 |
21 | /**
22 | * @var string
23 | */
24 | protected $spreadsheetClass;
25 |
26 | /**
27 | *
28 | * @var string
29 | */
30 | protected $sheetName;
31 |
32 | /**
33 | * Constructor
34 | *
35 | * @param RowIteratorFactory $rowIteratorFactory
36 | * @param string $spreadsheetClass
37 | * @param string $sheetName
38 | */
39 | public function __construct(RowIteratorFactory $rowIteratorFactory, $spreadsheetClass, $sheetName)
40 | {
41 | $this->rowIteratorFactory = $rowIteratorFactory;
42 | $this->spreadsheetClass = $spreadsheetClass;
43 | $this->sheetName = $sheetName;
44 | }
45 |
46 | /**
47 | * {@inheritdoc}
48 | */
49 | public function open($path, $type = null)
50 | {
51 | return new $this->spreadsheetClass(
52 | $this->rowIteratorFactory,
53 | $this->sheetName,
54 | $path
55 | );
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/SpreadsheetInterface.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | interface SpreadsheetInterface
13 | {
14 | /**
15 | * Returns an array containing all worksheet names
16 | *
17 | * The keys of the array should be the indexes of the worksheets
18 | *
19 | * @return string[]
20 | */
21 | public function getWorksheets();
22 |
23 | /**
24 | * Returns a row iterator for the current worksheet index
25 | *
26 | * @param int $worksheetIndex
27 | * @param array $options
28 | *
29 | * @return \Iterator
30 | */
31 | public function createRowIterator($worksheetIndex, array $options = []);
32 |
33 | /**
34 | * Returns a worksheet index by name
35 | *
36 | * @param string $name
37 | *
38 | * @return int|false Returns false in case there is no worksheet with this name
39 | */
40 | public function getWorksheetIndex($name);
41 | }
42 |
--------------------------------------------------------------------------------
/src/SpreadsheetLoader.php:
--------------------------------------------------------------------------------
1 |
11 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
13 | */
14 | class SpreadsheetLoader implements SpreadsheetLoaderInterface
15 | {
16 | /**
17 | * @var SpreadsheetLoaderInterface[]
18 | */
19 | protected $loaders = [];
20 |
21 | /**
22 | * Opens a spreadsheet
23 | *
24 | * @param string $path
25 | * @param string|null $type
26 | *
27 | * @return SpreadsheetInterface
28 | *
29 | * @throws InvalidArgumentException
30 | */
31 | public function open($path, $type = null)
32 | {
33 | $type = $type ?: $this->getType($path);
34 | if (!isset($this->loaders[$type])) {
35 | throw new InvalidArgumentException(sprintf('No loader for type %s', $type));
36 | }
37 |
38 | return $this->loaders[$type]->open($path);
39 | }
40 |
41 | /**
42 | * Addds a loader for a specified type
43 | *
44 | * @param string $type
45 | * @param SpreadsheetLoaderInterface $loader
46 | *
47 | * @return SpreadsheetLoader
48 | */
49 | public function addLoader($type, SpreadsheetLoaderInterface $loader)
50 | {
51 | $this->loaders[$type] = $loader;
52 |
53 | return $this;
54 | }
55 |
56 | /**
57 | * Returns the type for a path
58 | *
59 | * @param string $path
60 | *
61 | * @return string
62 | */
63 | protected function getType($path)
64 | {
65 | return strtolower(pathinfo($path, PATHINFO_EXTENSION));
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/SpreadsheetLoaderInterface.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | interface SpreadsheetLoaderInterface
13 | {
14 | /**
15 | * Opens a spreadsheet and returns a Spreadsheet object
16 | *
17 | * Spreadsheet objects are cached, and will be read only once
18 | *
19 | * @param string $path
20 | * @param string|null $type
21 | *
22 | * @return SpreadsheetInterface
23 | */
24 | public function open($path, $type = null);
25 | }
26 |
--------------------------------------------------------------------------------
/src/SpreadsheetParser.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class SpreadsheetParser
13 | {
14 | /**
15 | * @var SpreadsheetLoader
16 | */
17 | protected static $spreadsheetLoader;
18 |
19 | /**
20 | * Opens a spreadsheet
21 | *
22 | * @param string $path
23 | * @param string|null $type
24 | *
25 | * @return SpreadsheetInterface
26 | */
27 | public static function open($path, $type = null)
28 | {
29 | return static::getSpreadsheetLoader()->open($path, $type);
30 | }
31 |
32 | /**
33 | * Returns the spreadsheet loader
34 | *
35 | * @return SpreadsheetLoaderInterface
36 | */
37 | public static function getSpreadsheetLoader()
38 | {
39 | if (!isset(static::$spreadsheetLoader)) {
40 | static::$spreadsheetLoader = new SpreadsheetLoader();
41 | static::configureLoaders();
42 | }
43 |
44 | return static::$spreadsheetLoader;
45 | }
46 |
47 | /**
48 | * Configure the loaders
49 | */
50 | protected static function configureLoaders()
51 | {
52 | static::$spreadsheetLoader
53 | ->addLoader(Xlsx\XlsxParser::FORMAT_NAME, Xlsx\XlsxParser::getSpreadsheetLoader())
54 | ->addLoader(Xlsx\XlsxParser::MACRO_FORMAT_NAME, Xlsx\XlsxParser::getSpreadsheetLoader())
55 | ->addLoader(Csv\CsvParser::FORMAT_NAME, Csv\CsvParser::getSpreadsheetLoader());
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/Xlsx/AbstractXMLDictionnary.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | abstract class AbstractXMLDictionnary extends AbstractXMLResource
13 | {
14 | /**
15 | * @var boolean
16 | */
17 | protected $valid = true;
18 |
19 | /**
20 | * @var array
21 | */
22 | protected $values = [];
23 |
24 | /**
25 | * Returns a shared string by index
26 | *
27 | * @param int $index
28 | *
29 | * @throws \InvalidArgumentException
30 | */
31 | public function get($index)
32 | {
33 | while ($this->valid && !isset($this->values[$index])) {
34 | $this->readNext();
35 | }
36 | if ((!isset($this->values[$index]))) {
37 | throw new \InvalidArgumentException(sprintf('No value with index %s', $index));
38 | }
39 |
40 | return $this->values[$index];
41 | }
42 |
43 | /**
44 | * Reads the next value in the file
45 | */
46 | abstract protected function readNext();
47 | }
48 |
--------------------------------------------------------------------------------
/src/Xlsx/AbstractXMLResource.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | abstract class AbstractXMLResource
13 | {
14 | /**
15 | * @var string
16 | */
17 | protected $path;
18 |
19 | /**
20 | * @var \XMLReader
21 | */
22 | private $xml;
23 |
24 | /**
25 | * The Archive from which the path was extracted.
26 | *
27 | * A reference to the object is kept here to ensure that it is not deleted
28 | * before the RowIterator, as this would remove the extraction folder.
29 | *
30 | * @var Archive
31 | */
32 | private $archive;
33 |
34 | /**
35 | * Constructor
36 | *
37 | * @param string $path path to the extracted shared strings XML file
38 | * @param Archive|null $archive The Archive from which the path was extracted
39 | */
40 | public function __construct($path, Archive $archive = null)
41 | {
42 | $this->path = $path;
43 | $this->archive = $archive;
44 | }
45 |
46 | /**
47 | * @inheritdoc
48 | */
49 | public function __destruct()
50 | {
51 | if ($this->xml) {
52 | $this->closeXMLReader();
53 | }
54 | }
55 |
56 | /**
57 | * Returns the XML reader
58 | *
59 | * @return \XMLReader
60 | */
61 | protected function getXMLReader()
62 | {
63 | if (!$this->xml) {
64 | $this->xml = $this->createXMLReader();
65 | }
66 |
67 | return $this->xml;
68 | }
69 |
70 | /**
71 | * Creates the XML Reader
72 | *
73 | * @return \XMLReader
74 | */
75 | protected function createXMLReader()
76 | {
77 | $xml = new \XMLReader();
78 | $xml->open($this->path);
79 |
80 | return $xml;
81 | }
82 |
83 | /**
84 | * Closes the XML reader
85 | */
86 | protected function closeXMLReader()
87 | {
88 | $this->xml->close();
89 | $this->xml = null;
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/Xlsx/Archive.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class Archive
13 | {
14 | /**
15 | *
16 | * @var string
17 | */
18 | protected $tempPath;
19 |
20 | /**
21 | *
22 | * @var string
23 | */
24 | protected $archivePath;
25 |
26 | /**
27 | * @var \ZipArchive
28 | */
29 | private $zip;
30 |
31 | /**
32 | * Constructor
33 | *
34 | * @param string $archivePath
35 | */
36 | public function __construct($archivePath)
37 | {
38 | $this->archivePath = $archivePath;
39 | $this->tempPath = tempnam(sys_get_temp_dir(), 'xls_parser_archive');
40 | unlink($this->tempPath);
41 | }
42 |
43 | /**
44 | * Extracts the specified file to a temp path, and return the temp path
45 | *
46 | * Files are only extracted once for the given archive
47 | *
48 | * @param string $filePath
49 | *
50 | * @return string
51 | */
52 | public function extract($filePath)
53 | {
54 | $tempPath = sprintf('%s/%s', $this->tempPath, $filePath);
55 | if (!file_exists($tempPath)) {
56 | $this->getArchive()->extractTo($this->tempPath, $filePath);
57 | }
58 |
59 | return $tempPath;
60 | }
61 |
62 | /**
63 | * Clears all extracted files
64 | */
65 | public function __destruct()
66 | {
67 | $this->deleteTemp();
68 | $this->closeArchive();
69 | }
70 |
71 | /**
72 | * Returns the archive
73 | *
74 | * @return \ZipArchive
75 | */
76 | protected function getArchive()
77 | {
78 | if (!$this->zip) {
79 | $this->zip = new \ZipArchive();
80 | if (true !== $errorCode = $this->zip->open($this->archivePath)) {
81 | $this->zip = null;
82 | throw new \RuntimeException('Error opening file: '.$this->getErrorMessage($errorCode));
83 | }
84 | }
85 |
86 | return $this->zip;
87 | }
88 |
89 | /**
90 | * Closes the archive
91 | */
92 | protected function closeArchive()
93 | {
94 | if ($this->zip) {
95 | $this->zip->close();
96 | $this->zip = null;
97 | }
98 | }
99 |
100 | /**
101 | * Deletes temporary files
102 | *
103 | * @return null
104 | */
105 | protected function deleteTemp()
106 | {
107 | if (!file_exists($this->tempPath)) {
108 | return;
109 | }
110 |
111 | $files = new \RecursiveIteratorIterator(
112 | new \RecursiveDirectoryIterator($this->tempPath, \RecursiveDirectoryIterator::SKIP_DOTS),
113 | \RecursiveIteratorIterator::CHILD_FIRST
114 | );
115 | foreach ($files as $file) {
116 | if ($file->isDir()) {
117 | rmdir($file->getRealPath());
118 | } else {
119 | unlink($file->getRealPath());
120 | }
121 | }
122 | rmdir($this->tempPath);
123 | }
124 |
125 | /**
126 | * Gets an error message from the error code
127 | *
128 | * @param string $errorCode
129 | *
130 | * @return string
131 | */
132 | protected function getErrorMessage($errorCode)
133 | {
134 | switch ($errorCode) {
135 | case \ZipArchive::ER_MULTIDISK:
136 | return 'Multi-disk zip archives not supported';
137 |
138 | case \ZipArchive::ER_RENAME:
139 | return 'Renaming temporary file failed';
140 |
141 | case \ZipArchive::ER_CLOSE:
142 | return 'Closing zip archive failed';
143 |
144 | case \ZipArchive::ER_SEEK:
145 | return 'Seek error';
146 |
147 | case \ZipArchive::ER_READ:
148 | return 'Read error';
149 |
150 | case \ZipArchive::ER_WRITE:
151 | return 'Write error';
152 |
153 | case \ZipArchive::ER_CRC:
154 | return 'CRC error';
155 |
156 | case \ZipArchive::ER_ZIPCLOSED:
157 | return 'Containing zip archive was closed';
158 |
159 | case \ZipArchive::ER_NOENT:
160 | return 'No such file';
161 |
162 | case \ZipArchive::ER_EXISTS:
163 | return 'File already exists';
164 |
165 | case \ZipArchive::ER_OPEN:
166 | return 'Can\'t open file';
167 |
168 | case \ZipArchive::ER_TMPOPEN:
169 | return 'Failure to create temporary file';
170 |
171 | case \ZipArchive::ER_ZLIB:
172 | return 'Zlib error';
173 |
174 | case \ZipArchive::ER_MEMORY:
175 | return 'Malloc failure';
176 |
177 | case \ZipArchive::ER_CHANGED:
178 | return 'Entry has been changed';
179 |
180 | case \ZipArchive::ER_COMPNOTSUPP:
181 | return 'Compression method not supported';
182 |
183 | case \ZipArchive::ER_EOF:
184 | return 'Premature EOF';
185 |
186 | case \ZipArchive::ER_INVAL:
187 | return 'Invalid argument';
188 |
189 | case \ZipArchive::ER_NOZIP:
190 | return 'Not a zip archive';
191 |
192 | case \ZipArchive::ER_INTERNAL:
193 | return 'Internal error';
194 |
195 | case \ZipArchive::ER_INCONS:
196 | return 'Zip archive inconsistent';
197 |
198 | case \ZipArchive::ER_REMOVE:
199 | return 'Can\'t remove file';
200 |
201 | case \ZipArchive::ER_DELETED:
202 | return 'Entry has been deleted';
203 |
204 | default:
205 | return 'An unknown error has occurred('.intval($errorCode).')';
206 | }
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/src/Xlsx/ArchiveLoader.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class ArchiveLoader
13 | {
14 | /**
15 | *
16 | * @var string
17 | */
18 | protected $archiveClass;
19 |
20 | /**
21 | * Constructor
22 | *
23 | * @param string $archiveClass The class of loaded objects
24 | */
25 | public function __construct($archiveClass)
26 | {
27 | $this->archiveClass = $archiveClass;
28 | }
29 |
30 | /**
31 | * Opens the given archive
32 | *
33 | * @param string $path
34 | *
35 | * @return Archive
36 | */
37 | public function open($path)
38 | {
39 | return new $this->archiveClass($path);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Xlsx/ColumnIndexTransformer.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 |
13 | class ColumnIndexTransformer
14 | {
15 | /**
16 | * Transforms an Excel cell name in an index
17 | *
18 | * @param string $name
19 | *
20 | * @return integer
21 | */
22 | public function transform($name)
23 | {
24 | $number = -1;
25 |
26 | foreach (str_split($name) as $chr) {
27 | $digit = ord($chr) - 65;
28 | if ($digit < 0) {
29 | break;
30 | }
31 | $number = ($number + 1) * 26 + $digit;
32 | }
33 |
34 | return $number;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Xlsx/DateTransformer.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class DateTransformer
13 | {
14 | /**
15 | * @var \DateTime
16 | */
17 | protected $baseDate;
18 |
19 | /**
20 | * Constructor
21 | */
22 | public function __construct()
23 | {
24 | $this->baseDate = new \DateTime('1900-01-00 00:00:00 UTC');
25 | }
26 |
27 | /**
28 | * Transforms an Excel date into a DateTime object
29 | *
30 | * @param String $value
31 | *
32 | * @return \DateTime
33 | */
34 | public function transform($value)
35 | {
36 | $days = floor($value);
37 |
38 | $seconds = round(($value - $days) * 86400);
39 |
40 | $date = clone $this->baseDate;
41 | $date->modify(sprintf('+%sday +%ssecond', $days - 1, $seconds));
42 |
43 | return $date;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/Xlsx/Relationships.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class Relationships extends AbstractXMLResource
13 | {
14 |
15 | /**
16 | *
17 | * @var string
18 | */
19 | protected $relationshipsPath;
20 |
21 | /**
22 | *
23 | * @var array
24 | */
25 | protected $workSheetPaths;
26 |
27 | /**
28 | *
29 | * @var string
30 | */
31 | protected $stylePath;
32 |
33 | /**
34 | *
35 | * @var string
36 | */
37 | protected $sharedStringPath;
38 |
39 | /**
40 | * Constructor
41 | *
42 | * @param string $path the path to the XML relationships file
43 | */
44 | public function __construct($path)
45 | {
46 | parent::__construct($path);
47 | $xml = $this->getXMLReader();
48 |
49 | while ($xml->read()) {
50 | if (\XMLReader::ELEMENT === $xml->nodeType && 'Relationship' === $xml->name) {
51 |
52 | $type = basename((string)$xml->getAttribute('Type'));
53 | $this->storeRelationShipByType($type, $xml->getAttribute('Id'), 'xl/' . $xml->getAttribute('Target'));
54 | }
55 | }
56 |
57 | $this->closeXMLReader();
58 | }
59 |
60 | /**
61 | * Returns the path of a worksheet file inside the xlsx file
62 | *
63 | * @param string $id
64 | *
65 | * @return string
66 | */
67 | public function getWorksheetPath($id)
68 | {
69 | return $this->workSheetPaths[$id];
70 | }
71 |
72 | /**
73 | * Returns the path of the shared strings file inside the xlsx file
74 | *
75 | * @return string
76 | */
77 | public function getSharedStringsPath()
78 | {
79 | return $this->sharedStringPath;
80 | }
81 |
82 | /**
83 | * Returns the path of the styles XML file inside the xlsx file
84 | *
85 | * @return string
86 | */
87 | public function getStylesPath()
88 | {
89 | return $this->stylePath;
90 | }
91 |
92 | /**
93 | * stores the relationShip into the right variable
94 | *
95 | * @param string $type
96 | * @param string $id
97 | * @param string $target
98 | */
99 | private function storeRelationShipByType($type, $id, $target)
100 | {
101 | switch ($type) {
102 | case 'worksheet':
103 | $this->workSheetPaths[$id] = $target;
104 | break;
105 | case 'styles':
106 | $this->stylePath = $target;
107 | break;
108 | case 'sharedStrings':
109 | $this->sharedStringPath = $target;
110 | break;
111 | }
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/src/Xlsx/RelationshipsLoader.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class RelationshipsLoader
13 | {
14 | /**
15 | *
16 | * @var string
17 | */
18 | protected $relationshipClass;
19 |
20 | /**
21 | * Constructor
22 | *
23 | * @param string $relationshipClass The class of the relationship objects
24 | */
25 | public function __construct($relationshipClass)
26 | {
27 | $this->relationshipClass = $relationshipClass;
28 | }
29 |
30 | /**
31 | * Opens a relationships file
32 | *
33 | * @param string $path
34 | *
35 | * @return Relationships
36 | */
37 | public function open($path)
38 | {
39 | return new $this->relationshipClass($path);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Xlsx/RowBuilder.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class RowBuilder
13 | {
14 |
15 | /**
16 | *
17 | * @var array
18 | */
19 | protected $values = [];
20 |
21 | /**
22 | * Adds a value to the row
23 | *
24 | * @param int $columnIndex
25 | * @param string $value
26 | */
27 | public function addValue($columnIndex, $value)
28 | {
29 | if ('' !== $value) {
30 | $this->values[$columnIndex] = $value;
31 | }
32 | }
33 |
34 | /**
35 | * Returns the read row
36 | *
37 | * @return array
38 | */
39 | public function getData()
40 | {
41 | $data = [];
42 | foreach ($this->values as $columnIndex => $value) {
43 | while (count($data) < $columnIndex) {
44 | $data[] = '';
45 | }
46 | $data[] = $value;
47 | }
48 |
49 | return $data;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Xlsx/RowBuilderFactory.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 |
13 | class RowBuilderFactory
14 | {
15 |
16 | /**
17 | *
18 | * @var string
19 | */
20 | protected $rowBuilderClass;
21 |
22 | /**
23 | * Constructor
24 | *
25 | * @param string $rowBuilderClass
26 | */
27 | public function __construct($rowBuilderClass)
28 | {
29 | $this->rowBuilderClass = $rowBuilderClass;
30 | }
31 |
32 | /**
33 | * Creates a RowBuilder object
34 | *
35 | * @return RowBuilder
36 | */
37 | public function create()
38 | {
39 | return new $this->rowBuilderClass();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Xlsx/RowIterator.php:
--------------------------------------------------------------------------------
1 |
13 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
14 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15 | */
16 | class RowIterator implements \Iterator
17 | {
18 | /**
19 | * @var RowBuilderFactory
20 | */
21 | protected $rowBuilderFactory;
22 |
23 | /**
24 | * @var ColumnIndexTransformer
25 | */
26 | protected $columnIndexTransformer;
27 |
28 | /**
29 | * @var ValueTransformer
30 | */
31 | protected $valueTransformer;
32 |
33 | /**
34 | * @var string
35 | */
36 | protected $path;
37 |
38 | /**
39 | * @var array
40 | */
41 | protected $options;
42 |
43 | /**
44 | * @var \XMLReader
45 | */
46 | protected $xml;
47 |
48 | /**
49 | * @var int
50 | */
51 | protected $currentKey;
52 |
53 | /**
54 | * @var array
55 | */
56 | protected $currentValue;
57 |
58 | /**
59 | * @var boolean
60 | */
61 | protected $valid;
62 |
63 | /**
64 | * The Archive from which the path was extracted.
65 | *
66 | * A reference to the object is kept here to ensure that it is not deleted
67 | * before the RowIterator, as this would remove the extraction folder.
68 | *
69 | * @var Archive
70 | */
71 | private $archive;
72 |
73 | /**
74 | * Constructor
75 | *
76 | * @param RowBuilderFactory $rowBuilderFactory
77 | * @param ColumnIndexTransformer $columnIndexTransformer
78 | * @param ValueTransformer $valueTransformer
79 | * @param string $path
80 | * @param array $options
81 | * @param Archive $archive The Archive from which the path was extracted
82 | */
83 | public function __construct(
84 | RowBuilderFactory $rowBuilderFactory,
85 | ColumnIndexTransformer $columnIndexTransformer,
86 | ValueTransformer $valueTransformer,
87 | $path,
88 | array $options,
89 | Archive $archive
90 | ) {
91 | $this->rowBuilderFactory = $rowBuilderFactory;
92 | $this->columnIndexTransformer = $columnIndexTransformer;
93 | $this->valueTransformer = $valueTransformer;
94 | $this->path = $path;
95 | $this->options = $options;
96 | $this->archive = $archive;
97 | }
98 |
99 | /**
100 | * {@inheritdoc}
101 | */
102 | public function current()
103 | {
104 | return $this->currentValue;
105 | }
106 |
107 | /**
108 | * {@inheritdoc}
109 | */
110 | public function key()
111 | {
112 | return $this->currentKey;
113 | }
114 |
115 | /**
116 | * {@inheritdoc}
117 | */
118 | public function next()
119 | {
120 | $this->valid = false;
121 |
122 | $style = null;
123 | $type = null;
124 | $columnIndex = null;
125 | $rowBuilder = null;
126 | $currentKey = 0;
127 |
128 | while ($this->xml->read()) {
129 | if (\XMLReader::ELEMENT === $this->xml->nodeType) {
130 | switch ($this->xml->name) {
131 | case 'row':
132 | $currentKey = (int)$this->xml->getAttribute('r');
133 | $rowBuilder = $this->rowBuilderFactory->create();
134 | break;
135 | case 'c':
136 | $columnIndex = $this->columnIndexTransformer->transform($this->xml->getAttribute('r'));
137 | $style = $this->getValue($this->xml->getAttribute('s'));
138 | $type = $this->getValue($this->xml->getAttribute('t'));
139 | break;
140 | case 'v':
141 | $rowBuilder->addValue(
142 | $columnIndex,
143 | $this->valueTransformer->transform($this->xml->readString(), $type, $style)
144 | );
145 | break;
146 | case 'is':
147 | $rowBuilder->addValue($columnIndex, $this->xml->readString());
148 | break;
149 | }
150 | } elseif (\XMLReader::END_ELEMENT === $this->xml->nodeType) {
151 | switch ($this->xml->name) {
152 | case 'row':
153 | $currentValue = $rowBuilder->getData();
154 | if (count($currentValue)) {
155 | $this->currentKey = $currentKey;
156 | $this->currentValue = $currentValue;
157 | $this->valid = true;
158 |
159 | return;
160 | }
161 | break;
162 | case 'sheetData':
163 | break 2;
164 | }
165 | }
166 | }
167 | }
168 |
169 | /**
170 | * {@inheritdoc}
171 | */
172 | public function rewind()
173 | {
174 | if ($this->xml) {
175 | $this->xml->close();
176 | }
177 | $this->xml = new \XMLReader();
178 | $this->xml->open($this->path);
179 | $this->next();
180 | }
181 |
182 | /**
183 | * {@inheritdoc}
184 | */
185 | public function valid()
186 | {
187 | return $this->valid;
188 | }
189 |
190 | /**
191 | * Returns a normalized attribute value
192 | *
193 | * @param string $value
194 | *
195 | * @return string
196 | */
197 | protected function getValue($value)
198 | {
199 | return null === $value ? '' : $value;
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/src/Xlsx/RowIteratorFactory.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class RowIteratorFactory
13 | {
14 |
15 | /**
16 | *
17 | * @var RowBuilderFactory
18 | */
19 | protected $rowBuilderFactory;
20 |
21 | /**
22 | *
23 | * @var ColumnIndexTransformer
24 | */
25 | protected $columnIndexTransformer;
26 |
27 | /**
28 | *
29 | * @var string
30 | */
31 | protected $iteratorClass;
32 |
33 | /**
34 | * Constructor
35 | *
36 | * @param RowBuilderFactory $rowBuilderFactory
37 | * @param ColumnIndexTransformer $columnIndexTransformer
38 | * @param string $iteratorClass the class for row iterators
39 | */
40 | public function __construct(
41 | RowBuilderFactory $rowBuilderFactory,
42 | ColumnIndexTransformer $columnIndexTransformer,
43 | $iteratorClass
44 | ) {
45 | $this->rowBuilderFactory = $rowBuilderFactory;
46 | $this->columnIndexTransformer = $columnIndexTransformer;
47 | $this->iteratorClass = $iteratorClass;
48 | }
49 |
50 | /**
51 | * Creates a row iterator for the XML given worksheet file
52 | *
53 | * @param ValueTransformer $valueTransformer the value transformer for the spreadsheet
54 | * @param string $path the path to the extracted XML worksheet file
55 | * @param array $options options specific to the format
56 | * @param Archive $archive The Archive from which the path was extracted
57 | *
58 | * @return RowIterator
59 | */
60 | public function create(ValueTransformer $valueTransformer, $path, array $options, Archive $archive)
61 | {
62 | return new $this->iteratorClass(
63 | $this->rowBuilderFactory,
64 | $this->columnIndexTransformer,
65 | $valueTransformer,
66 | $path,
67 | $options,
68 | $archive
69 | );
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/src/Xlsx/SharedStrings.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class SharedStrings extends AbstractXMLDictionnary
13 | {
14 | /**
15 | * @var int
16 | */
17 | protected $currentIndex = -1;
18 |
19 | /**
20 | * Reads the next value in the file
21 | */
22 | protected function readNext()
23 | {
24 | $xml = $this->getXMLReader();
25 | while ($xml->read()) {
26 | if (\XMLReader::ELEMENT === $xml->nodeType) {
27 | switch ($xml->name) {
28 | case 'si':
29 | $this->currentIndex++;
30 | break;
31 | case 't':
32 | $this->values[$this->currentIndex] = $xml->readString();
33 |
34 | return;
35 | }
36 | }
37 | }
38 |
39 | $this->valid = false;
40 | $this->closeXMLReader();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Xlsx/SharedStringsLoader.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class SharedStringsLoader
13 | {
14 |
15 | /**
16 | *
17 | * @var string
18 | */
19 | protected $sharedStringsClass;
20 |
21 | /**
22 | * Constructor
23 | *
24 | * @param string $sharedStringsClass The class for created objects
25 | */
26 | public function __construct($sharedStringsClass)
27 | {
28 | $this->sharedStringsClass = $sharedStringsClass;
29 | }
30 |
31 | /**
32 | * Creates a SharedStrings from the archive
33 | *
34 | * @param string $path
35 | * @param Archive $archive The Archive from which the path was extracted
36 | *
37 | * @return SharedStrings
38 | */
39 | public function open($path, Archive $archive)
40 | {
41 | return new $this->sharedStringsClass($path, $archive);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/Xlsx/Spreadsheet.php:
--------------------------------------------------------------------------------
1 |
11 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
13 | */
14 | class Spreadsheet implements SpreadsheetInterface
15 | {
16 |
17 | /**
18 | * @staticvar string Path to the relationships file inside the XLSX archive
19 | */
20 | const RELATIONSHIPS_PATH = 'xl/_rels/workbook.xml.rels';
21 |
22 | /**
23 | * @staticvar string Path to the spreadsheets file inside the XLSX archive
24 | */
25 | const WORKBOOK_PATH = 'xl/workbook.xml';
26 |
27 | /**
28 | * @var RelationshipsLoader
29 | */
30 | protected $relationshipsLoader;
31 |
32 | /**
33 | * @var ValueTransformerFactory
34 | */
35 | protected $valueTransformerFactory;
36 |
37 | /**
38 | *
39 | * @var SharedStringsLoader
40 | */
41 | protected $sharedStringsLoader;
42 |
43 | /**
44 | *
45 | * @var RowIteratorFactory
46 | */
47 | protected $rowIteratorFactory;
48 |
49 | /**
50 | * @var Archive
51 | */
52 | protected $archive;
53 |
54 | /**
55 | * @var StylesLoader
56 | */
57 | protected $stylesLoader;
58 |
59 | /**
60 | * @var WorksheetListReader
61 | */
62 | protected $worksheetListReader;
63 |
64 | /**
65 | * @var Relationships
66 | */
67 | private $relationships;
68 |
69 | /**
70 | * @var ValueTransformer
71 | */
72 | private $valueTransformer;
73 |
74 | /**
75 | * @var SharedStrings
76 | */
77 | private $sharedStrings;
78 |
79 | /**
80 | * @var array
81 | */
82 | private $worksheetPaths;
83 |
84 | /**
85 | * @var Styles
86 | */
87 | private $styles;
88 |
89 | /**
90 | * Constructor
91 | *
92 | * @param Archive $archive
93 | * @param RelationshipsLoader $relationshipsLoader
94 | * @param SharedStringsLoader $sharedStringsLoader
95 | * @param StylesLoader $stylesLoader
96 | * @param WorksheetListReader $worksheetListReader
97 | * @param ValueTransformerFactory $valueTransformerFactory
98 | * @param RowIteratorFactory $rowIteratorFactory
99 | */
100 | public function __construct(
101 | Archive $archive,
102 | RelationshipsLoader $relationshipsLoader,
103 | SharedStringsLoader $sharedStringsLoader,
104 | StylesLoader $stylesLoader,
105 | WorksheetListReader $worksheetListReader,
106 | ValueTransformerFactory $valueTransformerFactory,
107 | RowIteratorFactory $rowIteratorFactory
108 | ) {
109 | $this->archive = $archive;
110 | $this->relationshipsLoader = $relationshipsLoader;
111 | $this->sharedStringsLoader = $sharedStringsLoader;
112 | $this->stylesLoader = $stylesLoader;
113 | $this->worksheetListReader = $worksheetListReader;
114 | $this->valueTransformerFactory = $valueTransformerFactory;
115 | $this->rowIteratorFactory = $rowIteratorFactory;
116 | }
117 |
118 | /**
119 | * {@inheritdoc}
120 | */
121 | public function getWorksheets()
122 | {
123 | return array_keys($this->getWorksheetPaths());
124 | }
125 |
126 | /**
127 | * {@inheritdoc}
128 | */
129 | public function createRowIterator($worksheetIndex, array $options = [])
130 | {
131 | $paths = array_values($this->getWorksheetPaths());
132 |
133 | return $this->rowIteratorFactory->create(
134 | $this->getValueTransformer(),
135 | $this->archive->extract($paths[$worksheetIndex]),
136 | $options,
137 | $this->archive
138 | );
139 | }
140 |
141 | /**
142 | * {@inheritdoc}
143 | */
144 | public function getWorksheetIndex($name)
145 | {
146 | return array_search($name, $this->getWorksheets());
147 | }
148 |
149 | /**
150 | * @return Relationships
151 | */
152 | protected function getRelationships()
153 | {
154 | if (!$this->relationships) {
155 | $path = $this->archive->extract(static::RELATIONSHIPS_PATH);
156 | $this->relationships = $this->relationshipsLoader->open($path);
157 | }
158 |
159 | return $this->relationships;
160 | }
161 |
162 | /**
163 | * @return ValueTransformer
164 | */
165 | protected function getValueTransformer()
166 | {
167 | if (!$this->valueTransformer) {
168 | $this->valueTransformer = $this->valueTransformerFactory->create(
169 | $this->getSharedStrings(),
170 | $this->getStyles()
171 | );
172 | }
173 |
174 | return $this->valueTransformer;
175 | }
176 |
177 | /**
178 | * @return SharedStrings
179 | */
180 | protected function getSharedStrings()
181 | {
182 | if (!$this->sharedStrings) {
183 | $path = $this->archive->extract($this->relationships->getSharedStringsPath());
184 | $this->sharedStrings = $this->sharedStringsLoader->open($path, $this->archive);
185 | }
186 |
187 | return $this->sharedStrings;
188 | }
189 |
190 | /**
191 | * @return array
192 | */
193 | protected function getWorksheetPaths()
194 | {
195 | if (!$this->worksheetPaths) {
196 | $path = $this->archive->extract(static::WORKBOOK_PATH);
197 | $this->worksheetPaths = $this->worksheetListReader->getWorksheetPaths($this->getRelationships(), $path);
198 | }
199 |
200 | return $this->worksheetPaths;
201 | }
202 |
203 | /**
204 | * @return Styles
205 | */
206 | protected function getStyles()
207 | {
208 | if (!$this->styles) {
209 | $path = $this->archive->extract($this->relationships->getStylesPath());
210 | $this->styles = $this->stylesLoader->open($path, $this->archive);
211 | }
212 |
213 | return $this->styles;
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/src/Xlsx/SpreadsheetLoader.php:
--------------------------------------------------------------------------------
1 |
11 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
13 | */
14 | class SpreadsheetLoader implements SpreadsheetLoaderInterface
15 | {
16 | /**
17 | * @var string
18 | */
19 | protected $spreadsheetClass;
20 |
21 | /**
22 | * @var RelationshipsLoader
23 | */
24 | protected $relationshipsLoader;
25 |
26 | /**
27 | * @var SharedStringsLoader
28 | */
29 | protected $sharedStringsLoader;
30 |
31 | /**
32 | * @var StylesLoader
33 | */
34 | protected $stylesLoader;
35 |
36 | /**
37 | * @var WorksheetListReader
38 | */
39 | protected $worksheetListReader;
40 |
41 | /**
42 | * @var ValueTransformerFactory
43 | */
44 | protected $valueTransformerFactory;
45 |
46 | /**
47 | * @var RowIteratorFactory
48 | */
49 | protected $rowIteratorFactory;
50 |
51 | /**
52 | * @var ArchiveLoader
53 | */
54 | protected $archiveLoader;
55 |
56 | /**
57 | * Constructor
58 | *
59 | * @param ArchiveLoader $archiveLoader
60 | * @param RelationshipsLoader $relationshipsLoader
61 | * @param SharedStringsLoader $sharedStringsLoader
62 | * @param StylesLoader $stylesLoader
63 | * @param WorksheetListReader $worksheetListReader
64 | * @param ValueTransformerFactory $valueTransformerFactory
65 | * @param RowIteratorFactory $rowIteratorFactory
66 | * @param string $spreadsheetClass
67 | */
68 | public function __construct(
69 | ArchiveLoader $archiveLoader,
70 | RelationshipsLoader $relationshipsLoader,
71 | SharedStringsLoader $sharedStringsLoader,
72 | StylesLoader $stylesLoader,
73 | WorksheetListReader $worksheetListReader,
74 | ValueTransformerFactory $valueTransformerFactory,
75 | RowIteratorFactory $rowIteratorFactory,
76 | $spreadsheetClass
77 | ) {
78 | $this->relationshipsLoader = $relationshipsLoader;
79 | $this->sharedStringsLoader = $sharedStringsLoader;
80 | $this->stylesLoader = $stylesLoader;
81 | $this->worksheetListReader = $worksheetListReader;
82 | $this->valueTransformerFactory = $valueTransformerFactory;
83 | $this->rowIteratorFactory = $rowIteratorFactory;
84 | $this->archiveLoader = $archiveLoader;
85 | $this->spreadsheetClass = $spreadsheetClass;
86 | }
87 |
88 | /**
89 | * {@inheritdoc}
90 | */
91 | public function open($path, $type = null)
92 | {
93 | $archive = $this->archiveLoader->open($path);
94 |
95 | return new $this->spreadsheetClass(
96 | $archive,
97 | $this->relationshipsLoader,
98 | $this->sharedStringsLoader,
99 | $this->stylesLoader,
100 | $this->worksheetListReader,
101 | $this->valueTransformerFactory,
102 | $this->rowIteratorFactory
103 | );
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/src/Xlsx/Styles.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class Styles extends AbstractXMLDictionnary
13 | {
14 | /**
15 | * @staticvar int Default format
16 | */
17 | const FORMAT_DEFAULT = 0;
18 |
19 | /**
20 | * @staticvar int Date format
21 | */
22 | const FORMAT_DATE = 1;
23 |
24 | /**
25 | * @var array
26 | */
27 | protected $nativeDateFormats = [14, 15, 16, 17, 18, 19, 20, 21, 22];
28 |
29 | /**
30 | * @var array
31 | */
32 | protected $numberFormats = [];
33 |
34 | /**
35 | * @var boolean
36 | */
37 | protected $inXfs;
38 |
39 | /**
40 | * {@inheritdoc}
41 | */
42 | protected function readNext()
43 | {
44 | $xml = $this->getXMLReader();
45 | while ($xml->read()) {
46 | if (\XMLReader::END_ELEMENT === $xml->nodeType && 'cellXfs' === $xml->name) {
47 | break;
48 | } elseif (\XMLReader::ELEMENT === $xml->nodeType && 'cellXfs' === $xml->name) {
49 | $this->inXfs = true;
50 | } elseif ($this->inXfs && \XMLReader::ELEMENT === $xml->nodeType && 'xf' === $xml->name) {
51 | $fmtId = $xml->getAttribute('numFmtId');
52 | if (isset($this->numberFormats[$fmtId])) {
53 | $value = $this->numberFormats[$fmtId];
54 | } elseif (in_array($fmtId, $this->nativeDateFormats)) {
55 | $value = static::FORMAT_DATE;
56 | } else {
57 | $value = static::FORMAT_DEFAULT;
58 | }
59 | $this->values[] = $value;
60 |
61 | return;
62 | }
63 | }
64 | $this->valid = false;
65 | $this->closeXMLReader();
66 | }
67 |
68 | /**
69 | * {@inheritdoc}
70 | */
71 | protected function createXMLReader()
72 | {
73 | $xml = parent::createXMLReader();
74 | $needsRewind = false;
75 | while ($xml->read()) {
76 | if (\XMLReader::END_ELEMENT === $xml->nodeType && 'numFmts' === $xml->name) {
77 | break;
78 | } elseif (\XMLReader::ELEMENT === $xml->nodeType) {
79 | switch ($xml->name) {
80 | case 'numFmt':
81 | $this->numberFormats[$xml->getAttribute('numFmtId')] =
82 | preg_match('{^(\[\$[[:alpha:]]*-[0-9A-F]*\])*[hmsdy]}i', $xml->getAttribute('formatCode'))
83 | ? static::FORMAT_DATE
84 | : static::FORMAT_DEFAULT;
85 | break;
86 | case 'cellXfs':
87 | $needsRewind = true;
88 | break;
89 | }
90 | }
91 | }
92 | if ($needsRewind) {
93 | $xml->close();
94 | $xml = parent::createXMLReader();
95 | }
96 |
97 | return $xml;
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/Xlsx/StylesLoader.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class StylesLoader
13 | {
14 | /**
15 | * @var string
16 | */
17 | protected $class;
18 |
19 | /**
20 | * Constructor
21 | *
22 | * @param string $class The class for created objects
23 | */
24 | public function __construct($class)
25 | {
26 | $this->class = $class;
27 | }
28 |
29 | /**
30 | * Creates a Styles from the archive
31 | *
32 | * @param string $path
33 | * @param Archive $archive The Archive from which the path was extracted
34 | *
35 | * @return Styles
36 | */
37 | public function open($path, Archive $archive)
38 | {
39 | return new $this->class($path, $archive);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Xlsx/ValueTransformer.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class ValueTransformer
13 | {
14 | /**
15 | * @var DateTransformer
16 | */
17 | protected $dateTransformer;
18 |
19 | /**
20 | * @var SharedStrings
21 | */
22 | protected $sharedStrings;
23 |
24 | /**
25 | * @var Styles
26 | */
27 | protected $styles;
28 |
29 | /**
30 | * @staticvar string Boolean type
31 | */
32 | const TYPE_BOOL = 'b';
33 |
34 | /**
35 | * @staticvar string Number type
36 | */
37 | const TYPE_NUMBER = 'n';
38 |
39 | /**
40 | * @staticvar string Error type
41 | */
42 | const TYPE_ERROR = 'e';
43 |
44 | /**
45 | * @staticvar string Shared string type
46 | */
47 | const TYPE_SHARED_STRING = 's';
48 |
49 | /**
50 | * @staticvar string String type
51 | */
52 | const TYPE_STRING = 'str';
53 |
54 | /**
55 | * @staticvar string Inline string type
56 | */
57 | const TYPE_INLINE_STRING = 'inlineStr';
58 |
59 | /**
60 | * Constructor
61 | *
62 | * @param DateTransformer $dateTransformer
63 | * @param SharedStrings $sharedStrings
64 | * @param Styles $styles
65 | */
66 | public function __construct(DateTransformer $dateTransformer, SharedStrings $sharedStrings, Styles $styles)
67 | {
68 | $this->dateTransformer = $dateTransformer;
69 | $this->sharedStrings = $sharedStrings;
70 | $this->styles = $styles;
71 | }
72 |
73 | /**
74 | * Formats a value
75 | *
76 | * @param string $value The value which should be transformed
77 | * @param string $type The type of the value
78 | * @param string $style The style of the value
79 | *
80 | * @return mixed
81 | */
82 | public function transform($value, $type, $style)
83 | {
84 | switch ($type) {
85 | case static::TYPE_BOOL:
86 | return ('1' === $value);
87 | case static::TYPE_SHARED_STRING:
88 | return rtrim($this->sharedStrings->get($value));
89 | case '':
90 | case static::TYPE_NUMBER:
91 | return $style && (Styles::FORMAT_DATE === $this->styles->get($style))
92 | ? $this->dateTransformer->transform($value)
93 | : $value * 1;
94 | default:
95 | return rtrim($value);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/Xlsx/ValueTransformerFactory.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class ValueTransformerFactory
13 | {
14 | /**
15 | *
16 | * @var string
17 | */
18 | protected $transformerClass;
19 |
20 | /**
21 | *
22 | * @var DateTransformer
23 | */
24 | protected $dateTransformer;
25 |
26 | /**
27 | * Constructor
28 | *
29 | * @param DateTransformer $dateTransformer
30 | * @param string $transformerClass The class of the created objects
31 | */
32 | public function __construct(DateTransformer $dateTransformer, $transformerClass)
33 | {
34 | $this->dateTransformer = $dateTransformer;
35 | $this->transformerClass = $transformerClass;
36 | }
37 |
38 | /**
39 | * Creates a value transformer
40 | *
41 | * @param SharedStrings $sharedStrings
42 | * @param Styles $styles
43 | *
44 | * @return ValueTransformer
45 | */
46 | public function create(SharedStrings $sharedStrings, Styles $styles)
47 | {
48 | return new $this->transformerClass($this->dateTransformer, $sharedStrings, $styles);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Xlsx/WorksheetListReader.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class WorksheetListReader
13 | {
14 | /**
15 | * Returns the list of worksheets inside the archive
16 | *
17 | * The keys of the array should be the titles of the worksheets
18 | * The values of the array are the names of the XML worksheet files inside the archive
19 | *
20 | * @param Relationships $relationships
21 | * @param string $path
22 | *
23 | * @return array
24 | */
25 | public function getWorksheetPaths(Relationships $relationships, $path)
26 | {
27 | $xml = new \XMLReader();
28 | $xml->open($path);
29 | $paths = [];
30 | while ($xml->read()) {
31 | if (\XMLReader::ELEMENT === $xml->nodeType && 'sheet' === $xml->name) {
32 | $rId = $xml->getAttributeNs(
33 | 'id',
34 | 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
35 | );
36 | $paths[$xml->getAttribute('name')] = $relationships->getWorksheetPath($rId);
37 | }
38 | }
39 |
40 | return $paths;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Xlsx/XlsxParser.php:
--------------------------------------------------------------------------------
1 |
9 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
10 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
11 | */
12 | class XlsxParser
13 | {
14 | /**
15 | * @staticvar string the name of the format
16 | */
17 | const FORMAT_NAME = 'xlsx';
18 |
19 | /**
20 | * @staticvar string the name of the macro format
21 | */
22 | const MACRO_FORMAT_NAME = 'xlsm';
23 |
24 | /**
25 | * @staticvar string Archive class
26 | */
27 | const ARCHIVE_CLASS = 'Akeneo\Component\SpreadsheetParser\Xlsx\Archive';
28 |
29 | /**
30 | * @staticvar string Relationships class
31 | */
32 | const RELATIONSHIPS_CLASS = 'Akeneo\Component\SpreadsheetParser\Xlsx\Relationships';
33 |
34 | /**
35 | * @staticvar string RowBuilder class
36 | */
37 | const ROW_BUILDER_CLASS = 'Akeneo\Component\SpreadsheetParser\Xlsx\RowBuilder';
38 |
39 | /**
40 | * @staticvar string RowIterator class
41 | */
42 | const ROW_ITERATOR_CLASS = 'Akeneo\Component\SpreadsheetParser\Xlsx\RowIterator';
43 |
44 | /**
45 | * @staticvar string SharedStrings class
46 | */
47 | const SHARED_STRINGS_CLASS = 'Akeneo\Component\SpreadsheetParser\Xlsx\SharedStrings';
48 |
49 | /**
50 | * @staticvar string Styles class
51 | */
52 | const STYLES_CLASS = 'Akeneo\Component\SpreadsheetParser\Xlsx\Styles';
53 |
54 | /**
55 | * @staticvar string ValueTransformer class
56 | */
57 | const VALUE_TRANSFORMER_CLASS = 'Akeneo\Component\SpreadsheetParser\Xlsx\ValueTransformer';
58 |
59 | /**
60 | * @staticvar string Spreadsheet class
61 | */
62 | const WORKBOOK_CLASS = 'Akeneo\Component\SpreadsheetParser\Xlsx\Spreadsheet';
63 |
64 | /**
65 | * @var SpreadsheetLoader
66 | */
67 | private static $spreadsheetLoader;
68 |
69 | /**
70 | * Opens an XLSX file
71 | *
72 | * @param string $path
73 | *
74 | * @return Spreadsheet
75 | */
76 | public static function open($path)
77 | {
78 | return static::getSpreadsheetLoader()->open($path);
79 | }
80 |
81 | /**
82 | * @return SpreadsheetLoader
83 | */
84 | public static function getSpreadsheetLoader()
85 | {
86 | if (!isset(self::$spreadsheetLoader)) {
87 | self::$spreadsheetLoader = new SpreadsheetLoader(
88 | static::createArchiveLoader(),
89 | static::createRelationshipsLoader(),
90 | static::createSharedStringsLoader(),
91 | static::createStylesLoader(),
92 | static::createWorksheetListReader(),
93 | static::createValueTransformerFactory(),
94 | static::createRowIteratorFactory(),
95 | static::WORKBOOK_CLASS
96 | );
97 | }
98 |
99 | return self::$spreadsheetLoader;
100 | }
101 |
102 | /**
103 | * @return ArchiveLoader
104 | */
105 | protected static function createArchiveLoader()
106 | {
107 | return new ArchiveLoader(static::ARCHIVE_CLASS);
108 | }
109 |
110 | /**
111 | * @return RelationshipsLoader
112 | */
113 | protected static function createRelationshipsLoader()
114 | {
115 | return new RelationshipsLoader(static::RELATIONSHIPS_CLASS);
116 | }
117 |
118 | /**
119 | * @return SharedStringsLoader
120 | */
121 | protected static function createSharedStringsLoader()
122 | {
123 | return new SharedStringsLoader(static::SHARED_STRINGS_CLASS);
124 | }
125 |
126 | /**
127 | * @return StylesLoader
128 | */
129 | protected static function createStylesLoader()
130 | {
131 | return new StylesLoader(static::STYLES_CLASS);
132 | }
133 |
134 | /**
135 | * @return WorksheetListReader
136 | */
137 | protected static function createWorksheetListReader()
138 | {
139 | return new WorksheetListReader();
140 | }
141 |
142 | /**
143 | * @return ValueTransformerFactory
144 | */
145 | protected static function createValueTransformerFactory()
146 | {
147 | return new ValueTransformerFactory(static::createDateTransformer(), static::VALUE_TRANSFORMER_CLASS);
148 | }
149 |
150 | /**
151 | * @return DateTransformer
152 | */
153 | protected static function createDateTransformer()
154 | {
155 | return new DateTransformer();
156 | }
157 |
158 | /**
159 | * @return RowBuilderFactory
160 | */
161 | protected static function createRowBuilderFactory()
162 | {
163 | return new RowBuilderFactory(static::ROW_BUILDER_CLASS);
164 | }
165 |
166 | /**
167 | * @return ColumnIndexTransformer
168 | */
169 | protected static function createColumnIndexTransformer()
170 | {
171 | return new ColumnIndexTransformer();
172 | }
173 |
174 | /**
175 | * @return RowIteratorFactory
176 | */
177 | protected static function createRowIteratorFactory()
178 | {
179 | return new RowIteratorFactory(
180 | static::createRowBuilderFactory(),
181 | static::createColumnIndexTransformer(),
182 | static::ROW_ITERATOR_CLASS
183 | );
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/tests/CsvTest.php:
--------------------------------------------------------------------------------
1 |
11 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
13 | */
14 | class CsvTest extends TestCase
15 | {
16 | public function testReadFile()
17 | {
18 | $spreadsheet = SpreadsheetParser::open(__DIR__ . '/fixtures/test.csv');
19 | $this->assertEquals(['default'], $spreadsheet->getWorksheets());
20 | $this->assertIteratesThrough(
21 | [
22 | 1 => ['value', 'enclosed value', '15'],
23 | 2 => ['', 'value2', '']
24 | ],
25 | $spreadsheet->createRowIterator(0)
26 | );
27 | }
28 |
29 | public function testReadFileWithForcedFormat()
30 | {
31 | $spreadsheet = SpreadsheetParser::open(__DIR__ . '/fixtures/test.txt', CsvParser::FORMAT_NAME);
32 | $this->assertEquals(['default'], $spreadsheet->getWorksheets());
33 | $this->assertIteratesThrough(
34 | [
35 | 1 => ['value', 'enclosed value', '15'],
36 | 2 => ['', 'value2', '']
37 | ],
38 | $spreadsheet->createRowIterator(0)
39 | );
40 | }
41 |
42 | public function testCsvParserClass()
43 | {
44 | $spreadsheet = CsvParser::open(__DIR__ . '/fixtures/test.txt');
45 | $this->assertIteratesThrough(
46 | [
47 | 1 => ['value', 'enclosed value', '15'],
48 | 2 => ['', 'value2', '']
49 | ],
50 | $spreadsheet->createRowIterator(0)
51 | );
52 | }
53 |
54 | protected function assertIteratesThrough($values, $iterator)
55 | {
56 | $valuesIterator = new ArrayIterator($values);
57 | $valuesIterator->rewind();
58 | foreach ($iterator as $key => $row) {
59 | $this->assertTrue($valuesIterator->valid());
60 | $this->assertEquals($valuesIterator->key(), $key);
61 | $this->assertEquals($valuesIterator->current(), $row);
62 | $valuesIterator->next();
63 | }
64 | $this->assertFalse($valuesIterator->valid());
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/XlsxTest.php:
--------------------------------------------------------------------------------
1 |
11 | * @copyright 2014 Akeneo SAS (http://www.akeneo.com)
12 | * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
13 | */
14 | class XlsxTest extends TestCase
15 | {
16 | public function testLibreOfficeFile()
17 | {
18 | $spreadsheet = SpreadsheetParser::open(__DIR__ . '/fixtures/libreoffice.xlsx');
19 | $this->assertEquals(['Sheet1', 'Sheet2'], $spreadsheet->getWorksheets());
20 | $this->assertIteratesThrough(
21 | [
22 | 2 => ['value1', '', 'value2'],
23 | 3 => ['value3', '2010-12-05 00:00', 154],
24 | 5 => ['test', '2006-08-12 15:46']
25 | ],
26 | $spreadsheet->createRowIterator(0)
27 | );
28 | $this->assertIteratesThrough(
29 | [
30 | 4 => ['value7', '', 'value11']
31 | ],
32 | $spreadsheet->createRowIterator(1)
33 | );
34 | }
35 |
36 | public function testXlsParserClass()
37 | {
38 | $spreadsheet = XlsxParser::open(__DIR__ . '/fixtures/libreoffice.xlsx');
39 | $this->assertEquals(['Sheet1', 'Sheet2'], $spreadsheet->getWorksheets());
40 | $this->assertIteratesThrough(
41 | [
42 | 2 => ['value1', '', 'value2'],
43 | 3 => ['value3', '2010-12-05 00:00', 154],
44 | 5 => ['test', '2006-08-12 15:46']
45 | ],
46 | $spreadsheet->createRowIterator(0)
47 | );
48 | $this->assertIteratesThrough(
49 | [
50 | 4 => ['value7', '', 'value11']
51 | ],
52 | $spreadsheet->createRowIterator(1)
53 | );
54 | }
55 |
56 | public function testReadSameFileTwice()
57 | {
58 | $spreadsheet = SpreadsheetParser::open(__DIR__ . '/fixtures/libreoffice.xlsx');
59 | $this->assertEquals(['Sheet1', 'Sheet2'], $spreadsheet->getWorksheets());
60 | $this->assertIteratesThrough(
61 | [
62 | 2 => ['value1', '', 'value2'],
63 | 3 => ['value3', '2010-12-05 00:00', 154],
64 | 5 => ['test', '2006-08-12 15:46']
65 | ],
66 | $spreadsheet->createRowIterator(0)
67 | );
68 | $this->assertIteratesThrough(
69 | [
70 | 2 => ['value1', '', 'value2'],
71 | 3 => ['value3', '2010-12-05 00:00', 154],
72 | 5 => ['test', '2006-08-12 15:46']
73 | ],
74 | $spreadsheet->createRowIterator(0)
75 | );
76 | }
77 |
78 | public function testMsOfficeFile()
79 | {
80 | $spreadsheet = SpreadsheetParser::open(__DIR__ . '/fixtures/msoffice.xlsx');
81 | $this->assertEquals(['Feuil1', 'Feuil2', 'Feuil3'], $spreadsheet->getWorksheets());
82 | $this->assertIteratesThrough(
83 | [
84 | 3 => ['value1', '', '2014-12-15 00:00', '2015-01-15 12:16'],
85 | 5 => ['', 'value5']
86 | ],
87 | $spreadsheet->createRowIterator(0)
88 | );
89 | $this->assertIteratesThrough(
90 | [
91 | 6 => ['', 'test1'],
92 | ],
93 | $spreadsheet->createRowIterator(1)
94 | );
95 | $this->assertIteratesThrough(
96 | [
97 | 1 => ['', '', '', 'test4'],
98 | ],
99 | $spreadsheet->createRowIterator(2)
100 | );
101 | }
102 |
103 | public function testMacroMsOfficeFile()
104 | {
105 | $spreadsheet = SpreadsheetParser::open(__DIR__ . '/fixtures/msoffice.xlsm');
106 | $this->assertEquals(['Feuil1', 'Feuil2', 'Feuil3'], $spreadsheet->getWorksheets());
107 | $this->assertIteratesThrough(
108 | [
109 | 3 => ['value1', '', '2014-12-15 00:00', '2015-01-15 12:16'],
110 | 5 => ['', 'value5']
111 | ],
112 | $spreadsheet->createRowIterator(0)
113 | );
114 | $this->assertIteratesThrough(
115 | [
116 | 6 => ['', 'test1'],
117 | ],
118 | $spreadsheet->createRowIterator(1)
119 | );
120 | $this->assertIteratesThrough(
121 | [
122 | 1 => ['', '', '', 'test4'],
123 | ],
124 | $spreadsheet->createRowIterator(2)
125 | );
126 | }
127 |
128 |
129 | protected function assertIteratesThrough($values, $iterator)
130 | {
131 | $valuesIterator = new ArrayIterator($values);
132 | $valuesIterator->rewind();
133 | foreach ($iterator as $key => $row) {
134 | foreach ($row as &$value) {
135 | if ($value instanceof DateTime) {
136 | $value = $value->format('Y-m-d H:i');
137 | }
138 | }
139 | $this->assertTrue($valuesIterator->valid());
140 | $this->assertEquals($valuesIterator->key(), $key);
141 | $this->assertEquals($valuesIterator->current(), $row);
142 | $valuesIterator->next();
143 | }
144 | $this->assertFalse($valuesIterator->valid());
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/tests/fixtures/libreoffice.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akeneo-labs/spreadsheet-parser/4be5fdae57363819dcd80e84ae875c6402213b1b/tests/fixtures/libreoffice.xlsx
--------------------------------------------------------------------------------
/tests/fixtures/msoffice.xlsm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akeneo-labs/spreadsheet-parser/4be5fdae57363819dcd80e84ae875c6402213b1b/tests/fixtures/msoffice.xlsm
--------------------------------------------------------------------------------
/tests/fixtures/msoffice.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akeneo-labs/spreadsheet-parser/4be5fdae57363819dcd80e84ae875c6402213b1b/tests/fixtures/msoffice.xlsx
--------------------------------------------------------------------------------
/tests/fixtures/test.csv:
--------------------------------------------------------------------------------
1 | value,"enclosed value",15
2 | ,value2,
--------------------------------------------------------------------------------
/tests/fixtures/test.txt:
--------------------------------------------------------------------------------
1 | value,"enclosed value",15
2 | ,value2,
--------------------------------------------------------------------------------