diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ce201f8bb6..7b74162561 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -9,4 +9,4 @@ Fixes # (issue) - [ ] My CI is :green_circle: - [ ] I have covered by unit tests my new code (check build/coverage for coverage report) - [ ] I have updated the [documentation](https://github.com/PHPOffice/PHPWord/tree/master/docs) to describe the changes -- [ ] I have updated the [changelog](https://github.com/PHPOffice/PHPWord/blob/master/docs/changes/2.x/2.0.0.md) +- [ ] I have updated the [changelog](https://github.com/PHPOffice/PHPWord/blob/master/docs/changes/1.x/1.4.0.md) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index ed772171e7..0e2e9ea96d 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -1,165 +1,124 @@ -name: CI -on: - pull_request: - push: - branches: - - master +name: PHPWord +on: [push, pull_request] jobs: - test: + php-cs-fixer: + name: PHP CS Fixer runs-on: ubuntu-latest - strategy: - matrix: - php-version: - - "7.1.3" - - "7.2" - - "7.3" - - "7.4" - - "8.0" - - "8.1" - - "8.2" - - "8.3" - - name: PHP ${{ matrix.php-version }} - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup PHP, with composer and extensions + - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-version }} - extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: none - - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Remove lock for old EOL PHP versions - if: matrix.php-version == '7.1.3' || matrix.php-version == '7.2' || matrix.php-version == '7.3' || matrix.php-version == '7.4' - run: rm composer.lock && composer config platform.php ${{ matrix.php-version }} + php-version: '8.3' + extensions: mbstring, intl, gd, xml, dom, json, fileinfo, curl, zip, iconv + - uses: actions/checkout@v2 - - name: Install dependencies - run: composer install --no-progress --prefer-dist --optimize-autoloader + - name: Validate composer config + run: composer validate --strict - - name: Setup problem matchers for PHP - run: echo "::add-matcher::${{ runner.tool_cache }}/php.json" + - name: Composer Install + run: composer global require friendsofphp/php-cs-fixer - - name: Setup problem matchers for PHPUnit - run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Add environment path + run: export PATH="$PATH:$HOME/.composer/vendor/bin" - - name: Configure matchers - uses: mheap/phpunit-matcher-action@v1 + - name: Run PHPCSFixer + run: php-cs-fixer fix --dry-run --diff - - name: Test with PHPUnit - run: ./vendor/bin/phpunit --no-coverage - - php-cs-fixer: + phpmd: + name: PHP Mess Detector runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v3 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: gd, xml, zip + - uses: actions/checkout@v2 - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: 8.0 - extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: none - tools: cs2pr + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Install dependencies - run: composer install --no-progress --prefer-dist --optimize-autoloader - - - name: Code style with PHP-CS-Fixer - run: ./vendor/bin/php-cs-fixer fix --dry-run --diff + - name: Run phpmd + run: ./vendor/bin/phpmd src/,tests/ text ./phpmd.xml.dist --exclude "src/PhpWord/Shared/PCLZip/*" phpstan: + name: PHP Static Analysis runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # Disabled PHPStan in '7.1' + php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] steps: - - name: Checkout - uses: actions/checkout@v3 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: gd, xml, zip + - uses: actions/checkout@v2 - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: 8.0 - extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: none - tools: cs2pr + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- + - name: Run phpstan + run: ./vendor/bin/phpstan analyse -c phpstan.neon.dist - - name: Install dependencies - run: composer install --no-progress --prefer-dist --optimize-autoloader - - - name: Static analysis with PHPStan - run: ./vendor/bin/phpstan analyse - - coverage: + phpunit: + name: PHPUnit ${{ matrix.php }} runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: gd, xml, zip + coverage: ${{ (matrix.php == '7.3') && 'xdebug' || 'none' }} + + - uses: actions/checkout@v2 + + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress + + - name: Run phpunit + if: matrix.php != '7.3' + run: ./vendor/bin/phpunit -c phpunit.xml.dist --no-coverage + + - name: Run phpunit + if: matrix.php == '7.3' + run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml + + - name: Upload coverage results to Coveralls + if: matrix.php == '7.3' + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar + chmod +x php-coveralls.phar + php php-coveralls.phar --coverage_clover=build/clover.xml --json_path=build/coveralls-upload.json -vvv + + samples: + name: Check samples + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] + steps: + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: gd, xml, zip + coverage: xdebug - - name: Setup PHP, with composer and extensions - uses: shivammathur/setup-php@v2 - with: - php-version: 8.1 - extensions: ctype, dom, gd, iconv, fileinfo, libxml, mbstring, simplexml, xml, xmlreader, xmlwriter, zip, zlib - coverage: xdebug + - uses: actions/checkout@v2 - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Composer Install + run: composer install --ansi --prefer-dist --no-interaction --no-progress - - name: Cache composer dependencies - uses: actions/cache@v3 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: ${{ runner.os }}-composer- - - - name: Install dependencies - run: composer install --no-progress --prefer-dist --optimize-autoloader - - - name: Run phpunit - run: ./vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/clover.xml - - - name: Upload coverage results to Coveralls - env: - COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.4.3/php-coveralls.phar - chmod +x php-coveralls.phar - php php-coveralls.phar --coverage_clover=build/clover.xml --json_path=build/coveralls-upload.json -vvv + - name: Generate samples files + run: composer run samples diff --git a/.gitignore b/.gitignore index 3695438057..0b9d0608d0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +/composer.lock + + .DS_Store ._* .Spotlight-V100 diff --git a/LICENSE b/LICENSE index 8a1acaeaba..aebd12b0ed 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ PHPWord, a pure PHP library for reading and writing word processing documents. -Copyright (c) 2010-2016 PHPWord. +Copyright (c) 2010-2025 PHPWord. PHPWord is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 as published by diff --git a/README.md b/README.md index 11bcd1525c..e080d32da8 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # ![PHPWord](https://rawgit.com/PHPOffice/PHPWord/develop/docs/images/phpword.svg "PHPWord") -[![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v/stable.png)](https://packagist.org/packages/phpoffice/phpword) +[![Latest Stable Version](https://poser.pugx.org/phpoffice/phpword/v)](https://packagist.org/packages/phpoffice/phpword) [![Coverage Status](https://coveralls.io/repos/github/PHPOffice/PHPWord/badge.svg?branch=master)](https://coveralls.io/github/PHPOffice/PHPWord?branch=master) -[![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads.png)](https://packagist.org/packages/phpoffice/phpword) -[![License](https://poser.pugx.org/phpoffice/phpword/license.png)](https://packagist.org/packages/phpoffice/phpword) -[![CI](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml/badge.svg)](https://github.com/PHPOffice/PHPWord/actions/workflows/ci.yml) -[![Join the chat at https://gitter.im/PHPOffice/PHPWord](https://img.shields.io/badge/GITTER-join%20chat-green.svg)](https://gitter.im/PHPOffice/PHPWord) +[![Total Downloads](https://poser.pugx.org/phpoffice/phpword/downloads)](https://packagist.org/packages/phpoffice/phpword) +[![License](https://poser.pugx.org/phpoffice/phpword/license)](https://packagist.org/packages/phpoffice/phpword) + +Branch Master : [![PHPWord](https://github.com/PHPOffice/PHPWord/actions/workflows/php.yml/badge.svg?branch=master)](https://github.com/PHPOffice/PHPWord/actions/workflows/php.yml) PHPWord is a library written in pure PHP that provides a set of classes to write to and read from different document file formats. The current version of PHPWord supports Microsoft [Office Open XML](http://en.wikipedia.org/wiki/Office_Open_XML) (OOXML or OpenXML), OASIS [Open Document Format for Office Applications](http://en.wikipedia.org/wiki/OpenDocument) (OpenDocument or ODF), [Rich Text Format](http://en.wikipedia.org/wiki/Rich_Text_Format) (RTF), HTML, and PDF. @@ -81,7 +81,6 @@ The following is a basic usage example of the PHPWord library. ```php =7.0", - "tecnickcom/tcpdf": "^6.5", "symfony/process": "^4.4 || ^5.0", - "friendsofphp/php-cs-fixer": "^3.3", - "phpstan/phpstan-phpunit": "@stable" + "tecnickcom/tcpdf": "^6.5" }, "suggest": { - "ext-zip": "Allows writing OOXML and ODF", - "ext-gd2": "Allows adding images", "ext-xmlwriter": "Allows writing OOXML and ODF", "ext-xsl": "Allows applying XSL style sheet to headers, to main document part, and to footers of an OOXML template", "dompdf/dompdf": "Allows writing PDF" diff --git a/composer.lock b/composer.lock deleted file mode 100644 index d6b3ee35d8..0000000000 --- a/composer.lock +++ /dev/null @@ -1,5090 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "15c1d733e1ddd2f424af0383ceb28dfd", - "packages": [ - { - "name": "phpoffice/math", - "version": "0.2.0", - "source": { - "type": "git", - "url": "https://github.com/PHPOffice/Math.git", - "reference": "fc2eb6d1a61b058d5dac77197059db30ee3c8329" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPOffice/Math/zipball/fc2eb6d1a61b058d5dac77197059db30ee3c8329", - "reference": "fc2eb6d1a61b058d5dac77197059db30ee3c8329", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xml": "*", - "php": "^7.1|^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^0.12.88 || ^1.0.0", - "phpunit/phpunit": "^7.0 || ^9.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "PhpOffice\\Math\\": "src/Math/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Progi1984", - "homepage": "https://lefevre.dev" - } - ], - "description": "Math - Manipulate Math Formula", - "homepage": "https://phpoffice.github.io/Math/", - "keywords": [ - "MathML", - "officemathml", - "php" - ], - "support": { - "issues": "https://github.com/PHPOffice/Math/issues", - "source": "https://github.com/PHPOffice/Math/tree/0.2.0" - }, - "time": "2024-08-12T07:30:45+00:00" - } - ], - "packages-dev": [ - { - "name": "composer/pcre", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/composer/pcre.git", - "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", - "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Pcre\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "PCRE wrapping library that offers type-safe preg_* replacements.", - "keywords": [ - "PCRE", - "preg", - "regex", - "regular expression" - ], - "support": { - "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/1.0.1" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-01-21T20:24:37+00:00" - }, - { - "name": "composer/semver", - "version": "3.3.2", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.3.2" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-04-01T19:23:25+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "2.0.5", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", - "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", - "shasum": "" - }, - "require": { - "composer/pcre": "^1", - "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1 || ^2 || ^3" - }, - "require-dev": { - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without Xdebug.", - "keywords": [ - "Xdebug", - "performance" - ], - "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/2.0.5" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2022-02-24T20:20:32+00:00" - }, - { - "name": "doctrine/annotations", - "version": "1.14.3", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", - "reference": "fb0d71a7393298a7b232cbf4c8b1f73f3ec3d5af", - "shasum": "" - }, - "require": { - "doctrine/lexer": "^1 || ^2", - "ext-tokenizer": "*", - "php": "^7.1 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" - }, - "require-dev": { - "doctrine/cache": "^1.11 || ^2.0", - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "~1.4.10 || ^1.8.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "vimeo/psalm": "^4.10" - }, - "suggest": { - "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.14.3" - }, - "time": "2023-02-01T09:20:38+00:00" - }, - { - "name": "doctrine/deprecations", - "version": "v1.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "8cffffb2218e01f3b370bf763e00e81697725259" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/8cffffb2218e01f3b370bf763e00e81697725259", - "reference": "8cffffb2218e01f3b370bf763e00e81697725259", - "shasum": "" - }, - "require": { - "php": "^7.1|^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5|^8.5|^9.5", - "psr/log": "^1|^2|^3" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/v1.1.0" - }, - "time": "2023-05-29T18:55:17+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", - "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^11", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.30 || ^5.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "https://ocramius.github.io/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "support": { - "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.5.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2022-12-30T00:15:36+00:00" - }, - { - "name": "doctrine/lexer", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "reference": "39ab8fcf5a51ce4b85ca97c7a7d033eb12831124", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^10", - "phpstan/phpstan": "^1.3", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "^0.18.3", - "vimeo/psalm": "^4.11 || ^5.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Lexer\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "https://www.doctrine-project.org/projects/lexer.html", - "keywords": [ - "annotations", - "docblock", - "lexer", - "parser", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/2.1.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", - "type": "tidelift" - } - ], - "time": "2022-12-14T08:49:07+00:00" - }, - { - "name": "dompdf/dompdf", - "version": "v2.0.4", - "source": { - "type": "git", - "url": "https://github.com/dompdf/dompdf.git", - "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/093f2d9739cec57428e39ddadedfd4f3ae862c0f", - "reference": "093f2d9739cec57428e39ddadedfd4f3ae862c0f", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-mbstring": "*", - "masterminds/html5": "^2.0", - "phenx/php-font-lib": ">=0.5.4 <1.0.0", - "phenx/php-svg-lib": ">=0.3.3 <1.0.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "ext-json": "*", - "ext-zip": "*", - "mockery/mockery": "^1.3", - "phpunit/phpunit": "^7.5 || ^8 || ^9", - "squizlabs/php_codesniffer": "^3.5" - }, - "suggest": { - "ext-gd": "Needed to process images", - "ext-gmagick": "Improves image processing performance", - "ext-imagick": "Improves image processing performance", - "ext-zlib": "Needed for pdf stream compression" - }, - "type": "library", - "autoload": { - "psr-4": { - "Dompdf\\": "src/" - }, - "classmap": [ - "lib/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1" - ], - "authors": [ - { - "name": "The Dompdf Community", - "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" - } - ], - "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", - "homepage": "https://github.com/dompdf/dompdf", - "support": { - "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v2.0.4" - }, - "time": "2023-12-12T20:19:39+00:00" - }, - { - "name": "friendsofphp/php-cs-fixer", - "version": "v3.4.0", - "source": { - "type": "git", - "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", - "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", - "shasum": "" - }, - "require": { - "composer/semver": "^3.2", - "composer/xdebug-handler": "^2.0", - "doctrine/annotations": "^1.12", - "ext-json": "*", - "ext-tokenizer": "*", - "php": "^7.2.5 || ^8.0", - "php-cs-fixer/diff": "^2.0", - "symfony/console": "^4.4.20 || ^5.1.3 || ^6.0", - "symfony/event-dispatcher": "^4.4.20 || ^5.0 || ^6.0", - "symfony/filesystem": "^4.4.20 || ^5.0 || ^6.0", - "symfony/finder": "^4.4.20 || ^5.0 || ^6.0", - "symfony/options-resolver": "^4.4.20 || ^5.0 || ^6.0", - "symfony/polyfill-mbstring": "^1.23", - "symfony/polyfill-php80": "^1.23", - "symfony/polyfill-php81": "^1.23", - "symfony/process": "^4.4.20 || ^5.0 || ^6.0", - "symfony/stopwatch": "^4.4.20 || ^5.0 || ^6.0" - }, - "require-dev": { - "justinrainbow/json-schema": "^5.2", - "keradus/cli-executor": "^1.5", - "mikey179/vfsstream": "^1.6.8", - "php-coveralls/php-coveralls": "^2.5.2", - "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", - "phpspec/prophecy": "^1.15", - "phpspec/prophecy-phpunit": "^1.1 || ^2.0", - "phpunit/phpunit": "^8.5.21 || ^9.5", - "phpunitgoodpractices/polyfill": "^1.5", - "phpunitgoodpractices/traits": "^1.9.1", - "symfony/phpunit-bridge": "^5.2.4 || ^6.0", - "symfony/yaml": "^4.4.20 || ^5.0 || ^6.0" - }, - "suggest": { - "ext-dom": "For handling output formats in XML", - "ext-mbstring": "For handling non-UTF8 characters." - }, - "bin": [ - "php-cs-fixer" - ], - "type": "application", - "autoload": { - "psr-4": { - "PhpCsFixer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" - } - ], - "description": "A tool to automatically fix PHP code style", - "support": { - "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.4.0" - }, - "funding": [ - { - "url": "https://github.com/keradus", - "type": "github" - } - ], - "time": "2021-12-11T16:25:08+00:00" - }, - { - "name": "masterminds/html5", - "version": "2.8.1", - "source": { - "type": "git", - "url": "https://github.com/Masterminds/html5-php.git", - "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f47dcf3c70c584de14f21143c55d9939631bc6cf", - "reference": "f47dcf3c70c584de14f21143c55d9939631bc6cf", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.7-dev" - } - }, - "autoload": { - "psr-4": { - "Masterminds\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matt Butcher", - "email": "technosophos@gmail.com" - }, - { - "name": "Matt Farina", - "email": "matt@mattfarina.com" - }, - { - "name": "Asmir Mustafic", - "email": "goetas@gmail.com" - } - ], - "description": "An HTML5 parser and serializer.", - "homepage": "http://masterminds.github.io/html5-php", - "keywords": [ - "HTML5", - "dom", - "html", - "parser", - "querypath", - "serializer", - "xml" - ], - "support": { - "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.8.1" - }, - "time": "2023-05-10T11:58:31+00:00" - }, - { - "name": "mpdf/mpdf", - "version": "v8.2.4", - "source": { - "type": "git", - "url": "https://github.com/mpdf/mpdf.git", - "reference": "9e3ff91606fed11cd58a130eabaaf60e56fdda88" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mpdf/mpdf/zipball/9e3ff91606fed11cd58a130eabaaf60e56fdda88", - "reference": "9e3ff91606fed11cd58a130eabaaf60e56fdda88", - "shasum": "" - }, - "require": { - "ext-gd": "*", - "ext-mbstring": "*", - "mpdf/psr-http-message-shim": "^1.0 || ^2.0", - "mpdf/psr-log-aware-trait": "^2.0 || ^3.0", - "myclabs/deep-copy": "^1.7", - "paragonie/random_compat": "^1.4|^2.0|^9.99.99", - "php": "^5.6 || ^7.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", - "psr/http-message": "^1.0 || ^2.0", - "psr/log": "^1.0 || ^2.0 || ^3.0", - "setasign/fpdi": "^2.1" - }, - "require-dev": { - "mockery/mockery": "^1.3.0", - "mpdf/qrcode": "^1.1.0", - "squizlabs/php_codesniffer": "^3.5.0", - "tracy/tracy": "~2.5", - "yoast/phpunit-polyfills": "^1.0" - }, - "suggest": { - "ext-bcmath": "Needed for generation of some types of barcodes", - "ext-xml": "Needed mainly for SVG manipulation", - "ext-zlib": "Needed for compression of embedded resources, such as fonts" - }, - "type": "library", - "autoload": { - "files": [ - "src/functions.php" - ], - "psr-4": { - "Mpdf\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0-only" - ], - "authors": [ - { - "name": "Matěj Humpál", - "role": "Developer, maintainer" - }, - { - "name": "Ian Back", - "role": "Developer (retired)" - } - ], - "description": "PHP library generating PDF files from UTF-8 encoded HTML", - "homepage": "https://mpdf.github.io", - "keywords": [ - "pdf", - "php", - "utf-8" - ], - "support": { - "docs": "http://mpdf.github.io", - "issues": "https://github.com/mpdf/mpdf/issues", - "source": "https://github.com/mpdf/mpdf" - }, - "funding": [ - { - "url": "https://www.paypal.me/mpdf", - "type": "custom" - } - ], - "time": "2024-06-14T16:06:41+00:00" - }, - { - "name": "mpdf/psr-http-message-shim", - "version": "v2.0.1", - "source": { - "type": "git", - "url": "https://github.com/mpdf/psr-http-message-shim.git", - "reference": "f25a0153d645e234f9db42e5433b16d9b113920f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mpdf/psr-http-message-shim/zipball/f25a0153d645e234f9db42e5433b16d9b113920f", - "reference": "f25a0153d645e234f9db42e5433b16d9b113920f", - "shasum": "" - }, - "require": { - "psr/http-message": "^2.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Mpdf\\PsrHttpMessageShim\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mark Dorison", - "email": "mark@chromatichq.com" - }, - { - "name": "Kristofer Widholm", - "email": "kristofer@chromatichq.com" - }, - { - "name": "Nigel Cunningham", - "email": "nigel.cunningham@technocrat.com.au" - } - ], - "description": "Shim to allow support of different psr/message versions.", - "support": { - "issues": "https://github.com/mpdf/psr-http-message-shim/issues", - "source": "https://github.com/mpdf/psr-http-message-shim/tree/v2.0.1" - }, - "time": "2023-10-02T14:34:03+00:00" - }, - { - "name": "mpdf/psr-log-aware-trait", - "version": "v3.0.0", - "source": { - "type": "git", - "url": "https://github.com/mpdf/psr-log-aware-trait.git", - "reference": "a633da6065e946cc491e1c962850344bb0bf3e78" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mpdf/psr-log-aware-trait/zipball/a633da6065e946cc491e1c962850344bb0bf3e78", - "reference": "a633da6065e946cc491e1c962850344bb0bf3e78", - "shasum": "" - }, - "require": { - "psr/log": "^3.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Mpdf\\PsrLogAwareTrait\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mark Dorison", - "email": "mark@chromatichq.com" - }, - { - "name": "Kristofer Widholm", - "email": "kristofer@chromatichq.com" - } - ], - "description": "Trait to allow support of different psr/log versions.", - "support": { - "issues": "https://github.com/mpdf/psr-log-aware-trait/issues", - "source": "https://github.com/mpdf/psr-log-aware-trait/tree/v3.0.0" - }, - "time": "2023-05-03T06:19:36+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.12.0", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3 <3.2.2" - }, - "require-dev": { - "doctrine/collections": "^1.6.8", - "doctrine/common": "^2.13.3 || ^3.2.2", - "phpspec/prophecy": "^1.10", - "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" - }, - "type": "library", - "autoload": { - "files": [ - "src/DeepCopy/deep_copy.php" - ], - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "support": { - "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2024-06-12T14:39:25+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v4.18.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.0" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.9-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" - }, - "time": "2023-12-10T21:03:43+00:00" - }, - { - "name": "paragonie/random_compat", - "version": "v9.99.100", - "source": { - "type": "git", - "url": "https://github.com/paragonie/random_compat.git", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a", - "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a", - "shasum": "" - }, - "require": { - "php": ">= 7" - }, - "require-dev": { - "phpunit/phpunit": "4.*|5.*", - "vimeo/psalm": "^1" - }, - "suggest": { - "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Paragon Initiative Enterprises", - "email": "security@paragonie.com", - "homepage": "https://paragonie.com" - } - ], - "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", - "keywords": [ - "csprng", - "polyfill", - "pseudorandom", - "random" - ], - "support": { - "email": "info@paragonie.com", - "issues": "https://github.com/paragonie/random_compat/issues", - "source": "https://github.com/paragonie/random_compat" - }, - "time": "2020-10-15T08:29:30+00:00" - }, - { - "name": "pdepend/pdepend", - "version": "2.16.2", - "source": { - "type": "git", - "url": "https://github.com/pdepend/pdepend.git", - "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58", - "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58", - "shasum": "" - }, - "require": { - "php": ">=5.3.7", - "symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0", - "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0", - "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0", - "symfony/polyfill-mbstring": "^1.19" - }, - "require-dev": { - "easy-doc/easy-doc": "0.0.0|^1.2.3", - "gregwar/rst": "^1.0", - "squizlabs/php_codesniffer": "^2.0.0" - }, - "bin": [ - "src/bin/pdepend" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "PDepend\\": "src/main/php/PDepend" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "description": "Official version of pdepend to be handled with Composer", - "keywords": [ - "PHP Depend", - "PHP_Depend", - "dev", - "pdepend" - ], - "support": { - "issues": "https://github.com/pdepend/pdepend/issues", - "source": "https://github.com/pdepend/pdepend/tree/2.16.2" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend", - "type": "tidelift" - } - ], - "time": "2023-12-17T18:09:59+00:00" - }, - { - "name": "phar-io/manifest", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-phar": "*", - "ext-xmlwriter": "*", - "phar-io/version": "^3.0.1", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "support": { - "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" - }, - "time": "2021-07-20T11:28:43+00:00" - }, - { - "name": "phar-io/version", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "support": { - "issues": "https://github.com/phar-io/version/issues", - "source": "https://github.com/phar-io/version/tree/3.2.1" - }, - "time": "2022-02-21T01:04:05+00:00" - }, - { - "name": "phenx/php-font-lib", - "version": "0.5.4", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-font-lib.git", - "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/dd448ad1ce34c63d09baccd05415e361300c35b4", - "reference": "dd448ad1ce34c63d09baccd05415e361300c35b4", - "shasum": "" - }, - "require": { - "ext-mbstring": "*" - }, - "require-dev": { - "symfony/phpunit-bridge": "^3 || ^4 || ^5" - }, - "type": "library", - "autoload": { - "psr-4": { - "FontLib\\": "src/FontLib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse, export and make subsets of different types of font files.", - "homepage": "https://github.com/PhenX/php-font-lib", - "support": { - "issues": "https://github.com/dompdf/php-font-lib/issues", - "source": "https://github.com/dompdf/php-font-lib/tree/0.5.4" - }, - "time": "2021-12-17T19:44:54+00:00" - }, - { - "name": "phenx/php-svg-lib", - "version": "0.5.4", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/46b25da81613a9cf43c83b2a8c2c1bdab27df691", - "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^7.1 || ^8.0", - "sabberworm/php-css-parser": "^8.4" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Svg\\": "src/Svg" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse and export to PDF SVG files.", - "homepage": "https://github.com/PhenX/php-svg-lib", - "support": { - "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.4" - }, - "time": "2024-04-08T12:52:34+00:00" - }, - { - "name": "php-cs-fixer/diff", - "version": "v2.0.2", - "source": { - "type": "git", - "url": "https://github.com/PHP-CS-Fixer/diff.git", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", - "symfony/process": "^3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "sebastian/diff v3 backport support for PHP 5.6+", - "homepage": "https://github.com/PHP-CS-Fixer", - "keywords": [ - "diff" - ], - "support": { - "issues": "https://github.com/PHP-CS-Fixer/diff/issues", - "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" - }, - "abandoned": true, - "time": "2020-10-14T08:32:19+00:00" - }, - { - "name": "phpmd/phpmd", - "version": "2.15.0", - "source": { - "type": "git", - "url": "https://github.com/phpmd/phpmd.git", - "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0", - "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0", - "shasum": "" - }, - "require": { - "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0", - "ext-xml": "*", - "pdepend/pdepend": "^2.16.1", - "php": ">=5.3.9" - }, - "require-dev": { - "easy-doc/easy-doc": "0.0.0 || ^1.3.2", - "ext-json": "*", - "ext-simplexml": "*", - "gregwar/rst": "^1.0", - "mikey179/vfsstream": "^1.6.8", - "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2" - }, - "bin": [ - "src/bin/phpmd" - ], - "type": "library", - "autoload": { - "psr-0": { - "PHPMD\\": "src/main/php" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Manuel Pichler", - "email": "github@manuel-pichler.de", - "homepage": "https://github.com/manuelpichler", - "role": "Project Founder" - }, - { - "name": "Marc Würth", - "email": "ravage@bluewin.ch", - "homepage": "https://github.com/ravage84", - "role": "Project Maintainer" - }, - { - "name": "Other contributors", - "homepage": "https://github.com/phpmd/phpmd/graphs/contributors", - "role": "Contributors" - } - ], - "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.", - "homepage": "https://phpmd.org/", - "keywords": [ - "dev", - "mess detection", - "mess detector", - "pdepend", - "phpmd", - "pmd" - ], - "support": { - "irc": "irc://irc.freenode.org/phpmd", - "issues": "https://github.com/phpmd/phpmd/issues", - "source": "https://github.com/phpmd/phpmd/tree/2.15.0" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd", - "type": "tidelift" - } - ], - "time": "2023-12-11T08:22:20+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "1.11.10", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "640410b32995914bde3eed26fa89552f9c2c082f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/640410b32995914bde3eed26fa89552f9c2c082f", - "reference": "640410b32995914bde3eed26fa89552f9c2c082f", - "shasum": "" - }, - "require": { - "php": "^7.2|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "keywords": [ - "dev", - "static analysis" - ], - "support": { - "docs": "https://phpstan.org/user-guide/getting-started", - "forum": "https://github.com/phpstan/phpstan/discussions", - "issues": "https://github.com/phpstan/phpstan/issues", - "security": "https://github.com/phpstan/phpstan/security/policy", - "source": "https://github.com/phpstan/phpstan-src" - }, - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://github.com/phpstan", - "type": "github" - } - ], - "time": "2024-08-08T09:02:50+00:00" - }, - { - "name": "phpstan/phpstan-phpunit", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/f3ea021866f4263f07ca3636bf22c64be9610c11", - "reference": "f3ea021866f4263f07ca3636bf22c64be9610c11", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.11" - }, - "conflict": { - "phpunit/phpunit": "<7.0" - }, - "require-dev": { - "nikic/php-parser": "^4.13.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-strict-rules": "^1.5.1", - "phpunit/phpunit": "^9.5" - }, - "type": "phpstan-extension", - "extra": { - "phpstan": { - "includes": [ - "extension.neon", - "rules.neon" - ] - } - }, - "autoload": { - "psr-4": { - "PHPStan\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPUnit extensions and rules for PHPStan", - "support": { - "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.0" - }, - "time": "2024-04-20T06:39:00+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "9.2.30", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-libxml": "*", - "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcov": "PHP extension that provides line coverage", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:47:57+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "3.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", - "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2021-12-02T12:48:52+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcntl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-invoker/issues", - "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:58:55+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-text-template/issues", - "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T05:33:50+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "5.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/php-timer/issues", - "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:16:10+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "9.6.15", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/05017b80304e0eb3f31d90194a563fd53a6021f1", - "reference": "05017b80304e0eb3f31d90194a563fd53a6021f1", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.3.1 || ^2", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", - "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", - "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", - "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", - "sebastian/version": "^3.0.2" - }, - "suggest": { - "ext-soap": "To be able to generate mocks based on WSDL files", - "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.6-dev" - } - }, - "autoload": { - "files": [ - "src/Framework/Assert/Functions.php" - ], - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.15" - }, - "funding": [ - { - "url": "https://phpunit.de/sponsors.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", - "type": "tidelift" - } - ], - "time": "2023-12-01T16:55:19+00:00" - }, - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" - }, - { - "name": "psr/container", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" - }, - "time": "2021-11-05T16:50:12+00:00" - }, - { - "name": "psr/event-dispatcher", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\EventDispatcher\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Standard interfaces for event handling.", - "keywords": [ - "events", - "psr", - "psr-14" - ], - "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" - }, - "time": "2019-01-08T18:20:26+00:00" - }, - { - "name": "psr/http-message", - "version": "2.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/http-message.git", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Http\\Message\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for HTTP messages", - "homepage": "https://github.com/php-fig/http-message", - "keywords": [ - "http", - "http-message", - "psr", - "psr-7", - "request", - "response" - ], - "support": { - "source": "https://github.com/php-fig/http-message/tree/2.0" - }, - "time": "2023-04-04T09:54:51+00:00" - }, - { - "name": "psr/log", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" - }, - "time": "2021-07-14T16:46:02+00:00" - }, - { - "name": "sabberworm/php-css-parser", - "version": "v8.6.0", - "source": { - "type": "git", - "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", - "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d2fb94a9641be84d79c7548c6d39bbebba6e9a70", - "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "php": ">=5.6.20" - }, - "require-dev": { - "phpunit/phpunit": "^5.7.27" - }, - "suggest": { - "ext-mbstring": "for parsing UTF-8 CSS" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Sabberworm\\CSS\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Raphael Schweikert" - }, - { - "name": "Oliver Klee", - "email": "github@oliverklee.de" - }, - { - "name": "Jake Hotson", - "email": "jake.github@qzdesign.co.uk" - } - ], - "description": "Parser for CSS Files written in PHP", - "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", - "keywords": [ - "css", - "parser", - "stylesheet" - ], - "support": { - "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", - "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.6.0" - }, - "time": "2024-07-01T07:33:21+00:00" - }, - { - "name": "sebastian/cli-parser", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for parsing CLI options", - "homepage": "https://github.com/sebastianbergmann/cli-parser", - "support": { - "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:08:49+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", - "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit/issues", - "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:08:54+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "support": { - "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", - "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:30:19+00:00" - }, - { - "name": "sebastian/comparator", - "version": "4.0.8", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", - "reference": "fa0f136dd2334583309d32b62544682ee972b51a", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/comparator/issues", - "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2022-09-14T12:41:17+00:00" - }, - { - "name": "sebastian/complexity", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", - "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for calculating the complexity of PHP code units", - "homepage": "https://github.com/sebastianbergmann/complexity", - "support": { - "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:19:30+00:00" - }, - { - "name": "sebastian/diff", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-05-07T05:35:17+00:00" - }, - { - "name": "sebastian/environment", - "version": "5.1.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:03:51+00:00" - }, - { - "name": "sebastian/exporter", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "https://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2022-09-14T06:03:37+00:00" - }, - { - "name": "sebastian/global-state", - "version": "5.0.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bde739e7565280bda77be70044ac1047bc007e34" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", - "reference": "bde739e7565280bda77be70044ac1047bc007e34", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-08-02T09:26:13+00:00" - }, - { - "name": "sebastian/lines-of-code", - "version": "1.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", - "shasum": "" - }, - "require": { - "nikic/php-parser": "^4.18 || ^5.0", - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library for counting the lines of code in PHP source code", - "homepage": "https://github.com/sebastianbergmann/lines-of-code", - "support": { - "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-12-22T06:20:34+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", - "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", - "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:12:34+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "2.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "support": { - "issues": "https://github.com/sebastianbergmann/object-reflector/issues", - "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:14:26+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "https://github.com/sebastianbergmann/recursion-context", - "support": { - "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:07:39+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:45:17+00:00" - }, - { - "name": "sebastian/type", - "version": "3.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", - "support": { - "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2023-02-03T06:13:03+00:00" - }, - { - "name": "sebastian/version", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "support": { - "issues": "https://github.com/sebastianbergmann/version/issues", - "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:39:44+00:00" - }, - { - "name": "setasign/fpdi", - "version": "v2.6.0", - "source": { - "type": "git", - "url": "https://github.com/Setasign/FPDI.git", - "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/a6db878129ec6c7e141316ee71872923e7f1b7ad", - "reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad", - "shasum": "" - }, - "require": { - "ext-zlib": "*", - "php": "^5.6 || ^7.0 || ^8.0" - }, - "conflict": { - "setasign/tfpdf": "<1.31" - }, - "require-dev": { - "phpunit/phpunit": "~5.7", - "setasign/fpdf": "~1.8.6", - "setasign/tfpdf": "~1.33", - "squizlabs/php_codesniffer": "^3.5", - "tecnickcom/tcpdf": "~6.2" - }, - "suggest": { - "setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured." - }, - "type": "library", - "autoload": { - "psr-4": { - "setasign\\Fpdi\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Slabon", - "email": "jan.slabon@setasign.com", - "homepage": "https://www.setasign.com" - }, - { - "name": "Maximilian Kresse", - "email": "maximilian.kresse@setasign.com", - "homepage": "https://www.setasign.com" - } - ], - "description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.", - "homepage": "https://www.setasign.com/fpdi", - "keywords": [ - "fpdf", - "fpdi", - "pdf" - ], - "support": { - "issues": "https://github.com/Setasign/FPDI/issues", - "source": "https://github.com/Setasign/FPDI/tree/v2.6.0" - }, - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/setasign/fpdi", - "type": "tidelift" - } - ], - "time": "2023-12-11T16:03:32+00:00" - }, - { - "name": "symfony/config", - "version": "v5.4.31", - "source": { - "type": "git", - "url": "https://github.com/symfony/config.git", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", - "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/filesystem": "^4.4|^5.0|^6.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22" - }, - "conflict": { - "symfony/finder": "<4.4" - }, - "require-dev": { - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/finder": "^4.4|^5.0|^6.0", - "symfony/messenger": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/yaml": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/yaml": "To use the yaml reference dumper" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Config\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/config/tree/v5.4.31" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-11-09T08:22:43+00:00" - }, - { - "name": "symfony/console", - "version": "v5.3.16", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "2e322c76cdccb302af6b275ea2207169c8355328" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/2e322c76cdccb302af6b275ea2207169c8355328", - "reference": "2e322c76cdccb302af6b275ea2207169c8355328", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/polyfill-php80": "^1.16", - "symfony/service-contracts": "^1.1|^2", - "symfony/string": "^5.1" - }, - "conflict": { - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" - }, - "provide": { - "psr/log-implementation": "1.0|2.0" - }, - "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/event-dispatcher": "^4.4|^5.0", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^4.4|^5.0", - "symfony/var-dumper": "^4.4|^5.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Eases the creation of beautiful and testable command line interfaces", - "homepage": "https://symfony.com", - "keywords": [ - "cli", - "command line", - "console", - "terminal" - ], - "support": { - "source": "https://github.com/symfony/console/tree/v5.3.16" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-03-01T08:24:05+00:00" - }, - { - "name": "symfony/dependency-injection", - "version": "v5.4.34", - "source": { - "type": "git", - "url": "https://github.com/symfony/dependency-injection.git", - "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/75d568165a65fa7d8124869ec7c3a90424352e6c", - "reference": "75d568165a65fa7d8124869ec7c3a90424352e6c", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/container": "^1.1.1", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16", - "symfony/polyfill-php81": "^1.22", - "symfony/service-contracts": "^1.1.6|^2" - }, - "conflict": { - "ext-psr": "<1.1|>=2", - "symfony/config": "<5.3", - "symfony/finder": "<4.4", - "symfony/proxy-manager-bridge": "<4.4", - "symfony/yaml": "<4.4.26" - }, - "provide": { - "psr/container-implementation": "1.0", - "symfony/service-implementation": "1.0|2.0" - }, - "require-dev": { - "symfony/config": "^5.3|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/yaml": "^4.4.26|^5.0|^6.0" - }, - "suggest": { - "symfony/config": "", - "symfony/expression-language": "For using expressions in service container configuration", - "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required", - "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", - "symfony/yaml": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\DependencyInjection\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Allows you to standardize and centralize the way objects are constructed in your application", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.34" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-12-28T09:31:38+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v2.5.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-01-02T09:53:40+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v5.4.22", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1df20e45d56da29a4b1d8259dd6e950acbf1b13f", - "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/event-dispatcher-contracts": "^2|^3", - "symfony/polyfill-php80": "^1.16" - }, - "conflict": { - "symfony/dependency-injection": "<4.4" - }, - "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0" - }, - "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/expression-language": "^4.4|^5.0|^6.0", - "symfony/http-foundation": "^4.4|^5.0|^6.0", - "symfony/service-contracts": "^1.1|^2|^3", - "symfony/stopwatch": "^4.4|^5.0|^6.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.22" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-03-17T11:31:58+00:00" - }, - { - "name": "symfony/event-dispatcher-contracts", - "version": "v2.5.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/event-dispatcher": "^1" - }, - "suggest": { - "symfony/event-dispatcher-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-01-02T09:53:40+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v5.4.25", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", - "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.25" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-31T13:04:02+00:00" - }, - { - "name": "symfony/finder", - "version": "v5.4.21", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/078e9a5e1871fcfe6a5ce421b539344c21afef19", - "reference": "078e9a5e1871fcfe6a5ce421b539344c21afef19", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Finds files and directories via an intuitive fluent interface", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.21" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-02-16T09:33:00+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v5.4.21", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", - "reference": "4fe5cf6ede71096839f0e4b4444d65dd3a7c1eb9", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php73": "~1.0", - "symfony/polyfill-php80": "^1.16" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.4.21" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-02-14T08:03:56+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", - "reference": "511a08c03c1960e08a883f4cffcacd219b758354", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's grapheme_* functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "42292d99c55abe617799667f454222c54c60e229" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", - "reference": "42292d99c55abe617799667f454222c54c60e229", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-07-28T09:04:16+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, - { - "name": "symfony/polyfill-php80", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/polyfill-php81", - "version": "v1.28.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", - "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.28-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-01-26T09:26:14+00:00" - }, - { - "name": "symfony/process", - "version": "v5.4.34", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/8fa22178dfc368911dbd513b431cd9b06f9afe7a", - "reference": "8fa22178dfc368911dbd513b431cd9b06f9afe7a", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-php80": "^1.16" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Executes commands in sub-processes", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v5.4.34" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-12-02T08:41:43+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v2.5.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" - }, - "conflict": { - "ext-psr": "<1.1|>=2" - }, - "suggest": { - "symfony/service-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-05-30T19:17:29+00:00" - }, - { - "name": "symfony/stopwatch", - "version": "v5.4.21", - "source": { - "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/f83692cd869a6f2391691d40a01e8acb89e76fee", - "reference": "f83692cd869a6f2391691d40a01e8acb89e76fee", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/service-contracts": "^1|^2|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides a way to profile code", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.4.21" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-02-14T08:03:56+00:00" - }, - { - "name": "symfony/string", - "version": "v5.4.22", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", - "reference": "8036a4c76c0dd29e60b6a7cafcacc50cf088ea62", - "shasum": "" - }, - "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" - }, - "conflict": { - "symfony/translation-contracts": ">=3.0" - }, - "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/functions.php" - ], - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", - "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], - "support": { - "source": "https://github.com/symfony/string/tree/v5.4.22" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-03-14T06:11:53+00:00" - }, - { - "name": "tecnickcom/tcpdf", - "version": "6.7.5", - "source": { - "type": "git", - "url": "https://github.com/tecnickcom/TCPDF.git", - "reference": "951eabf0338ec2522bd0d5d9c79b08a3a3d36b36" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/951eabf0338ec2522bd0d5d9c79b08a3a3d36b36", - "reference": "951eabf0338ec2522bd0d5d9c79b08a3a3d36b36", - "shasum": "" - }, - "require": { - "php": ">=5.5.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "config", - "include", - "tcpdf.php", - "tcpdf_parser.php", - "tcpdf_import.php", - "tcpdf_barcodes_1d.php", - "tcpdf_barcodes_2d.php", - "include/tcpdf_colors.php", - "include/tcpdf_filters.php", - "include/tcpdf_font_data.php", - "include/tcpdf_fonts.php", - "include/tcpdf_images.php", - "include/tcpdf_static.php", - "include/barcodes/datamatrix.php", - "include/barcodes/pdf417.php", - "include/barcodes/qrcode.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Nicola Asuni", - "email": "info@tecnick.com", - "role": "lead" - } - ], - "description": "TCPDF is a PHP class for generating PDF documents and barcodes.", - "homepage": "http://www.tcpdf.org/", - "keywords": [ - "PDFD32000-2008", - "TCPDF", - "barcodes", - "datamatrix", - "pdf", - "pdf417", - "qrcode" - ], - "support": { - "issues": "https://github.com/tecnickcom/TCPDF/issues", - "source": "https://github.com/tecnickcom/TCPDF/tree/6.7.5" - }, - "funding": [ - { - "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tcpdf%20project", - "type": "custom" - } - ], - "time": "2024-04-20T17:25:10+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "support": { - "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.2" - }, - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2023-11-20T00:12:19+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "phpstan/phpstan-phpunit": 0 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": "^7.1|^8.0", - "ext-dom": "*", - "ext-json": "*", - "ext-xml": "*" - }, - "platform-dev": { - "ext-zip": "*", - "ext-gd": "*", - "ext-libxml": "*" - }, - "platform-overrides": { - "php": "8.0" - }, - "plugin-api-version": "2.6.0" -} diff --git a/docs/changes/1.x/1.3.0.md b/docs/changes/1.x/1.3.0.md index cb8e11eecc..4b2e1b25df 100644 --- a/docs/changes/1.x/1.3.0.md +++ b/docs/changes/1.x/1.3.0.md @@ -1,15 +1,53 @@ -# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0) (WIP) +# [1.3.0](https://github.com/PHPOffice/PHPWord/tree/1.3.0) [Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...1.3.0) ## Enhancements +- IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515) +- PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642) +- Word2007 Reader: Support for Paragraph Border Style by [@damienfa](https://github.com/damienfa) in [#2651](https://github.com/PHPOffice/PHPWord/pull/2651) +- Word2007 Writer: Support for field REF by [@crystoline](https://github.com/crystoline) in [#2652](https://github.com/PHPOffice/PHPWord/pull/2652) +- Word2007 Reader : Support for FormFields by [@vincentKool](https://github.com/vincentKool) in [#2653](https://github.com/PHPOffice/PHPWord/pull/2653) +- RTF Writer : Support for Table Border Style fixing [#345](https://github.com/PHPOffice/PHPWord/issues/345) by [@Progi1984](https://github.com/Progi1984) in [#2656](https://github.com/PHPOffice/PHPWord/pull/2656) +- Word2007 Reader: Support the page break () by [@stanolacko](https://github.com/stanolacko) in [#2662](https://github.com/PHPOffice/PHPWord/pull/2662) +- MsDoc Reader: Support for UTF-8 characters by [@Progi1984] fixing [#881](https://github.com/PHPOffice/PHPWord/issues/881), [#1454](https://github.com/PHPOffice/PHPWord/issues/1454), [#1817](https://github.com/PHPOffice/PHPWord/issues/1817), [#1927](https://github.com/PHPOffice/PHPWord/issues/1927), [#2383](https://github.com/PHPOffice/PHPWord/issues/2383), [#2565](https://github.com/PHPOffice/PHPWord/issues/2565) in [#2664](https://github.com/PHPOffice/PHPWord/pull/2664) +- Word2007 Writer: Added support for multiples comment for the same text by [@rodrigoq](https://github.com/rodrigoq) fixing [#2109](https://github.com/PHPOffice/PHPWord/issues/2109) in [#2665](https://github.com/PHPOffice/PHPWord/pull/2665) + ### Bug fixes -- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) Issue [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) PR [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) +- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) - Html Reader : Process Titles as Headings not Paragraphs [@0b10011](https://github.com/0b10011) and [@oleibman](https://github.com/oleibman) Issue [#1692](https://github.com/PHPOffice/PHPWord/issues/1692) PR [#2533](https://github.com/PHPOffice/PHPWord/pull/2533) -- Table Borders Fixes by [@oleibman](https://github.com/oleibman) Issue [#2402](https://github.com/PHPOffice/PHPWord/issues/2402) Issue [#2474](https://github.com/PHPOffice/PHPWord/issues/2474) PR [#2535](https://github.com/PHPOffice/PHPWord/pull/2535) +- Generate Table Cell if Row Doesn't Have Any [@oleibman](https://github.com/oleibman) fixing [#2505](https://github.com/PHPOffice/PHPWord/issues/2505) in [#2516](https://github.com/PHPOffice/PHPWord/pull/2516) +- TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545) +- TemplateProcessor Destructor Problem with Php7 [@oleibman](https://github.com/oleibman) fixing [#2548](https://github.com/PHPOffice/PHPWord/issues/2548) in [#2554](https://github.com/PHPOffice/PHPWord/pull/2554) +- bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) +- 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551) +- Typo : Fix hardcoded macro chars in TemplateProcessor method [@glafarge](https://github.com/glafarge) in [#2618](https://github.com/PHPOffice/PHPWord/pull/2618) +- XML Reader : Prevent fatal errors when opening corrupt files or "doc" files [@mmcev106](https://github.com/mmcev106) in [#2626](https://github.com/PHPOffice/PHPWord/pull/2626) +- Documentation : Updated Comment element by [@laminga](https://github.com/laminga) in [#2650](https://github.com/PHPOffice/PHPWord/pull/2650) +- HTML Reader : Read width & height attributes in points fixing [#2589](https://github.com/PHPOffice/PHPWord/issues/2589) by [@Progi1984](https://github.com/Progi1984) in [#2654](https://github.com/PHPOffice/PHPWord/pull/2654) +- Template Processor : Fixed bad naming of variables fixing [#2586](https://github.com/PHPOffice/PHPWord/issues/2586) by [@Progi1984](https://github.com/Progi1984) in [#2655](https://github.com/PHPOffice/PHPWord/pull/2655) +- Word2007 Writer : Fix first footnote appearing as separator [#2634](https://github.com/PHPOffice/PHPWord/issues/2634) by [@jacksleight](https://github.com/jacksleight) in [#2635](https://github.com/PHPOffice/PHPWord/pull/2635) +- Template Processor : Fixed images with transparent backgrounds displaying a white background by [@ElwynVdb](https://github.com/ElwynVdb) in [#2638](https://github.com/PHPOffice/PHPWord/pull/2638) +- HTML Writer : Fixed rowspan for tables by [@andomiell](https://github.com/andomiell) in [#2659](https://github.com/PHPOffice/PHPWord/pull/2659) +- Word2007 Writer : Fixed StrikeThrough property by [@noec764](https://github.com/noec764) fixing [#1722](https://github.com/PHPOffice/PHPWord/issues/1722) & [#1693](https://github.com/PHPOffice/PHPWord/issues/1693) in [#2661](https://github.com/PHPOffice/PHPWord/pull/2661) +- HTML Reader : Fixed link without href by [@asmundstavdahl](https://github.com/asmundstavdahl) fixing [#1562](https://github.com/PHPOffice/PHPWord/issues/1562) in [#2663](https://github.com/PHPOffice/PHPWord/pull/2663) ### Miscellaneous +- Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) +- Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) +- Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) +- Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) +- Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) +- Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536) +- Allow rgb() when converting Html by [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) +- Improved Issue Template by [@Progi1984](https://github.com/Progi1984) in [#2609](https://github.com/PHPOffice/PHPWord/pull/2609) +- Bump phpoffice/math from 0.1.0 to 0.2.0 by [@Progi1984](https://github.com/Progi1984) fixing [#2559](https://github.com/PHPOffice/PHPWord/issues/2559) in [#2645](https://github.com/PHPOffice/PHPWord/pull/2645) +- Bump tecnickcom/tcpdf from 6.6.5 to 6.7.5 by [@dependabot](https://github.com/dependabot) in [#2646](https://github.com/PHPOffice/PHPWord/pull/2646) +- Bump mpdf/mpdf from 8.2.2 to 8.2.4 by [@dependabot](https://github.com/dependabot) in [#2647](https://github.com/PHPOffice/PHPWord/pull/2647) +- Bump phenx/php-svg-lib from 0.5.1 to 0.5.4 by [@dependabot](https://github.com/dependabot) in [#2649](https://github.com/PHPOffice/PHPWord/pull/2649) +- Bump phpstan/phpstan-phpunit from 1.3.15 to 1.4.0 by [@dependabot](https://github.com/dependabot) in [#2648](https://github.com/PHPOffice/PHPWord/pull/2648) + ### BC Breaks diff --git a/docs/changes/1.x/1.4.0.md b/docs/changes/1.x/1.4.0.md new file mode 100644 index 0000000000..c8a019115d --- /dev/null +++ b/docs/changes/1.x/1.4.0.md @@ -0,0 +1,36 @@ +# [1.4.0](https://github.com/PHPOffice/PHPWord/tree/1.4.0) (WIP) + +[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.3.0...1.4.0) + +## Enhancements + +- Default Font: Allow specify Asisn font and Latin font separately + +- Writer ODText: Support for ListItemRun by [@Progi1984](https://github.com/Progi1984) fixing [#2159](https://github.com/PHPOffice/PHPWord/issues/2159), [#2620](https://github.com/PHPOffice/PHPWord/issues/2620) in [#2669](https://github.com/PHPOffice/PHPWord/pull/2669) +- Writer HTML: Support for vAlign in Tables by [@SpraxDev](https://github.com/SpraxDev) in [#2675](https://github.com/PHPOffice/PHPWord/pull/2675) +- Writer Word2007: Support for padding in Table Cell by [@Azamat8405](https://github.com/Azamat8405) in [#2697](https://github.com/PHPOffice/PHPWord/pull/2697) +- Added support for PHP 8.4 by [@Progi1984](https://github.com/Progi1984) in [#2660](https://github.com/PHPOffice/PHPWord/pull/2660) +- Autoload : Allow to use PHPWord without Composer fixing [#2543](https://github.com/PHPOffice/PHPWord/issues/2543), [#2552](https://github.com/PHPOffice/PHPWord/issues/2552), [#2716](https://github.com/PHPOffice/PHPWord/issues/2716), [#2717](https://github.com/PHPOffice/PHPWord/issues/2717) in [#2722](https://github.com/PHPOffice/PHPWord/pull/2722) +- Add Default font color for Word by [@Collie-IT](https://github.com/Collie-IT) in [#2700](https://github.com/PHPOffice/PHPWord/pull/2700) +- Writer HTML: Support Default font color by [@MichaelPFrey](https://github.com/MichaelPFrey) +- Add basic ruby text (phonetic guide) support for Word2007 and HTML Reader/Writer, RTF Writer, basic support for ODT writing by [@Deadpikle](https://github.com/Deadpikle) in [#2727](https://github.com/PHPOffice/PHPWord/pull/2727) + +### Bug fixes + +- Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668) +- Allow vAlign and vMerge on Style\Cell to be set to null by [@SpraxDev](https://github.com/SpraxDev) fixing [#2673](https://github.com/PHPOffice/PHPWord/issues/2673) in [#2676](https://github.com/PHPOffice/PHPWord/pull/2676) +- Reader HTML: Support for differents size units for table by [@Progi1984](https://github.com/Progi1984) fixing [#2384](https://github.com/PHPOffice/PHPWord/issues/2384), [#2701](https://github.com/PHPOffice/PHPWord/issues/2701) in [#2725](https://github.com/PHPOffice/PHPWord/pull/2725) +- Reader Word2007 : Respect paragraph indent units by [@tugmaks](https://github.com/tugmaks) & [@Progi1984](https://github.com/Progi1984) fixing [#507](https://github.com/PHPOffice/PHPWord/issues/507) in [#2726](https://github.com/PHPOffice/PHPWord/pull/2726) +- Reader Word2007 : Support Header elements within Title elements by [@SpraxDev](https://github.com/SpraxDev) fixing [#2616](https://github.com/PHPOffice/PHPWord/issues/2616), [#2426](https://github.com/PHPOffice/PHPWord/issues/2426) in [#2674](https://github.com/PHPOffice/PHPWord/pull/2674) + +### Miscellaneous + +- Bump dompdf/dompdf from 2.0.4 to 3.0.0 by [@dependabot](https://github.com/dependabot) fixing [#2621](https://github.com/PHPOffice/PHPWord/issues/2621) in [#2666](https://github.com/PHPOffice/PHPWord/pull/2666) +- Add test case to make sure vMerge defaults to 'continue' by [@SpraxDev](https://github.com/SpraxDev) in [#2677](https://github.com/PHPOffice/PHPWord/pull/2677) + +### Deprecations +- Deprecate `PhpOffice\PhpWord\Style\Paragraph::getIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::getIndentLeft()` +- Deprecate `PhpOffice\PhpWord\Style\Paragraph::setHanging()` : Use `PhpOffice\PhpWord\Style\Paragraph::setIndentHanging()` +- Deprecate `PhpOffice\PhpWord\Style\Paragraph::setIndent()` : Use `PhpOffice\PhpWord\Style\Paragraph::setIndentLeft()` + +### BC Breaks diff --git a/docs/changes/2.x/2.0.0.md b/docs/changes/2.x/2.0.0.md deleted file mode 100644 index f1e5583e7c..0000000000 --- a/docs/changes/2.x/2.0.0.md +++ /dev/null @@ -1,47 +0,0 @@ -# [2.0.0](https://github.com/PHPOffice/PHPWord/tree/2.0.0) (WIP) - -[Full Changelog](https://github.com/PHPOffice/PHPWord/compare/1.2.0...2.0.0) - -## Enhancements - -- IOFactory : Added extractVariables method to extract variables from a document [@sibalonat](https://github.com/sibalonat) in [#2515](https://github.com/PHPOffice/PHPWord/pull/2515) -- PDF Writer : Documented how to specify a PDF renderer, when working with the PDF writer, as well as the three available choices by [@settermjd](https://github.com/settermjd) in [#2642](https://github.com/PHPOffice/PHPWord/pull/2642) -- Word2007 Reader: Support for Paragraph Border Style by [@damienfa](https://github.com/damienfa) in [#2651](https://github.com/PHPOffice/PHPWord/pull/2651) -- Word2007 Writer: Support for field REF by [@crystoline](https://github.com/crystoline) in [#2652](https://github.com/PHPOffice/PHPWord/pull/2652) -- Word2007 Reader : Support for FormFields by [@vincentKool](https://github.com/vincentKool) in [#2653](https://github.com/PHPOffice/PHPWord/pull/2653) -- RTF Writer : Support for Table Border Style fixing [#345](https://github.com/PHPOffice/PHPWord/issues/345) by [@Progi1984](https://github.com/Progi1984) in [#2656](https://github.com/PHPOffice/PHPWord/pull/2656) - -### Bug fixes - -- MsDoc Reader : Correct Font Size Calculation by [@oleibman](https://github.com/oleibman) fixing [#2526](https://github.com/PHPOffice/PHPWord/issues/2526) in [#2531](https://github.com/PHPOffice/PHPWord/pull/2531) -- Html Reader : Process Titles as Headings not Paragraphs [@0b10011](https://github.com/0b10011) and [@oleibman](https://github.com/oleibman) Issue [#1692](https://github.com/PHPOffice/PHPWord/issues/1692) PR [#2533](https://github.com/PHPOffice/PHPWord/pull/2533) -- Generate Table Cell if Row Doesn't Have Any [@oleibman](https://github.com/oleibman) fixing [#2505](https://github.com/PHPOffice/PHPWord/issues/2505) in [#2516](https://github.com/PHPOffice/PHPWord/pull/2516) -- TemplateProcessor Persist File After Destruct [@oleibman](https://github.com/oleibman) fixing [#2539](https://github.com/PHPOffice/PHPWord/issues/2539) in [#2545](https://github.com/PHPOffice/PHPWord/pull/2545) -- TemplateProcessor Destructor Problem with Php7 [@oleibman](https://github.com/oleibman) fixing [#2548](https://github.com/PHPOffice/PHPWord/issues/2548) in [#2554](https://github.com/PHPOffice/PHPWord/pull/2554) -- bug: TemplateProcessor fix multiline values [@gimler](https://github.com/gimler) fixing [#268](https://github.com/PHPOffice/PHPWord/issues/268), [#2323](https://github.com/PHPOffice/PHPWord/issues/2323) and [#2486](https://github.com/PHPOffice/PHPWord/issues/2486) in [#2522](https://github.com/PHPOffice/PHPWord/pull/2522) -- 32-bit Problem in PasswordEncoder [@oleibman](https://github.com/oleibman) fixing [#2550](https://github.com/PHPOffice/PHPWord/issues/2550) in [#2551](https://github.com/PHPOffice/PHPWord/pull/2551) -- Typo : Fix hardcoded macro chars in TemplateProcessor method [@glafarge](https://github.com/glafarge) in [#2618](https://github.com/PHPOffice/PHPWord/pull/2618) -- XML Reader : Prevent fatal errors when opening corrupt files or "doc" files [@mmcev106](https://github.com/mmcev106) in [#2626](https://github.com/PHPOffice/PHPWord/pull/2626) -- Documentation : Updated Comment element by [@laminga](https://github.com/laminga) in [#2650](https://github.com/PHPOffice/PHPWord/pull/2650) -- HTML Reader : Read width & height attributes in points fixing [#2589](https://github.com/PHPOffice/PHPWord/issues/2589) by [@Progi1984](https://github.com/Progi1984) in [#2654](https://github.com/PHPOffice/PHPWord/pull/2654) -- Template Processor : Fixed bad naming of variables fixing [#2586](https://github.com/PHPOffice/PHPWord/issues/2586) by [@Progi1984](https://github.com/Progi1984) in [#2655](https://github.com/PHPOffice/PHPWord/pull/2655) -- Word2007 Writer : Fix first footnote appearing as separator [#2634](https://github.com/PHPOffice/PHPWord/issues/2634) by [@jacksleight](https://github.com/jacksleight) in [#2635](https://github.com/PHPOffice/PHPWord/pull/2635) -- Template Processor : Fixed images with transparent backgrounds displaying a white background by [@ElwynVdb](https://github.com/ElwynVdb) in [#2638](https://github.com/PHPOffice/PHPWord/pull/2638) - -### Miscellaneous - -- Bump dompdf/dompdf from 2.0.3 to 2.0.4 by [@dependabot](https://github.com/dependabot) in [#2530](https://github.com/PHPOffice/PHPWord/pull/2530) -- Bump phpunit/phpunit from 9.6.13 to 9.6.14 by [@dependabot](https://github.com/dependabot) in [#2519](https://github.com/PHPOffice/PHPWord/pull/2519) -- Bump mpdf/mpdf from 8.2.0 to 8.2.2 by [@dependabot](https://github.com/dependabot) in [#2518](https://github.com/PHPOffice/PHPWord/pull/2518) -- Bump phpmd/phpmd from 2.14.1 to 2.15.0 by [@dependabot](https://github.com/dependabot) in [#2538](https://github.com/PHPOffice/PHPWord/pull/2538) -- Bump phpunit/phpunit from 9.6.14 to 9.6.15 by [@dependabot](https://github.com/dependabot) in [#2537](https://github.com/PHPOffice/PHPWord/pull/2537) -- Bump symfony/process from 5.4.28 to 5.4.34 by [@dependabot](https://github.com/dependabot) in [#2536](https://github.com/PHPOffice/PHPWord/pull/2536) -- Allow rgb() when converting Html by [@oleibman](https://github.com/oleibman) fixing [#2508](https://github.com/PHPOffice/PHPWord/issues/2508) in [#2512](https://github.com/PHPOffice/PHPWord/pull/2512) -- Improved Issue Template by [@Progi1984](https://github.com/Progi1984) in [#2609](https://github.com/PHPOffice/PHPWord/pull/2609) -- Bump phpoffice/math from 0.1.0 to 0.2.0 by [@Progi1984](https://github.com/Progi1984) fixing [#2559](https://github.com/PHPOffice/PHPWord/issues/2559) in [#2645](https://github.com/PHPOffice/PHPWord/pull/2645) -- Bump tecnickcom/tcpdf from 6.6.5 to 6.7.5 by [@dependabot](https://github.com/dependabot) in [#2646](https://github.com/PHPOffice/PHPWord/pull/2646) -- Bump mpdf/mpdf from 8.2.2 to 8.2.4 by [@dependabot](https://github.com/dependabot) in [#2647](https://github.com/PHPOffice/PHPWord/pull/2647) -- Bump phenx/php-svg-lib from 0.5.1 to 0.5.4 by [@dependabot](https://github.com/dependabot) in [#2649](https://github.com/PHPOffice/PHPWord/pull/2649) -- Bump phpstan/phpstan-phpunit from 1.3.15 to 1.4.0 by [@dependabot](https://github.com/dependabot) in [#2648](https://github.com/PHPOffice/PHPWord/pull/2648) - -### BC Breaks diff --git a/docs/howto.md b/docs/howto.md index f53217f869..fd4c860682 100644 --- a/docs/howto.md +++ b/docs/howto.md @@ -15,7 +15,7 @@ $imageStyle = array( 'posHorizontalRel' => 'margin', 'posVerticalRel' => 'line', ); -$textrun->addImage('resources/_earth.jpg', $imageStyle); +$textrun->addImage(__DIR__ . '/resources/_earth.jpg', $imageStyle); ``` ## Download the produced file automatically diff --git a/docs/index.md b/docs/index.md index dd600689d7..211fc31a79 100644 --- a/docs/index.md +++ b/docs/index.md @@ -52,7 +52,7 @@ Below are the supported features for each file formats. | | Preserve Text | :material-check: | | | | | | | Text Break | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | | | Page Break | :material-check: | | :material-check: | | | -| | List | :material-check: | | | | | +| | List | :material-check: | :material-check: | | | | | | Table | :material-check: | :material-check: | :material-check: | :material-check: | :material-check: | | | Image | :material-check: | :material-check: | :material-check: | :material-check: | | | | Object | :material-check: | | | | | diff --git a/docs/install.md b/docs/install.md index 1b54a3173f..a4d61b104d 100644 --- a/docs/install.md +++ b/docs/install.md @@ -32,7 +32,6 @@ To install via Composer, add the following lines to your `composer.json`: To install manually: * [download PHPOffice\PHPWord package from GitHub](https://github.com/PHPOffice/PHPWord/archive/master.zip) -* [download PHPOffice\Common package from GitHub](https://github.com/PHPOffice/Common/archive/master.zip) * extract the package and put the contents to your machine. @@ -42,11 +41,10 @@ To install manually: require_once 'path/to/PHPWord/src/PhpWord/Autoloader.php'; \PhpOffice\PhpWord\Autoloader::register(); -require_once 'path/to/PhpOffice/Common/src/Common/Autoloader.php'; -\PhpOffice\Common\Autoloader::register(); - ``` +The preferred method is the Composer one. + ## Samples After installation, you can browse and use the samples that we've provided, either by command line or using browser. If you can access your PhpWord library folder using browser, point your browser to the `samples` folder, e.g. `http://localhost/PhpWord/samples/`. diff --git a/docs/usage/elements/ruby.md b/docs/usage/elements/ruby.md new file mode 100644 index 0000000000..508b97cd84 --- /dev/null +++ b/docs/usage/elements/ruby.md @@ -0,0 +1,57 @@ +# Ruby + +Ruby (phonetic guide) text can be added by using the ``addRuby`` method. Ruby elements require a ``RubyProperties`` object, a ``TextRun`` for the base text, and a ``TextRun`` for the actual ruby (phonetic guide) text. + +Here is one example for a complete ruby element setup: + +``` php +addSection(); +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(4); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('ja-JP'); + +$baseTextRun = new TextRun(null); +$baseTextRun->addText('私'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('わたし'); + +$section->addRuby($baseTextRun, $rubyTextRun, $properties); +``` + +- ``$baseTextRun``. ``TextRun`` to be used for the base text. +- ``$rubyTextRun``. ``TextRun`` to be used for the ruby text. +- ``$properties``. ``RubyProperties`` properties object for the ruby text. + +A title with a phonetic guide is a little more complex, but still possible. Make sure you add the appropraite title style to your document. + +```php +$phpWord = new PhpWord(); +$fontStyle = new Font(); +$fontStyle->setAllCaps(true); +$fontStyle->setBold(true); +$fontStyle->setSize(24); +$phpWord->addTitleStyle(1, ['name' => 'Arial', 'size' => 24, 'bold' => true, 'color' => '990000']); + +$section = $phpWord->addSection(); +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(4); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('ja-JP'); + +$baseTextRun = new TextRun(null); +$baseTextRun->addText('私'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('わたし'); + +$textRun = new TextRun(); +$textRun->addRuby($baseTextRun, $rubyTextRun, $properties); +$section->addTitle($textRun, 1); +``` \ No newline at end of file diff --git a/docs/usage/introduction.md b/docs/usage/introduction.md index b3a101ab0d..19d6aff51f 100644 --- a/docs/usage/introduction.md +++ b/docs/usage/introduction.md @@ -7,7 +7,6 @@ are provided in the [samples folder](https://github.com/PHPOffice/PHPWord/tree/m ``` php setDefaultFontName('Times New Roman'); +$phpWord->setDefaultFontColor('FF0000'); $phpWord->setDefaultFontSize(12); ``` +Or you can specify Asian Font + +``` php +setDefaultAsianFontName('標楷體'); +``` + ## Document settings Settings for the generated document can be set using ``$phpWord->getSettings()`` @@ -381,4 +389,4 @@ To control whether or not words in all capital letters shall be hyphenated use t getSettings()->setDoNotHyphenateCaps(true); -``` \ No newline at end of file +``` diff --git a/mkdocs.yml b/mkdocs.yml index 6eb4d42911..0462c9c8a4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -63,6 +63,7 @@ nav: - OLE Object: 'usage/elements/oleobject.md' - Page Break: 'usage/elements/pagebreak.md' - Preserve Text: 'usage/elements/preservetext.md' + - Ruby: 'usage/elements/ruby.md' - Text: 'usage/elements/text.md' - TextBox: 'usage/elements/textbox.md' - Text Break: 'usage/elements/textbreak.md' @@ -86,9 +87,9 @@ nav: - How to: 'howto.md' - Credits: 'credits.md' - Releases: - - '2.x': - - '2.0.0 (WIP)': 'changes/2.x/2.0.0.md' - '1.x': + - '1.4.0 (WIP)': 'changes/1.x/1.4.0.md' + - '1.3.0': 'changes/1.x/1.3.0.md' - '1.2.0': 'changes/1.x/1.2.0.md' - '1.1.0': 'changes/1.x/1.1.0.md' - '1.0.0': 'changes/1.x/1.0.0.md' diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index a2f9112ce4..5e1f9cd2c2 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -375,11 +375,6 @@ parameters: count: 1 path: src/PhpWord/Shared/Drawing.php - - - message: "#^Binary operation \"\\*\" between string and 50 results in an error\\.$#" - count: 1 - path: src/PhpWord/Shared/Html.php - - message: "#^Call to an undefined method DOMNode\\:\\:getAttribute\\(\\)\\.$#" count: 1 @@ -430,6 +425,11 @@ parameters: count: 1 path: src/PhpWord/Shared/Html.php + - + message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseRuby\\(\\) has no return type specified\\.$#" + count: 1 + path: src/PhpWord/Shared/Html.php + - message: "#^Method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyleDeclarations\\(\\) has no return type specified\\.$#" count: 1 @@ -442,7 +442,7 @@ parameters: - message: "#^Parameter \\#1 \\$attribute of static method PhpOffice\\\\PhpWord\\\\Shared\\\\Html\\:\\:parseStyle\\(\\) expects DOMAttr, DOMNode given\\.$#" - count: 1 + count: 3 path: src/PhpWord/Shared/Html.php - @@ -680,11 +680,6 @@ parameters: count: 1 path: src/PhpWord/Style/Cell.php - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Cell\\:\\:\\$shading is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Cell.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\Chart\\:\\:getMajorTickPosition\\(\\) has no return type specified\\.$#" count: 1 @@ -755,41 +750,6 @@ parameters: count: 1 path: src/PhpWord/Style/Font.php - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$allCaps is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$doubleStrikethrough is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$lang is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$paragraph is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$shading is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$smallCaps is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Font\\:\\:\\$strikethrough is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Font.php - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Line\\:\\:\\$weight \\(int\\) does not accept float\\|int\\|null\\.$#" count: 1 @@ -810,21 +770,6 @@ parameters: count: 1 path: src/PhpWord/Style/Paragraph.php - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$indentation is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Paragraph.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$shading is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Paragraph.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Paragraph\\:\\:\\$spacing is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Paragraph.php - - message: "#^Result of && is always false\\.$#" count: 1 @@ -835,36 +780,6 @@ parameters: count: 1 path: src/PhpWord/Style/Section.php - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Section\\:\\:\\$lineNumbering is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Section.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$extrusion is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$fill is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$frame is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$outline is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - - - message: "#^Property PhpOffice\\\\PhpWord\\\\Style\\\\Shape\\:\\:\\$shadow is never written, only read\\.$#" - count: 1 - path: src/PhpWord/Style/Shape.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Style\\\\TOC\\:\\:setTabLeader\\(\\) should return PhpOffice\\\\PhpWord\\\\Style\\\\TOC but returns PhpOffice\\\\PhpWord\\\\Style\\\\Tab\\.$#" count: 1 @@ -1115,11 +1030,6 @@ parameters: count: 1 path: src/PhpWord/Writer/AbstractWriter.php - - - message: "#^PHPDoc tag @param has invalid value \\(\\\\PhpOffice\\\\PhpWord\\\\PhpWord\\)\\: Unexpected token \"\\\\n \\*\", expected variable at offset 78$#" - count: 1 - path: src/PhpWord/Writer/AbstractWriter.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\HTML\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#" count: 1 @@ -1141,14 +1051,14 @@ parameters: path: src/PhpWord/Writer/ODText/Element/Table.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) has parameter \\$text with no type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\AbstractElement\\:\\:replaceTabs\\(\\) has parameter \\$text with no type specified\\.$#" count: 1 - path: src/PhpWord/Writer/ODText/Element/Text.php + path: src/PhpWord/Writer/ODText/Element/AbstractElement.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:replacetabs\\(\\) has parameter \\$xmlWriter with no type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\AbstractElement\\:\\:replaceTabs\\(\\) has parameter \\$xmlWriter with no type specified\\.$#" count: 1 - path: src/PhpWord/Writer/ODText/Element/Text.php + path: src/PhpWord/Writer/ODText/Element/AbstractElement.php - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\ODText\\\\Element\\\\Text\\:\\:writeChangeInsertion\\(\\) has parameter \\$start with no type specified\\.$#" @@ -1310,11 +1220,6 @@ parameters: count: 1 path: src/PhpWord/Writer/RTF/Style/Border.php - - - message: "#^PHPDoc tag @param has invalid value \\(\\\\PhpOffice\\\\PhpWord\\\\PhpWord\\)\\: Unexpected token \"\\\\n \", expected variable at offset 86$#" - count: 1 - path: src/PhpWord/Writer/Word2007.php - - message: "#^Method PhpOffice\\\\PhpWord\\\\Writer\\\\Word2007\\\\Element\\\\AbstractElement\\:\\:write\\(\\) has no return type specified\\.$#" count: 1 @@ -1421,29 +1326,29 @@ parameters: path: tests/PhpWordTests/AbstractTestReader.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getBaseUrl\\(\\) has no return type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getBaseUrl\\(\\) has no return type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteBmpImageUrl\\(\\) has no return type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteBmpImageUrl\\(\\) has no return type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteGifImageUrl\\(\\) has no return type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteGifImageUrl\\(\\) has no return type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:getRemoteImageUrl\\(\\) has no return type specified\\.$#" + message: "#^Method PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:getRemoteImageUrl\\(\\) has no return type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - - message: "#^Property PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbeddedTest\\:\\:\\$httpServer has no type specified\\.$#" + message: "#^Property PhpOffice\\\\PhpWordTests\\\\AbstractWebServerEmbedded\\:\\:\\$httpServer has no type specified\\.$#" count: 1 - path: tests/PhpWordTests/AbstractWebServerEmbeddedTest.php + path: tests/PhpWordTests/AbstractWebServerEmbedded.php - message: "#^Parameter \\#1 \\$width of class PhpOffice\\\\PhpWord\\\\Element\\\\Cell constructor expects int\\|null, string given\\.$#" @@ -1782,17 +1687,17 @@ parameters: - message: "#^Cannot access property \\$length on DOMNodeList\\\\|false\\.$#" - count: 6 + count: 9 path: tests/PhpWordTests/Writer/HTML/ElementTest.php - + - - message: "#^Cannot call method item\\(\\) on DOMNodeList\\\\|false\\.$#" - count: 8 - path: tests/PhpWordTests/Writer/HTML/ElementTest.php + message: "#^Cannot access property \\$length on DOMNodeList\\\\|false\\.$#" + count: 2 + path: tests/PhpWordTests/Writer/HTML/Element/RubyTest.php - - message: "#^Method PhpOffice\\\\PhpWordTests\\\\Writer\\\\HTML\\\\ElementTest\\:\\:getAsHTML\\(\\) has no return type specified\\.$#" - count: 1 + message: "#^Cannot call method item\\(\\) on DOMNodeList\\\\|false\\.$#" + count: 11 path: tests/PhpWordTests/Writer/HTML/ElementTest.php - diff --git a/phpstan.neon b/phpstan.neon deleted file mode 100644 index aac94077bd..0000000000 --- a/phpstan.neon +++ /dev/null @@ -1,19 +0,0 @@ -includes: - - phpstan-baseline.neon - - vendor/phpstan/phpstan-phpunit/extension.neon - - vendor/phpstan/phpstan-phpunit/rules.neon -parameters: - level: 7 - paths: - - src/ - - tests/ - excludePaths: - - */pclzip.lib.php - - src/PhpWord/Shared/OLERead.php - - src/PhpWord/Reader/MsDoc.php - - src/PhpWord/Writer/PDF/MPDF.php - bootstrapFiles: - - tests/bootstrap.php - ignoreErrors: - - - identifier: missingType.iterableValue diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000000..0cdf25ef21 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,44 @@ +includes: + - phpstan-baseline.neon + - vendor/phpstan/phpstan-phpunit/extension.neon + - vendor/phpstan/phpstan-phpunit/rules.neon +parameters: + level: 7 + paths: + - src/ + - tests/ + excludePaths: + - */pclzip.lib.php + - src/PhpWord/Shared/OLERead.php + - src/PhpWord/Reader/MsDoc.php + - src/PhpWord/Writer/PDF/MPDF.php + bootstrapFiles: + - tests/bootstrap.php + ## <=PHP7.4 + reportUnmatchedIgnoredErrors: false + ignoreErrors: + - + identifier: missingType.iterableValue + + ## <=PHP7.4 + - + message: '#Parameter \#1 \$argument of class ReflectionClass constructor expects class-string\|T of object, string given.#' + path: src/PhpWord/Element/AbstractContainer.php + - + message: '#Parameter \#1 \$function of function call_user_func expects callable\(\): mixed, string given.#' + path: src/PhpWord/Element/Image.php + - + message: '#Parameter \#1 \$argument of class ReflectionClass constructor expects class-string\|T of object, string given.#' + path: src/PhpWord/IOFactory.php + - + message: '#Parameter \#1 \$function of function forward_static_call_array expects callable\(\): mixed, array{.+, string} given.#' + path: src/PhpWord/PhpWord.php + - + message: '#Parameter \#1 \$function of function call_user_func_array expects callable\(\): mixed, array{\$this\(PhpOffice\\PhpWord\\Shared\\ZipArchive\)\|PclZip\|ZipArchive, mixed} given.#' + path: src/PhpWord/Shared/ZipArchive.php + - + message: '#Parameter \#1 \$function of function call_user_func_array expects callable\(\): mixed, array{PhpOffice\\PhpWord\\Writer\\PDF\\AbstractRenderer, string} given.#' + path: src/PhpWord/Writer/PDF.php + - + message: '#Parameter \#1 \$argument of class ReflectionClass constructor expects class-string\|object, class-string\|false given.#' + path: tests/PhpWordTests/Style/AbstractStyleTest.php diff --git a/phpword.ini.dist b/phpword.ini.dist index f3f66dbe2e..21d3b50609 100644 --- a/phpword.ini.dist +++ b/phpword.ini.dist @@ -14,6 +14,7 @@ outputEscapingEnabled = false defaultFontName = Arial defaultFontSize = 10 +defaultFontColor = 000000 [Paper] diff --git a/samples/Sample_01_SimpleText.php b/samples/Sample_01_SimpleText.php index e89f7323ba..07e0d05aa5 100644 --- a/samples/Sample_01_SimpleText.php +++ b/samples/Sample_01_SimpleText.php @@ -7,16 +7,16 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$languageEnGb = new \PhpOffice\PhpWord\Style\Language(\PhpOffice\PhpWord\Style\Language::EN_GB); +$languageEnGb = new PhpOffice\PhpWord\Style\Language(PhpOffice\PhpWord\Style\Language::EN_GB); -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->getSettings()->setThemeFontLang($languageEnGb); $fontStyleName = 'rStyle'; $phpWord->addFontStyle($fontStyleName, ['bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true]); $paragraphStyleName = 'pStyle'; -$phpWord->addParagraphStyle($paragraphStyleName, ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100]); +$phpWord->addParagraphStyle($paragraphStyleName, ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100]); $phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]); @@ -29,7 +29,7 @@ // $pStyle = new Font(); // $pStyle->setLang() -$section->addText('Ce texte-ci est en français.', ['lang' => \PhpOffice\PhpWord\Style\Language::FR_BE]); +$section->addText('Ce texte-ci est en français.', ['lang' => PhpOffice\PhpWord\Style\Language::FR_BE]); // Two text break $section->addTextBreak(2); @@ -82,7 +82,7 @@ $section->addTextBreak(); // Image -$section->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); +$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_02_TabStops.php b/samples/Sample_02_TabStops.php index 74a0ed1fa3..ad99fe83f5 100644 --- a/samples/Sample_02_TabStops.php +++ b/samples/Sample_02_TabStops.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $multipleTabsStyleName = 'multipleTab'; @@ -12,18 +12,18 @@ $multipleTabsStyleName, [ 'tabs' => [ - new \PhpOffice\PhpWord\Style\Tab('left', 1550), - new \PhpOffice\PhpWord\Style\Tab('center', 3200), - new \PhpOffice\PhpWord\Style\Tab('right', 5300), + new PhpOffice\PhpWord\Style\Tab('left', 1550), + new PhpOffice\PhpWord\Style\Tab('center', 3200), + new PhpOffice\PhpWord\Style\Tab('right', 5300), ], ] ); $rightTabStyleName = 'rightTab'; -$phpWord->addParagraphStyle($rightTabStyleName, ['tabs' => [new \PhpOffice\PhpWord\Style\Tab('right', 9090)]]); +$phpWord->addParagraphStyle($rightTabStyleName, ['tabs' => [new PhpOffice\PhpWord\Style\Tab('right', 9090)]]); $leftTabStyleName = 'centerTab'; -$phpWord->addParagraphStyle($leftTabStyleName, ['tabs' => [new \PhpOffice\PhpWord\Style\Tab('center', 4680)]]); +$phpWord->addParagraphStyle($leftTabStyleName, ['tabs' => [new PhpOffice\PhpWord\Style\Tab('center', 4680)]]); // New portrait section $section = $phpWord->addSection(); diff --git a/samples/Sample_03_Sections.php b/samples/Sample_03_Sections.php index b02a277c43..b01726d81c 100644 --- a/samples/Sample_03_Sections.php +++ b/samples/Sample_03_Sections.php @@ -6,7 +6,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New portrait section $section = $phpWord->addSection(['borderColor' => '00FF00', 'borderSize' => 12]); diff --git a/samples/Sample_04_Textrun.php b/samples/Sample_04_Textrun.php index 33af08a5b4..6d50e285ec 100644 --- a/samples/Sample_04_Textrun.php +++ b/samples/Sample_04_Textrun.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $paragraphStyleName = 'pStyle'; @@ -17,7 +17,7 @@ $phpWord->addFontStyle($coloredFontStyleName, ['color' => 'FF8080', 'bgColor' => 'FFFFCC']); $linkFontStyleName = 'NLink'; -$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); +$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); // New portrait section $section = $phpWord->addSection(); @@ -35,9 +35,9 @@ $textrun->addText(' Sample Link: '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName); $textrun->addText(' Sample Image: '); -$textrun->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); +$textrun->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); $textrun->addText(' Sample Object: '); -$textrun->addObject('resources/_sheet.xls'); +$textrun->addObject(__DIR__ . '/resources/_sheet.xls'); $textrun->addText(' Here is some more text. '); $textrun = $section->addTextRun(); diff --git a/samples/Sample_05_Multicolumn.php b/samples/Sample_05_Multicolumn.php index 093dd60424..c4d1dd7280 100644 --- a/samples/Sample_05_Multicolumn.php +++ b/samples/Sample_05_Multicolumn.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $filler = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ' . 'Nulla fermentum, tortor id adipiscing adipiscing, tortor turpis commodo. ' . 'Donec vulputate iaculis metus, vel luctus dolor hendrerit ac. ' diff --git a/samples/Sample_06_Footnote.php b/samples/Sample_06_Footnote.php index f3c369b342..035916ee09 100644 --- a/samples/Sample_06_Footnote.php +++ b/samples/Sample_06_Footnote.php @@ -7,8 +7,8 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); -\PhpOffice\PhpWord\Settings::setCompatibility(false); +$phpWord = new PhpOffice\PhpWord\PhpWord(); +PhpOffice\PhpWord\Settings::setCompatibility(false); // Define styles $paragraphStyleName = 'pStyle'; @@ -21,7 +21,7 @@ $phpWord->addFontStyle($coloredFontStyleName, ['color' => 'FF8080', 'bgColor' => 'FFFFCC']); $linkFontStyleName = 'NLink'; -$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); +$phpWord->addLinkStyle($linkFontStyleName, ['color' => '0000FF', 'underline' => PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE]); // New portrait section $section = $phpWord->addSection(); @@ -39,9 +39,9 @@ $footnote->addText('links like '); $footnote->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', $linkFontStyleName); $footnote->addText(', image like '); -$footnote->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); +$footnote->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); $footnote->addText(', or object like '); -$footnote->addObject('resources/_sheet.xls'); +$footnote->addObject(__DIR__ . '/resources/_sheet.xls'); $footnote->addText('But you can only put footnote in section, not in header or footer.'); $section->addText( diff --git a/samples/Sample_07_TemplateCloneRow.php b/samples/Sample_07_TemplateCloneRow.php index a921569f64..0f1d165f19 100644 --- a/samples/Sample_07_TemplateCloneRow.php +++ b/samples/Sample_07_TemplateCloneRow.php @@ -4,7 +4,7 @@ // Template processor instance creation echo date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL; -$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_07_TemplateCloneRow.docx'); +$templateProcessor = new PhpOffice\PhpWord\TemplateProcessor(__DIR__ . '/resources/Sample_07_TemplateCloneRow.docx'); // Variables on different parts of document $templateProcessor->setValue('weekday', date('l')); // On section/content @@ -79,9 +79,9 @@ // $templateProcessor->setValue('userPhone#3', '+1 428 889 775'); echo date('H:i:s'), ' Saving the result document...', EOL; -$templateProcessor->saveAs('results/Sample_07_TemplateCloneRow.docx'); +$templateProcessor->saveAs(__DIR__ . '/results/Sample_07_TemplateCloneRow.docx'); -echo getEndingNotes(['Word2007' => 'docx'], 'results/Sample_07_TemplateCloneRow.docx'); +echo getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_07_TemplateCloneRow.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_08_ParagraphPagination.php b/samples/Sample_08_ParagraphPagination.php index f343366a84..cac52e3baf 100644 --- a/samples/Sample_08_ParagraphPagination.php +++ b/samples/Sample_08_ParagraphPagination.php @@ -4,11 +4,11 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultParagraphStyle( [ - 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::BOTH, - 'spaceAfter' => \PhpOffice\PhpWord\Shared\Converter::pointToTwip(12), + 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::BOTH, + 'spaceAfter' => PhpOffice\PhpWord\Shared\Converter::pointToTwip(12), 'spacing' => 120, ] ); diff --git a/samples/Sample_09_Tables.php b/samples/Sample_09_Tables.php index f1b67c9ecc..3a887468b0 100644 --- a/samples/Sample_09_Tables.php +++ b/samples/Sample_09_Tables.php @@ -7,7 +7,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $header = ['size' => 16, 'bold' => true]; @@ -31,10 +31,10 @@ $section->addText('Fancy table', $header); $fancyTableStyleName = 'Fancy Table'; -$fancyTableStyle = ['borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER, 'cellSpacing' => 50]; +$fancyTableStyle = ['borderSize' => 6, 'borderColor' => '006699', 'cellMargin' => 80, 'alignment' => PhpOffice\PhpWord\SimpleType\JcTable::CENTER, 'cellSpacing' => 50]; $fancyTableFirstRowStyle = ['borderBottomSize' => 18, 'borderBottomColor' => '0000FF', 'bgColor' => '66BBFF']; $fancyTableCellStyle = ['valign' => 'center']; -$fancyTableCellBtlrStyle = ['valign' => 'center', 'textDirection' => \PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR]; +$fancyTableCellBtlrStyle = ['valign' => 'center', 'textDirection' => PhpOffice\PhpWord\Style\Cell::TEXT_DIR_BTLR]; $fancyTableFontStyle = ['bold' => true]; $phpWord->addTableStyle($fancyTableStyleName, $fancyTableStyle, $fancyTableFirstRowStyle); $table = $section->addTable($fancyTableStyleName); @@ -56,11 +56,13 @@ /* * 3. colspan (gridSpan) and rowspan (vMerge) - * --------------------- - * | | B | | - * | A |--------| E | - * | | C | D | | - * --------------------- + * ------------------------- + * | A | B | C | + * |-----|-----------| | + * | D | | + * ------|-----------| | + * | E | F | G | | + * ------------------------- */ $section->addPageBreak(); @@ -70,32 +72,27 @@ $cellRowSpan = ['vMerge' => 'restart', 'valign' => 'center', 'bgColor' => 'FFFF00']; $cellRowContinue = ['vMerge' => 'continue']; $cellColSpan = ['gridSpan' => 2, 'valign' => 'center']; -$cellHCentered = ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]; +$cellHCentered = ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]; $cellVCentered = ['valign' => 'center']; $spanTableStyleName = 'Colspan Rowspan'; $phpWord->addTableStyle($spanTableStyleName, $fancyTableStyle); $table = $section->addTable($spanTableStyleName); -$table->addRow(); - -$cell1 = $table->addCell(2000, $cellRowSpan); -$textrun1 = $cell1->addTextRun($cellHCentered); -$textrun1->addText('A'); -$textrun1->addFootnote()->addText('Row span'); - -$cell2 = $table->addCell(4000, $cellColSpan); -$textrun2 = $cell2->addTextRun($cellHCentered); -$textrun2->addText('B'); -$textrun2->addFootnote()->addText('Column span'); +$row1 = $table->addRow(); +$row1->addCell(500)->addText('A'); +$row1->addCell(1000, ['gridSpan' => 2])->addText('B'); +$row1->addCell(500, ['vMerge' => 'restart'])->addText('C'); -$table->addCell(2000, $cellRowSpan)->addText('E', null, $cellHCentered); +$row2 = $table->addRow(); +$row2->addCell(1500, ['gridSpan' => 3])->addText('D'); +$row2->addCell(null, ['vMerge' => 'continue']); -$table->addRow(); -$table->addCell(null, $cellRowContinue); -$table->addCell(2000, $cellVCentered)->addText('C', null, $cellHCentered); -$table->addCell(2000, $cellVCentered)->addText('D', null, $cellHCentered); -$table->addCell(null, $cellRowContinue); +$row3 = $table->addRow(); +$row3->addCell(500)->addText('E'); +$row3->addCell(500)->addText('F'); +$row3->addCell(500)->addText('G'); +$row3->addCell(null, ['vMerge' => 'continue']); /* * 4. colspan (gridSpan) and rowspan (vMerge) @@ -137,10 +134,10 @@ $section->addTextBreak(2); $section->addText('Nested table in a centered and 50% width table.', $header); -$table = $section->addTable(['width' => 50 * 50, 'unit' => 'pct', 'alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER]); +$table = $section->addTable(['width' => 50 * 50, 'unit' => 'pct', 'alignment' => PhpOffice\PhpWord\SimpleType\JcTable::CENTER]); $cell = $table->addRow()->addCell(); $cell->addText('This cell contains nested table.'); -$innerCell = $cell->addTable(['alignment' => \PhpOffice\PhpWord\SimpleType\JcTable::CENTER])->addRow()->addCell(); +$innerCell = $cell->addTable(['alignment' => PhpOffice\PhpWord\SimpleType\JcTable::CENTER])->addRow()->addCell(); $innerCell->addText('Inside nested table'); // 6. Table with floating position diff --git a/samples/Sample_10_EastAsianFontStyle.php b/samples/Sample_10_EastAsianFontStyle.php index c8a6ec3a5e..f730ab510f 100644 --- a/samples/Sample_10_EastAsianFontStyle.php +++ b/samples/Sample_10_EastAsianFontStyle.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $header = ['size' => 16, 'bold' => true]; //1.Use EastAisa FontStyle diff --git a/samples/Sample_11_ReadWord2007.php b/samples/Sample_11_ReadWord2007.php index 313cc00797..72cdfac625 100644 --- a/samples/Sample_11_ReadWord2007.php +++ b/samples/Sample_11_ReadWord2007.php @@ -7,7 +7,7 @@ $source = __DIR__ . "/resources/{$name}.docx"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_11_ReadWord97.php b/samples/Sample_11_ReadWord97.php index 4187baaef7..728df6210b 100644 --- a/samples/Sample_11_ReadWord97.php +++ b/samples/Sample_11_ReadWord97.php @@ -4,9 +4,9 @@ // Read contents $name = basename(__FILE__, '.php'); -$source = "resources/{$name}.doc"; +$source = __DIR__ . "/resources/{$name}.doc"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'MsDoc'); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source, 'MsDoc'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_12_HeaderFooter.php b/samples/Sample_12_HeaderFooter.php index 081371863a..393e9d1032 100644 --- a/samples/Sample_12_HeaderFooter.php +++ b/samples/Sample_12_HeaderFooter.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New portrait section $section = $phpWord->addSection(); @@ -18,16 +18,16 @@ $textrun = $cell->addTextRun(); $textrun->addText('This is the header with '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); -$table->addCell(4500)->addImage('resources/PhpWord.png', ['width' => 80, 'height' => 80, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END]); +$table->addCell(4500)->addImage(__DIR__ . '/resources/PhpWord.png', ['width' => 80, 'height' => 80, 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::END]); // Add header for all other pages $subsequent = $section->addHeader(); $subsequent->addText('Subsequent pages in Section 1 will Have this!'); -$subsequent->addImage('resources/_mars.jpg', ['width' => 80, 'height' => 80]); +$subsequent->addImage(__DIR__ . '/resources/_mars.jpg', ['width' => 80, 'height' => 80]); // Add footer $footer = $section->addFooter(); -$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', null, ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$footer->addPreserveText('Page {PAGE} of {NUMPAGES}.', null, ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $footer->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); // Write some text diff --git a/samples/Sample_13_Images.php b/samples/Sample_13_Images.php index 30b9cae949..a8ab87ce8c 100644 --- a/samples/Sample_13_Images.php +++ b/samples/Sample_13_Images.php @@ -1,22 +1,23 @@ addSection(); $section->addText('Local image without any styles:'); -$section->addImage('resources/_mars.jpg'); +$section->addImage(__DIR__ . '/resources/_mars.jpg'); printSeparator($section); $section->addText('Local image with styles:'); -$section->addImage('resources/_earth.jpg', ['width' => 210, 'height' => 210, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 210, 'height' => 210, 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); // Remote image printSeparator($section); @@ -26,7 +27,7 @@ // Image from string printSeparator($section); -$source = 'resources/_mars.jpg'; +$source = __DIR__ . '/resources/_mars.jpg'; $fileContent = file_get_contents($source); $section->addText('Image from string'); $section->addImage($fileContent); @@ -38,7 +39,7 @@ foreach ($wrappingStyles as $wrappingStyle) { $section->addText("Wrapping style {$wrappingStyle}"); $section->addImage( - 'resources/_earth.jpg', + __DIR__ . '/resources/_earth.jpg', [ 'positioning' => 'relative', 'marginTop' => -1, @@ -57,16 +58,16 @@ //Absolute positioning $section->addText('Absolute positioning: see top right corner of page'); $section->addImage( - 'resources/_mars.jpg', + __DIR__ . '/resources/_mars.jpg', [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), - 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, - 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_RIGHT, - 'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE, - 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE, - 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15.5), - 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1.55), + 'width' => Converter::cmToPixel(3), + 'height' => Converter::cmToPixel(3), + 'positioning' => PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, + 'posHorizontal' => PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_RIGHT, + 'posHorizontalRel' => PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE, + 'posVerticalRel' => PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_PAGE, + 'marginLeft' => Converter::cmToPixel(15.5), + 'marginTop' => Converter::cmToPixel(1.55), ] ); @@ -75,15 +76,15 @@ $section->addText('Relative positioning: Horizontal position center relative to column,'); $section->addText('Vertical position top relative to line'); $section->addImage( - 'resources/_mars.jpg', + __DIR__ . '/resources/_mars.jpg', [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(3), - 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE, - 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_CENTER, - 'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_COLUMN, - 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, - 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_LINE, + 'width' => Converter::cmToPixel(3), + 'height' => Converter::cmToPixel(3), + 'positioning' => PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE, + 'posHorizontal' => PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_CENTER, + 'posHorizontalRel' => PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_COLUMN, + 'posVertical' => PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, + 'posVerticalRel' => PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_LINE, ] ); diff --git a/samples/Sample_14_ListItem.php b/samples/Sample_14_ListItem.php index 3b509f3577..f82c3ec064 100644 --- a/samples/Sample_14_ListItem.php +++ b/samples/Sample_14_ListItem.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $fontStyleName = 'myOwnStyle'; @@ -25,7 +25,7 @@ ] ); -$predefinedMultilevelStyle = ['listType' => \PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED]; +$predefinedMultilevelStyle = ['listType' => PhpOffice\PhpWord\Style\ListItem::TYPE_NUMBER_NESTED]; // New section $section = $phpWord->addSection(); diff --git a/samples/Sample_15_Link.php b/samples/Sample_15_Link.php index faef305962..43994deaa2 100644 --- a/samples/Sample_15_Link.php +++ b/samples/Sample_15_Link.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $linkFontStyleName = 'myOwnLinStyle'; @@ -17,7 +17,7 @@ $section->addLink( 'https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub', - ['color' => '0000FF', 'underline' => \PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE] + ['color' => '0000FF', 'underline' => PhpOffice\PhpWord\Style\Font::UNDERLINE_SINGLE] ); $section->addTextBreak(2); $section->addLink('http://www.bing.com', null, $linkFontStyleName); diff --git a/samples/Sample_16_Object.php b/samples/Sample_16_Object.php index b68fb1675b..d3912a6c50 100644 --- a/samples/Sample_16_Object.php +++ b/samples/Sample_16_Object.php @@ -4,13 +4,13 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Begin code $section = $phpWord->addSection(); $section->addText('You can open this OLE object by double clicking on the icon:'); $section->addTextBreak(2); -$section->addOLEObject('resources/_sheet.xls'); +$section->addOLEObject(__DIR__ . '/resources/_sheet.xls'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_17_TitleTOC.php b/samples/Sample_17_TitleTOC.php index dcf060b0e6..3102ebda83 100644 --- a/samples/Sample_17_TitleTOC.php +++ b/samples/Sample_17_TitleTOC.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->getSettings()->setUpdateFields(true); // New section diff --git a/samples/Sample_18_Watermark.php b/samples/Sample_18_Watermark.php index aebb369023..0b3ae34f83 100644 --- a/samples/Sample_18_Watermark.php +++ b/samples/Sample_18_Watermark.php @@ -4,12 +4,12 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Begin code $section = $phpWord->addSection(); $header = $section->addHeader(); -$header->addWatermark('resources/_earth.jpg', ['marginTop' => 200, 'marginLeft' => 55]); +$header->addWatermark(__DIR__ . '/resources/_earth.jpg', ['marginTop' => 200, 'marginLeft' => 55]); $section->addText('The header reference to the current section includes a watermark image.'); // Save file diff --git a/samples/Sample_19_TextBreak.php b/samples/Sample_19_TextBreak.php index 45c79beeb6..0b41110b18 100644 --- a/samples/Sample_19_TextBreak.php +++ b/samples/Sample_19_TextBreak.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $fontStyle24 = ['size' => 24]; diff --git a/samples/Sample_20_BGColor.php b/samples/Sample_20_BGColor.php index 915a824171..e0ce4d6436 100644 --- a/samples/Sample_20_BGColor.php +++ b/samples/Sample_20_BGColor.php @@ -4,14 +4,14 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); $section->addText( 'This is some text highlighted using fgColor (limited to 15 colors)', - ['fgColor' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW] + ['fgColor' => PhpOffice\PhpWord\Style\Font::FGCOLOR_YELLOW] ); $section->addText('This one uses bgColor and is using hex value (0xfbbb10)', ['bgColor' => 'fbbb10']); $section->addText('Compatible with font colors', ['color' => '0000ff', 'bgColor' => 'fbbb10']); diff --git a/samples/Sample_21_TableRowRules.php b/samples/Sample_21_TableRowRules.php index 42fc2d92a5..0ddaa08faf 100644 --- a/samples/Sample_21_TableRowRules.php +++ b/samples/Sample_21_TableRowRules.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); @@ -19,7 +19,7 @@ $table1 = $section->addTable(['cellMargin' => 0, 'cellMarginRight' => 0, 'cellMarginBottom' => 0, 'cellMarginLeft' => 0]); $table1->addRow(3750); $cell1 = $table1->addCell(null, ['valign' => 'top', 'borderSize' => 30, 'borderColor' => 'ff0000']); -$cell1->addImage('./resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$cell1->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $section->addTextBreak(); $section->addText("But if we set the rowStyle 'exactHeight' to true, the real row height is used, removing the textbreak:"); @@ -34,7 +34,7 @@ ); $table2->addRow(3750, ['exactHeight' => true]); $cell2 = $table2->addCell(null, ['valign' => 'top', 'borderSize' => 30, 'borderColor' => '00ff00']); -$cell2->addImage('./resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$cell2->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 250, 'height' => 250, 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $section->addTextBreak(); $section->addText('In this example, image is 250px height. Rows are calculated in twips, and 1px = 15twips.'); diff --git a/samples/Sample_22_CheckBox.php b/samples/Sample_22_CheckBox.php index 33d4e39c66..91685924b0 100644 --- a/samples/Sample_22_CheckBox.php +++ b/samples/Sample_22_CheckBox.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); diff --git a/samples/Sample_23_TemplateBlock.php b/samples/Sample_23_TemplateBlock.php index 6da66a72d4..4cc541ab3a 100644 --- a/samples/Sample_23_TemplateBlock.php +++ b/samples/Sample_23_TemplateBlock.php @@ -4,7 +4,7 @@ // Template processor instance creation echo date('H:i:s') , ' Creating new TemplateProcessor instance...' , EOL; -$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_23_TemplateBlock.docx'); +$templateProcessor = new PhpOffice\PhpWord\TemplateProcessor(__DIR__ . '/resources/Sample_23_TemplateBlock.docx'); // Will clone everything between ${tag} and ${/tag}, the number of times. By default, 1. $templateProcessor->cloneBlock('CLONEME', 3); @@ -13,9 +13,9 @@ $templateProcessor->deleteBlock('DELETEME'); echo date('H:i:s'), ' Saving the result document...', EOL; -$templateProcessor->saveAs('results/Sample_23_TemplateBlock.docx'); +$templateProcessor->saveAs(__DIR__ . '/results/Sample_23_TemplateBlock.docx'); -echo getEndingNotes(['Word2007' => 'docx'], 'Sample_23_TemplateBlock'); +echo getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_23_TemplateBlock.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_24_ReadODText.php b/samples/Sample_24_ReadODText.php index 73c110203e..1b3a43cd57 100644 --- a/samples/Sample_24_ReadODText.php +++ b/samples/Sample_24_ReadODText.php @@ -7,7 +7,7 @@ $source = __DIR__ . "/resources/{$name}.odt"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'ODText'); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source, 'ODText'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_25_TextBox.php b/samples/Sample_25_TextBox.php index a897a6269f..3516379d42 100644 --- a/samples/Sample_25_TextBox.php +++ b/samples/Sample_25_TextBox.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); @@ -12,7 +12,7 @@ // In section $textbox = $section->addTextBox( [ - 'alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER, + 'alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'width' => 400, 'height' => 150, 'borderSize' => 1, @@ -39,7 +39,7 @@ $textrun->addText(', '); $textrun->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); $textrun->addText(', and image '); -$textrun->addImage('resources/_earth.jpg', ['width' => 18, 'height' => 18]); +$textrun->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); $textrun->addText('.'); // Save file diff --git a/samples/Sample_26_Html.php b/samples/Sample_26_Html.php index daf109966c..971c317c43 100644 --- a/samples/Sample_26_Html.php +++ b/samples/Sample_26_Html.php @@ -4,7 +4,7 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->addParagraphStyle('Heading2', ['alignment' => 'center']); $section = $phpWord->addSection(); @@ -93,7 +93,7 @@ $html .= '

The text below is not visible, click on show/hide to reveil it:

'; $html .= '

This is hidden text

'; -\PhpOffice\PhpWord\Shared\Html::addHtml($section, $html, false, false); +PhpOffice\PhpWord\Shared\Html::addHtml($section, $html, false, false); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_27_Field.php b/samples/Sample_27_Field.php index fd441ba022..e1dbb4f258 100644 --- a/samples/Sample_27_Field.php +++ b/samples/Sample_27_Field.php @@ -6,7 +6,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); PhpOffice\PhpWord\Style::addTitleStyle(1, ['size' => 14]); // New section @@ -49,7 +49,7 @@ $section->addText('The actual index:'); $section->addField('INDEX', [], ['\\e " "'], 'right click to update the index'); -$textrun = $section->addTextRun(['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]); +$textrun = $section->addTextRun(['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]); $textrun->addText('This is the date of lunar calendar '); $textrun->addField('DATE', ['dateformat' => 'd-M-yyyy H:mm:ss'], ['PreserveFormat', 'LunarCalendar']); $textrun->addText(' written in a textrun.'); diff --git a/samples/Sample_28_ReadRTF.php b/samples/Sample_28_ReadRTF.php index 43b859ac28..52aa74a9a5 100644 --- a/samples/Sample_28_ReadRTF.php +++ b/samples/Sample_28_ReadRTF.php @@ -7,7 +7,7 @@ $source = __DIR__ . "/resources/{$name}.rtf"; echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'RTF'); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source, 'RTF'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_29_Line.php b/samples/Sample_29_Line.php index e5f41b8340..2fdf33c30d 100644 --- a/samples/Sample_29_Line.php +++ b/samples/Sample_29_Line.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); @@ -14,16 +14,16 @@ $section->addText('Horizontal Line (Inline style):'); $section->addLine( [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), + 'width' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), + 'height' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), 'positioning' => 'absolute', ] ); $section->addText('Vertical Line (Inline style):'); $section->addLine( [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), + 'width' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), + 'height' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), 'positioning' => 'absolute', ] ); @@ -33,14 +33,14 @@ $section->addText('Positioned Line (red):'); $section->addLine( [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), + 'width' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(4), + 'height' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(1), 'positioning' => 'absolute', 'posHorizontalRel' => 'page', 'posVerticalRel' => 'page', - 'marginLeft' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(10), - 'marginTop' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(8), - 'wrappingStyle' => \PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, + 'marginLeft' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(10), + 'marginTop' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(8), + 'wrappingStyle' => PhpOffice\PhpWord\Style\Image::WRAPPING_STYLE_SQUARE, 'color' => 'red', ] ); @@ -48,12 +48,12 @@ $section->addText('Horizontal Formatted Line'); $section->addLine( [ - 'width' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(15), - 'height' => \PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), + 'width' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(15), + 'height' => PhpOffice\PhpWord\Shared\Converter::cmToPixel(0), 'positioning' => 'absolute', - 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, - 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, - 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, + 'beginArrow' => PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, + 'endArrow' => PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, + 'dash' => PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, 'weight' => 10, ] ); diff --git a/samples/Sample_30_ReadHTML.php b/samples/Sample_30_ReadHTML.php index 8698fe639a..b6564eddc8 100644 --- a/samples/Sample_30_ReadHTML.php +++ b/samples/Sample_30_ReadHTML.php @@ -7,7 +7,7 @@ $source = realpath(__DIR__ . "/resources/{$name}.html"); echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$phpWord = \PhpOffice\PhpWord\IOFactory::load($source, 'HTML'); +$phpWord = PhpOffice\PhpWord\IOFactory::load($source, 'HTML'); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_31_Shape.php b/samples/Sample_31_Shape.php index 90e364e7be..7f68f3fc2a 100644 --- a/samples/Sample_31_Shape.php +++ b/samples/Sample_31_Shape.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index 7e99984e41..c8c65e989e 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -6,7 +6,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // Define styles $phpWord->addTitleStyle(1, ['size' => 14, 'bold' => true], ['keepNext' => true, 'spaceBefore' => 240]); diff --git a/samples/Sample_33_FormField.php b/samples/Sample_33_FormField.php index 24ef6ee947..223fdd2987 100644 --- a/samples/Sample_33_FormField.php +++ b/samples/Sample_33_FormField.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->getSettings()->getDocumentProtection()->setEditing('forms'); // New section diff --git a/samples/Sample_34_SDT.php b/samples/Sample_34_SDT.php index c1722b5b5c..4c8f588e81 100644 --- a/samples/Sample_34_SDT.php +++ b/samples/Sample_34_SDT.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New section $section = $phpWord->addSection(); diff --git a/samples/Sample_35_InternalLink.php b/samples/Sample_35_InternalLink.php index e59c353001..ef10c4b61f 100644 --- a/samples/Sample_35_InternalLink.php +++ b/samples/Sample_35_InternalLink.php @@ -4,7 +4,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); $section->addTitle('This is page 1', 1); diff --git a/samples/Sample_36_RTL.php b/samples/Sample_36_RTL.php index b3baca90cb..e3cf84576a 100644 --- a/samples/Sample_36_RTL.php +++ b/samples/Sample_36_RTL.php @@ -6,7 +6,7 @@ // New Word document echo date('H:i:s'), ' Create new PhpWord object', EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $phpWord->setDefaultFontName('DejaVu Sans'); // for good rendition of PDF $rendererName = Settings::PDF_RENDERER_MPDF; $rendererLibraryPath = $vendorDirPath . '/mpdf/mpdf'; @@ -18,17 +18,17 @@ $textrun = $section->addTextRun(); $textrun->addText('This is a Left to Right paragraph.'); -$textrun = $section->addTextRun(['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END]); +$textrun = $section->addTextRun(['alignment' => PhpOffice\PhpWord\SimpleType\Jc::END]); $textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true]); $section->addText('Table visually presented as RTL'); $style = ['rtl' => true, 'size' => 12]; -$tableStyle = ['borderSize' => 6, 'borderColor' => '000000', 'width' => 5000, 'unit' => \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT, 'bidiVisual' => true]; +$tableStyle = ['borderSize' => 6, 'borderColor' => '000000', 'width' => 5000, 'unit' => PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT, 'bidiVisual' => true]; $table = $section->addTable($tableStyle); -$cellHCentered = ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]; -$cellHEnd = ['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::END]; -$cellVCentered = ['valign' => \PhpOffice\PhpWord\SimpleType\VerticalJc::CENTER]; +$cellHCentered = ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER]; +$cellHEnd = ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::END]; +$cellVCentered = ['valign' => PhpOffice\PhpWord\SimpleType\VerticalJc::CENTER]; //Vidually bidirectinal table $table->addRow(); diff --git a/samples/Sample_37_Comments.php b/samples/Sample_37_Comments.php index 79647478e8..ac03a699e4 100644 --- a/samples/Sample_37_Comments.php +++ b/samples/Sample_37_Comments.php @@ -4,10 +4,10 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // A comment -$comment = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials'); $comment->addText('Test', ['bold' => true]); $phpWord->addComment($comment); @@ -22,7 +22,7 @@ $section->addTextBreak(2); // Let's create a comment that we will link to a start element and an end element -$commentWithStartAndEnd = new \PhpOffice\PhpWord\Element\Comment('Foo Bar', new \DateTime()); +$commentWithStartAndEnd = new PhpOffice\PhpWord\Element\Comment('Foo Bar', new DateTime()); $commentWithStartAndEnd->addText('A comment with a start and an end'); $phpWord->addComment($commentWithStartAndEnd); @@ -37,12 +37,12 @@ $section->addTextBreak(2); // Let's add a comment on an image -$commentOnImage = new \PhpOffice\PhpWord\Element\Comment('Mr Smart', new \DateTime()); +$commentOnImage = new PhpOffice\PhpWord\Element\Comment('Mr Smart', new DateTime()); $imageComment = $commentOnImage->addTextRun(); $imageComment->addText('Hey, Mars does look '); $imageComment->addText('red', ['color' => 'FF0000']); $phpWord->addComment($commentOnImage); -$image = $section->addImage('resources/_mars.jpg'); +$image = $section->addImage(__DIR__ . '/resources/_mars.jpg'); $image->setCommentRangeStart($commentOnImage); $section->addTextBreak(2); @@ -50,12 +50,27 @@ // We can also do things the other way round, link the comment to the element $anotherText = $section->addText('another text'); -$comment1 = new \PhpOffice\PhpWord\Element\Comment('Authors name', new \DateTime(), 'my_initials'); +$comment1 = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials'); $comment1->addText('Test', ['bold' => true]); $comment1->setStartElement($anotherText); $comment1->setEndElement($anotherText); $phpWord->addComment($comment1); +// We can also do things the other way round, link the comment to the element +$lastText = $section->addText('with a last text and two comments'); + +$comment1 = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials'); +$comment1->addText('Comment 1', ['bold' => true]); +$comment1->setStartElement($lastText); +$comment1->setEndElement($lastText); +$phpWord->addComment($comment1); + +$comment2 = new PhpOffice\PhpWord\Element\Comment('Authors name', new DateTime(), 'my_initials'); +$comment2->addText('Comment 2', ['bold' => true]); +$comment2->setStartElement($lastText); +$comment2->setEndElement($lastText); +$phpWord->addComment($comment2); + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/samples/Sample_38_Protection.php b/samples/Sample_38_Protection.php index 9f61538096..737946d51a 100644 --- a/samples/Sample_38_Protection.php +++ b/samples/Sample_38_Protection.php @@ -6,7 +6,7 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); $documentProtection = $phpWord->getSettings()->getDocumentProtection(); $documentProtection->setEditing(DocProtect::READ_ONLY); diff --git a/samples/Sample_39_TrackChanges.php b/samples/Sample_39_TrackChanges.php index a95d98cb81..a2c2bcf61c 100644 --- a/samples/Sample_39_TrackChanges.php +++ b/samples/Sample_39_TrackChanges.php @@ -6,7 +6,7 @@ // New Word Document echo date('H:i:s') , ' Create new PhpWord object' , EOL; -$phpWord = new \PhpOffice\PhpWord\PhpWord(); +$phpWord = new PhpOffice\PhpWord\PhpWord(); // New portrait section $section = $phpWord->addSection(); @@ -21,7 +21,7 @@ $text->setTrackChange(new TrackChange(TrackChange::INSERTED, 'Fred')); $text = $textRun->addText('go to sleep'); -$text->setChangeInfo(TrackChange::DELETED, 'Barney', new \DateTime('@' . (time() - 3600))); +$text->setChangeInfo(TrackChange::DELETED, 'Barney', new DateTime('@' . (time() - 3600))); // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); diff --git a/samples/Sample_40_TemplateSetComplexValue.php b/samples/Sample_40_TemplateSetComplexValue.php index 38ecb3f7ae..41cbab8950 100644 --- a/samples/Sample_40_TemplateSetComplexValue.php +++ b/samples/Sample_40_TemplateSetComplexValue.php @@ -9,7 +9,7 @@ // Template processor instance creation echo date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL; -$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_40_TemplateSetComplexValue.docx'); +$templateProcessor = new PhpOffice\PhpWord\TemplateProcessor(__DIR__ . '/resources/Sample_40_TemplateSetComplexValue.docx'); $title = new TextRun(); $title->addText('This title has been set ', ['bold' => true, 'italic' => true, 'color' => 'blue']); @@ -38,9 +38,9 @@ // $templateProcessor->setComplexValue('link', $link); echo date('H:i:s'), ' Saving the result document...', EOL; -$templateProcessor->saveAs('results/Sample_40_TemplateSetComplexValue.docx'); +$templateProcessor->saveAs(__DIR__ . '/results/Sample_40_TemplateSetComplexValue.docx'); -echo getEndingNotes(['Word2007' => 'docx'], 'results/Sample_40_TemplateSetComplexValue.docx'); +echo getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_40_TemplateSetComplexValue.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_41_TemplateSetChart.php b/samples/Sample_41_TemplateSetChart.php index 88eb2ccbd9..36be5888f7 100644 --- a/samples/Sample_41_TemplateSetChart.php +++ b/samples/Sample_41_TemplateSetChart.php @@ -7,7 +7,7 @@ // Template processor instance creation echo date('H:i:s'), ' Creating new TemplateProcessor instance...', EOL; -$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('resources/Sample_41_TemplateSetChart.docx'); +$templateProcessor = new PhpOffice\PhpWord\TemplateProcessor(__DIR__ . '/resources/Sample_41_TemplateSetChart.docx'); $chartTypes = ['pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column']; $twoSeries = ['bar', 'column', 'line', 'area', 'scatter', 'radar', 'stacked_bar', 'percent_stacked_bar', 'stacked_column', 'percent_stacked_column']; @@ -38,9 +38,9 @@ } echo date('H:i:s'), ' Saving the result document...', EOL; -$templateProcessor->saveAs('results/Sample_41_TemplateSetChart.docx'); +$templateProcessor->saveAs(__DIR__ . '/results/Sample_41_TemplateSetChart.docx'); -echo getEndingNotes(['Word2007' => 'docx'], 'results/Sample_41_TemplateSetChart.docx'); +echo getEndingNotes(['Word2007' => 'docx'], __DIR__ . '/results/Sample_41_TemplateSetChart.docx'); if (!CLI) { include_once 'Sample_Footer.php'; } diff --git a/samples/Sample_44_ExtractVariablesFromReaderWord2007.php b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php index 24574e5fb7..8c1703499f 100644 --- a/samples/Sample_44_ExtractVariablesFromReaderWord2007.php +++ b/samples/Sample_44_ExtractVariablesFromReaderWord2007.php @@ -9,6 +9,6 @@ echo date('H:i:s'), " Reading contents from `{$source}`", EOL; -$variables = \PhpOffice\PhpWord\IOFactory::extractVariables($source); +$variables = PhpOffice\PhpWord\IOFactory::extractVariables($source); var_dump($variables); diff --git a/samples/Sample_45_Autoloader.php b/samples/Sample_45_Autoloader.php new file mode 100644 index 0000000000..71f443f770 --- /dev/null +++ b/samples/Sample_45_Autoloader.php @@ -0,0 +1,93 @@ +getSettings()->setThemeFontLang($languageEnGb); + +$fontStyleName = 'rStyle'; +$phpWord->addFontStyle($fontStyleName, ['bold' => true, 'italic' => true, 'size' => 16, 'allCaps' => true, 'doubleStrikethrough' => true]); + +$paragraphStyleName = 'pStyle'; +$phpWord->addParagraphStyle($paragraphStyleName, ['alignment' => PhpOffice\PhpWord\SimpleType\Jc::CENTER, 'spaceAfter' => 100]); + +$phpWord->addTitleStyle(1, ['bold' => true], ['spaceAfter' => 240]); + +// New portrait section +$section = $phpWord->addSection(); + +// Simple text +$section->addTitle('Welcome to PhpWord', 1); +$section->addText('Hello World!'); + +// $pStyle = new Font(); +// $pStyle->setLang() +$section->addText('Ce texte-ci est en français.', ['lang' => PhpOffice\PhpWord\Style\Language::FR_BE]); + +// Two text break +$section->addTextBreak(2); + +// Define styles +$section->addText('I am styled by a font style definition.', $fontStyleName); +$section->addText('I am styled by a paragraph style definition.', null, $paragraphStyleName); +$section->addText('I am styled by both font and paragraph style.', $fontStyleName, $paragraphStyleName); + +$section->addTextBreak(); + +// Inline font style +$fontStyle['name'] = 'Times New Roman'; +$fontStyle['size'] = 20; + +$textrun = $section->addTextRun(); +$textrun->addText('I am inline styled ', $fontStyle); +$textrun->addText('with '); +$textrun->addText('color', ['color' => '996699']); +$textrun->addText(', '); +$textrun->addText('bold', ['bold' => true]); +$textrun->addText(', '); +$textrun->addText('italic', ['italic' => true]); +$textrun->addText(', '); +$textrun->addText('underline', ['underline' => 'dash']); +$textrun->addText(', '); +$textrun->addText('strikethrough', ['strikethrough' => true]); +$textrun->addText(', '); +$textrun->addText('doubleStrikethrough', ['doubleStrikethrough' => true]); +$textrun->addText(', '); +$textrun->addText('superScript', ['superScript' => true]); +$textrun->addText(', '); +$textrun->addText('subScript', ['subScript' => true]); +$textrun->addText(', '); +$textrun->addText('smallCaps', ['smallCaps' => true]); +$textrun->addText(', '); +$textrun->addText('allCaps', ['allCaps' => true]); +$textrun->addText(', '); +$textrun->addText('fgColor', ['fgColor' => 'yellow']); +$textrun->addText(', '); +$textrun->addText('scale', ['scale' => 200]); +$textrun->addText(', '); +$textrun->addText('spacing', ['spacing' => 120]); +$textrun->addText(', '); +$textrun->addText('kerning', ['kerning' => 10]); +$textrun->addText('. '); + +// Link +$section->addLink('https://github.com/PHPOffice/PHPWord', 'PHPWord on GitHub'); +$section->addTextBreak(); + +// Image +$section->addImage(__DIR__ . '/resources/_earth.jpg', ['width' => 18, 'height' => 18]); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_46_RubyPhoneticGuide.php b/samples/Sample_46_RubyPhoneticGuide.php new file mode 100644 index 0000000000..0d991de756 --- /dev/null +++ b/samples/Sample_46_RubyPhoneticGuide.php @@ -0,0 +1,70 @@ +addSection(); + +$section->addText('Here is some normal text with no ruby, also known as "phonetic guide", text.'); + +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(20); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('en-US'); + +$textRun = $section->addTextRun(); +$textRun->addText('Here is a demonstration of ruby text for '); +$baseTextRun = new TextRun(null); +$baseTextRun->addText('this'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('ruby-text'); +$textRun->addRuby($baseTextRun, $rubyTextRun, $properties); +$textRun->addText(' word.'); + +$textRun = $section->addTextRun(); +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(20); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('ja-JP'); +$textRun->addText('Here is a demonstration of ruby text for Japanese text: '); +$baseTextRun = new TextRun(null); +$baseTextRun->addText('私'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('わたし'); +$textRun->addRuby($baseTextRun, $rubyTextRun, $properties); + +$section->addText('You can also have ruby text for titles:'); + +$phpWord->addTitleStyle(1, ['name' => 'Arial', 'size' => 24, 'bold' => true, 'color' => '000099']); + +$properties = new RubyProperties(); +$properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); +$properties->setFontFaceSize(10); +$properties->setFontPointsAboveBaseText(50); +$properties->setFontSizeForBaseText(18); +$properties->setLanguageId('ja-JP'); + +$baseTextRun = new TextRun(null); +$baseTextRun->addText('私'); +$rubyTextRun = new TextRun(null); +$rubyTextRun->addText('わたし'); +$textRun = new TextRun(); +$textRun->addRuby($baseTextRun, $rubyTextRun, $properties); +$section->addTitle($textRun, 1); + +// Save file +echo write($phpWord, basename(__FILE__, '.php'), $writers); +if (!CLI) { + include_once 'Sample_Footer.php'; +} diff --git a/samples/Sample_Header.php b/samples/Sample_Header.php index 8d05a2a34e..eab7033275 100644 --- a/samples/Sample_Header.php +++ b/samples/Sample_Header.php @@ -1,5 +1,19 @@ items; } @@ -44,11 +47,9 @@ public function getItems() /** * Get item by index. * - * @param int $index - * - * @return ?\PhpOffice\PhpWord\Element\AbstractContainer + * @return ?T */ - public function getItem($index) + public function getItem(int $index) { if (array_key_exists($index, $this->items)) { return $this->items[$index]; @@ -60,10 +61,9 @@ public function getItem($index) /** * Set item. * - * @param int $index - * @param ?\PhpOffice\PhpWord\Element\AbstractContainer $item + * @param ?T $item */ - public function setItem($index, $item): void + public function setItem(int $index, $item): void { if (array_key_exists($index, $this->items)) { $this->items[$index] = $item; @@ -73,11 +73,9 @@ public function setItem($index, $item): void /** * Add new item. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $item - * - * @return int + * @param T $item */ - public function addItem($item) + public function addItem($item): int { $index = $this->countItems(); $this->items[$index] = $item; @@ -87,10 +85,8 @@ public function addItem($item) /** * Get item count. - * - * @return int */ - public function countItems() + public function countItems(): int { return count($this->items); } diff --git a/src/PhpWord/Collection/Bookmarks.php b/src/PhpWord/Collection/Bookmarks.php index e7d9b4a384..0694bf7dd8 100644 --- a/src/PhpWord/Collection/Bookmarks.php +++ b/src/PhpWord/Collection/Bookmarks.php @@ -1,4 +1,5 @@ */ class Bookmarks extends AbstractCollection { diff --git a/src/PhpWord/Collection/Charts.php b/src/PhpWord/Collection/Charts.php index bb63a13962..ef1c6597ff 100644 --- a/src/PhpWord/Collection/Charts.php +++ b/src/PhpWord/Collection/Charts.php @@ -1,4 +1,5 @@ */ class Charts extends AbstractCollection { diff --git a/src/PhpWord/Collection/Comments.php b/src/PhpWord/Collection/Comments.php index 8c6b577d7e..4f1394359f 100644 --- a/src/PhpWord/Collection/Comments.php +++ b/src/PhpWord/Collection/Comments.php @@ -1,4 +1,5 @@ */ class Comments extends AbstractCollection { diff --git a/src/PhpWord/Collection/Endnotes.php b/src/PhpWord/Collection/Endnotes.php index 362b25881d..3de1ad22d5 100644 --- a/src/PhpWord/Collection/Endnotes.php +++ b/src/PhpWord/Collection/Endnotes.php @@ -1,4 +1,5 @@ */ class Endnotes extends AbstractCollection { diff --git a/src/PhpWord/Collection/Footnotes.php b/src/PhpWord/Collection/Footnotes.php index 76eae3eab3..804a45c873 100644 --- a/src/PhpWord/Collection/Footnotes.php +++ b/src/PhpWord/Collection/Footnotes.php @@ -1,4 +1,5 @@ */ class Footnotes extends AbstractCollection { diff --git a/src/PhpWord/Collection/Titles.php b/src/PhpWord/Collection/Titles.php index 7b795771e8..1a943697d2 100644 --- a/src/PhpWord/Collection/Titles.php +++ b/src/PhpWord/Collection/Titles.php @@ -1,4 +1,5 @@ */ class Titles extends AbstractCollection { diff --git a/src/PhpWord/ComplexType/FootnoteProperties.php b/src/PhpWord/ComplexType/FootnoteProperties.php index 2e7743ca08..10c426e84c 100644 --- a/src/PhpWord/ComplexType/FootnoteProperties.php +++ b/src/PhpWord/ComplexType/FootnoteProperties.php @@ -1,4 +1,5 @@ alignment = self::ALIGNMENT_DISTRIBUTE_SPACE; + $this->fontFaceSize = 12; + $this->fontPointsAboveText = 22; + $this->languageId = 'ja-JP'; + $this->baseTextFontSize = 24; + } + + /** + * Get the ruby alignment. + */ + public function getAlignment(): string + { + return $this->alignment; + } + + /** + * Set the Ruby Alignment (center, distributeLetter, distributeSpace, left, right, rightVertical). + */ + public function setAlignment(string $alignment): self + { + $alignmentTypes = [ + self::ALIGNMENT_CENTER, + self::ALIGNMENT_DISTRIBUTE_LETTER, + self::ALIGNMENT_DISTRIBUTE_SPACE, + self::ALIGNMENT_LEFT, + self::ALIGNMENT_RIGHT, + self::ALIGNMENT_RIGHT_VERTICAL, + ]; + + if (in_array($alignment, $alignmentTypes)) { + $this->alignment = $alignment; + } else { + throw new InvalidArgumentException('Invalid value, alignments of ' . implode(', ', $alignmentTypes) . ' possible'); + } + + return $this; + } + + /** + * Get the ruby font face size. + */ + public function getFontFaceSize(): float + { + return $this->fontFaceSize; + } + + /** + * Set the ruby font face size. + */ + public function setFontFaceSize(float $size): self + { + $this->fontFaceSize = $size; + + return $this; + } + + /** + * Get the ruby font points above base text. + */ + public function getFontPointsAboveBaseText(): float + { + return $this->fontPointsAboveText; + } + + /** + * Set the ruby font points above base text. + */ + public function setFontPointsAboveBaseText(float $size): self + { + $this->fontPointsAboveText = $size; + + return $this; + } + + /** + * Get the ruby font size for base text. + */ + public function getFontSizeForBaseText(): float + { + return $this->baseTextFontSize; + } + + /** + * Set the ruby font size for base text. + */ + public function setFontSizeForBaseText(float $size): self + { + $this->baseTextFontSize = $size; + + return $this; + } + + /** + * Get the ruby language id. + */ + public function getLanguageId(): string + { + return $this->languageId; + } + + /** + * Set the ruby language id. + */ + public function setLanguageId(string $langId): self + { + $this->languageId = $langId; + + return $this; + } +} diff --git a/src/PhpWord/ComplexType/TblWidth.php b/src/PhpWord/ComplexType/TblWidth.php index 6a9368f464..f1c0e10c9c 100644 --- a/src/PhpWord/ComplexType/TblWidth.php +++ b/src/PhpWord/ComplexType/TblWidth.php @@ -1,4 +1,5 @@ newInstanceArgs($elementArgs); // Set parent container @@ -165,7 +167,7 @@ protected function addElement($elementName) /** * Get all elements. * - * @return \PhpOffice\PhpWord\Element\AbstractElement[] + * @return AbstractElement[] */ public function getElements() { @@ -177,7 +179,7 @@ public function getElements() * * @param int $index * - * @return null|\PhpOffice\PhpWord\Element\AbstractElement + * @return null|AbstractElement */ public function getElement($index) { @@ -191,13 +193,13 @@ public function getElement($index) /** * Removes the element at requested index. * - * @param int|\PhpOffice\PhpWord\Element\AbstractElement $toRemove + * @param AbstractElement|int $toRemove */ public function removeElement($toRemove): void { if (is_int($toRemove) && array_key_exists($toRemove, $this->elements)) { unset($this->elements[$toRemove]); - } elseif ($toRemove instanceof \PhpOffice\PhpWord\Element\AbstractElement) { + } elseif ($toRemove instanceof AbstractElement) { foreach ($this->elements as $key => $element) { if ($element->getElementId() === $toRemove->getElementId()) { unset($this->elements[$key]); @@ -253,7 +255,7 @@ private function checkValidity($method) 'Footnote' => ['Section', 'TextRun', 'Cell', 'ListItemRun'], 'Endnote' => ['Section', 'TextRun', 'Cell'], 'PreserveText' => ['Section', 'Header', 'Footer', 'Cell'], - 'Title' => ['Section', 'Cell'], + 'Title' => ['Section', 'Cell', 'Header'], 'TOC' => ['Section'], 'PageBreak' => ['Section'], 'Chart' => ['Section', 'Cell'], diff --git a/src/PhpWord/Element/AbstractElement.php b/src/PhpWord/Element/AbstractElement.php index 9f9c2e82aa..3a29b68673 100644 --- a/src/PhpWord/Element/AbstractElement.php +++ b/src/PhpWord/Element/AbstractElement.php @@ -1,4 +1,5 @@ phpWord; } @@ -254,7 +255,7 @@ public function getElementId() */ public function setElementId(): void { - $this->elementId = substr(md5(mt_rand()), 0, 6); + $this->elementId = substr(md5((string) mt_rand()), 0, 6); } /** @@ -287,14 +288,24 @@ public function getNestedLevel() return $this->nestedLevel; } + /** + * Get comments start. + */ + public function getCommentsRangeStart(): ?Comments + { + return $this->commentsRangeStart; + } + /** * Get comment start. - * - * @return Comment */ - public function getCommentRangeStart() + public function getCommentRangeStart(): ?Comment { - return $this->commentRangeStart; + if ($this->commentsRangeStart != null) { + return $this->commentsRangeStart->getItem($this->commentsRangeStart->countItems()); + } + + return null; } /** @@ -305,18 +316,40 @@ public function setCommentRangeStart(Comment $value): void if ($this instanceof Comment) { throw new InvalidArgumentException('Cannot set a Comment on a Comment'); } - $this->commentRangeStart = $value; - $this->commentRangeStart->setStartElement($this); + if ($this->commentsRangeStart == null) { + $this->commentsRangeStart = new Comments(); + } + // Set ID early to avoid duplicates. + if ($value->getElementId() == null) { + $value->setElementId(); + } + foreach ($this->commentsRangeStart->getItems() as $comment) { + if ($value->getElementId() == $comment->getElementId()) { + return; + } + } + $idxItem = $this->commentsRangeStart->addItem($value); + $this->commentsRangeStart->getItem($idxItem)->setStartElement($this); + } + + /** + * Get comments end. + */ + public function getCommentsRangeEnd(): ?Comments + { + return $this->commentsRangeEnd; } /** * Get comment end. - * - * @return Comment */ - public function getCommentRangeEnd() + public function getCommentRangeEnd(): ?Comment { - return $this->commentRangeEnd; + if ($this->commentsRangeEnd != null) { + return $this->commentsRangeEnd->getItem($this->commentsRangeEnd->countItems()); + } + + return null; } /** @@ -327,8 +360,20 @@ public function setCommentRangeEnd(Comment $value): void if ($this instanceof Comment) { throw new InvalidArgumentException('Cannot set a Comment on a Comment'); } - $this->commentRangeEnd = $value; - $this->commentRangeEnd->setEndElement($this); + if ($this->commentsRangeEnd == null) { + $this->commentsRangeEnd = new Comments(); + } + // Set ID early to avoid duplicates. + if ($value->getElementId() == null) { + $value->setElementId(); + } + foreach ($this->commentsRangeEnd->getItems() as $comment) { + if ($value->getElementId() == $comment->getElementId()) { + return; + } + } + $idxItem = $this->commentsRangeEnd->addItem($value); + $this->commentsRangeEnd->getItem($idxItem)->setEndElement($this); } /** @@ -428,7 +473,7 @@ public function isInSection() * Set new style value. * * @param mixed $styleObject Style object - * @param null|array|\PhpOffice\PhpWord\Style|string $styleValue Style value + * @param null|array|string|Style $styleValue Style value * @param bool $returnObject Always return object * * @return mixed diff --git a/src/PhpWord/Element/Bookmark.php b/src/PhpWord/Element/Bookmark.php index 4fe3d0f067..151d5a48bf 100644 --- a/src/PhpWord/Element/Bookmark.php +++ b/src/PhpWord/Element/Bookmark.php @@ -1,4 +1,5 @@ startElement = $value; - if ($value->getCommentRangeStart() == null) { - $value->setCommentRangeStart($this); - } + $value->setCommentRangeStart($this); } /** * Get the element where this comment starts. * - * @return \PhpOffice\PhpWord\Element\AbstractElement + * @return AbstractElement */ public function getStartElement() { @@ -104,15 +103,13 @@ public function getStartElement() public function setEndElement(AbstractElement $value): void { $this->endElement = $value; - if ($value->getCommentRangeEnd() == null) { - $value->setCommentRangeEnd($this); - } + $value->setCommentRangeEnd($this); } /** * Get the element where this comment ends. * - * @return \PhpOffice\PhpWord\Element\AbstractElement + * @return AbstractElement */ public function getEndElement() { diff --git a/src/PhpWord/Element/Endnote.php b/src/PhpWord/Element/Endnote.php index 2888fdebc3..d2f42eafd0 100644 --- a/src/PhpWord/Element/Endnote.php +++ b/src/PhpWord/Element/Endnote.php @@ -1,4 +1,5 @@ baseTextRun = $baseTextRun; + $this->rubyTextRun = $rubyTextRun; + $this->properties = $properties; + } + + /** + * Get base text run. + */ + public function getBaseTextRun(): TextRun + { + return $this->baseTextRun; + } + + /** + * Set the base text run. + */ + public function setBaseTextRun(TextRun $textRun): self + { + $this->baseTextRun = $textRun; + + return $this; + } + + /** + * Get ruby text run. + */ + public function getRubyTextRun(): TextRun + { + return $this->rubyTextRun; + } + + /** + * Set the ruby text run. + */ + public function setRubyTextRun(TextRun $textRun): self + { + $this->rubyTextRun = $textRun; + + return $this; + } + + /** + * Get ruby properties. + */ + public function getProperties(): RubyProperties + { + return $this->properties; + } + + /** + * Set the ruby properties. + */ + public function setProperties(RubyProperties $properties): self + { + $this->properties = $properties; + + return $this; + } +} diff --git a/src/PhpWord/Element/SDT.php b/src/PhpWord/Element/SDT.php index 561cb9dd9e..62a66c0426 100644 --- a/src/PhpWord/Element/SDT.php +++ b/src/PhpWord/Element/SDT.php @@ -1,4 +1,5 @@ $collectionArray; if (in_array($type, [Header::AUTO, Header::FIRST, Header::EVEN])) { $index = count($collection); - /** @var \PhpOffice\PhpWord\Element\AbstractContainer $container Type hint */ + /** @var AbstractContainer $container Type hint */ $container = new $containerClass($this->sectionId, ++$index, $type); $container->setPhpWord($this->phpWord); diff --git a/src/PhpWord/Element/Shape.php b/src/PhpWord/Element/Shape.php index 15161f892e..9ea221db3b 100644 --- a/src/PhpWord/Element/Shape.php +++ b/src/PhpWord/Element/Shape.php @@ -1,4 +1,5 @@ phpWord->getTitles()->getItems(); foreach ($titles as $i => $title) { - /** @var \PhpOffice\PhpWord\Element\Title $title Type hint */ + /** @var Title $title Type hint */ $depth = $title->getDepth(); if ($this->minDepth > $depth) { unset($titles[$i]); @@ -110,7 +111,7 @@ public function getTitles() /** * Get TOC Style. * - * @return \PhpOffice\PhpWord\Style\TOC + * @return TOCStyle */ public function getStyleTOC() { @@ -120,7 +121,7 @@ public function getStyleTOC() /** * Get Font Style. * - * @return \PhpOffice\PhpWord\Style\Font|string + * @return Font|string */ public function getStyleFont() { diff --git a/src/PhpWord/Element/Table.php b/src/PhpWord/Element/Table.php index 53a828a9ea..7fb1030638 100644 --- a/src/PhpWord/Element/Table.php +++ b/src/PhpWord/Element/Table.php @@ -1,4 +1,5 @@ rows); for ($i = 0; $i < $rowCount; ++$i) { - /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ + /** @var Row $row Type hint */ $row = $this->rows[$i]; $cellCount = count($row->getCells()); if ($columnCount < $cellCount) { diff --git a/src/PhpWord/Element/Text.php b/src/PhpWord/Element/Text.php index 9695395324..ea5f5f87a4 100644 --- a/src/PhpWord/Element/Text.php +++ b/src/PhpWord/Element/Text.php @@ -1,4 +1,5 @@ getElements() as $element) { if ($element instanceof Text) { $outstr .= $element->getText(); + } elseif ($element instanceof Ruby) { + $outstr .= $element->getBaseTextRun()->getText() . + ' (' . $element->getRubyTextRun()->getText() . ')'; } } diff --git a/src/PhpWord/Element/Title.php b/src/PhpWord/Element/Title.php index 8fd5b21b1d..89f438a5ef 100644 --- a/src/PhpWord/Element/Title.php +++ b/src/PhpWord/Element/Title.php @@ -1,4 +1,5 @@ load($filename); @@ -100,7 +101,7 @@ public static function load($filename, $readerName = 'Word2007') */ public static function extractVariables(string $filename, string $readerName = 'Word2007'): array { - /** @var \PhpOffice\PhpWord\Reader\ReaderInterface $reader */ + /** @var ReaderInterface $reader */ $reader = self::createReader($readerName); $document = $reader->load($filename); $extractedVariables = []; diff --git a/src/PhpWord/Media.php b/src/PhpWord/Media.php index 31487a91fe..0a340a0a3c 100644 --- a/src/PhpWord/Media.php +++ b/src/PhpWord/Media.php @@ -1,4 +1,5 @@ collections[$key]; return $collectionObject->addItem($args[0] ?? null); @@ -152,7 +152,7 @@ public function __call($function, $args) /** * Get document properties object. * - * @return \PhpOffice\PhpWord\Metadata\DocInfo + * @return Metadata\DocInfo */ public function getDocInfo() { @@ -162,7 +162,7 @@ public function getDocInfo() /** * Get compatibility. * - * @return \PhpOffice\PhpWord\Metadata\Compatibility + * @return Metadata\Compatibility * * @since 0.12.0 */ @@ -174,7 +174,7 @@ public function getCompatibility() /** * Get compatibility. * - * @return \PhpOffice\PhpWord\Metadata\Settings + * @return Metadata\Settings * * @since 0.14.0 */ @@ -186,7 +186,7 @@ public function getSettings() /** * Get all sections. * - * @return \PhpOffice\PhpWord\Element\Section[] + * @return Section[] */ public function getSections() { @@ -198,7 +198,7 @@ public function getSections() * * @param int $index * - * @return null|\PhpOffice\PhpWord\Element\Section + * @return null|Section */ public function getSection($index) { @@ -214,7 +214,7 @@ public function getSection($index) * * @param null|array|string $style * - * @return \PhpOffice\PhpWord\Element\Section + * @return Section */ public function addSection($style = null) { @@ -257,6 +257,40 @@ public function setDefaultFontName($fontName): void Settings::setDefaultFontName($fontName); } + /** + * Get default asian font name. + */ + public function getDefaultAsianFontName(): string + { + return Settings::getDefaultAsianFontName(); + } + + /** + * Set default asian font name. + * + * @param string $fontName + */ + public function setDefaultAsianFontName($fontName): void + { + Settings::setDefaultAsianFontName($fontName); + } + + /** + * Set default font color. + */ + public function setDefaultFontColor(string $fontColor): void + { + Settings::setDefaultFontColor($fontColor); + } + + /** + * Get default font color. + */ + public function getDefaultFontColor(): string + { + return Settings::getDefaultFontColor(); + } + /** * Get default font size. * @@ -282,7 +316,7 @@ public function setDefaultFontSize($fontSize): void * * @param array $styles Paragraph style definition * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return Style\Paragraph */ public function setDefaultParagraphStyle($styles) { @@ -334,7 +368,7 @@ public function save($filename, $format = 'Word2007', $download = false) * * @param array $settings * - * @return \PhpOffice\PhpWord\Element\Section + * @return Section * * @codeCoverageIgnore */ @@ -348,7 +382,7 @@ public function createSection($settings = null) * * @deprecated 0.12.0 * - * @return \PhpOffice\PhpWord\Metadata\DocInfo + * @return Metadata\DocInfo * * @codeCoverageIgnore */ @@ -362,7 +396,7 @@ public function getDocumentProperties() * * @deprecated 0.12.0 * - * @param \PhpOffice\PhpWord\Metadata\DocInfo $documentProperties + * @param Metadata\DocInfo $documentProperties * * @return self * diff --git a/src/PhpWord/Reader/AbstractReader.php b/src/PhpWord/Reader/AbstractReader.php index da5e6f6e19..3c70834d16 100644 --- a/src/PhpWord/Reader/AbstractReader.php +++ b/src/PhpWord/Reader/AbstractReader.php @@ -1,4 +1,5 @@ dataWorkDocument, $arrayRGFC[$key] + $inc); + for ($inc = 0; $inc < ($strLen * 2); ++$inc) { + $byte = self::getInt2d($this->dataWorkDocument, $arrayRGFC[$key] + ($inc * 2)); if ($byte > 0) { - $string .= chr($byte); + $string .= mb_chr($byte, 'UTF-8'); + } else { + break; } } } @@ -2331,7 +2334,7 @@ private function generatePhpWord(): void foreach ($this->arrayParagraphs as $itmParagraph) { $textPara = $itmParagraph; foreach ($this->arrayCharacters as $oCharacters) { - $subText = substr($textPara, $oCharacters->pos_start, $oCharacters->pos_len); + $subText = mb_substr($textPara, $oCharacters->pos_start, $oCharacters->pos_len); $subText = str_replace(chr(13), PHP_EOL, $subText); $arrayText = explode(PHP_EOL, $subText); if (end($arrayText) == '') { diff --git a/src/PhpWord/Reader/ODText.php b/src/PhpWord/Reader/ODText.php index d7f8344443..288bf9a0dd 100644 --- a/src/PhpWord/Reader/ODText.php +++ b/src/PhpWord/Reader/ODText.php @@ -1,4 +1,5 @@ setRels($relationships); $part->read($phpWord); diff --git a/src/PhpWord/Reader/ODText/AbstractPart.php b/src/PhpWord/Reader/ODText/AbstractPart.php index 4c89192edd..447c96f094 100644 --- a/src/PhpWord/Reader/ODText/AbstractPart.php +++ b/src/PhpWord/Reader/ODText/AbstractPart.php @@ -1,4 +1,5 @@ readFontStyle($xmlReader, $domNode); $nodes = $xmlReader->getElements('w:r', $domNode); foreach ($nodes as $node) { - $instrText = $xmlReader->getValue('w:instrText', $node); - if ($xmlReader->elementExists('w:fldChar', $node)) { - $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); - if ('begin' == $fldCharType) { - $ignoreText = true; - } elseif ('end' == $fldCharType) { - $ignoreText = false; - } + if ($xmlReader->elementExists('w:lastRenderedPageBreak', $node)) { + $parent->addPageBreak(); } + $instrText = $xmlReader->getValue('w:instrText', $node); if (null !== $instrText) { $textContent .= '{' . $instrText . '}'; } else { + if ($xmlReader->elementExists('w:fldChar', $node)) { + $fldCharType = $xmlReader->getAttribute('w:fldCharType', $node, 'w:fldChar'); + if ('begin' == $fldCharType) { + $ignoreText = true; + } elseif ('end' == $fldCharType) { + $ignoreText = false; + } + } if (false === $ignoreText) { $textContent .= $xmlReader->getValue('w:t', $node); } @@ -293,7 +300,8 @@ protected function readParagraph(XMLReader $xmlReader, DOMElement $domNode, $par if ($headingDepth !== null) { $textContent = null; $nodes = $xmlReader->getElements('w:r|w:hyperlink', $domNode); - if ($nodes->length === 1) { + $hasRubyElement = $xmlReader->elementExists('w:r/w:ruby', $domNode); + if ($nodes->length === 1 && !$hasRubyElement) { $textContent = htmlspecialchars($xmlReader->getValue('w:t', $nodes->item(0)), ENT_QUOTES, 'UTF-8'); } else { $textContent = new TextRun($paragraphStyle); @@ -447,7 +455,7 @@ private function getHeadingDepth(?array $paragraphStyle = null) /** * Read w:r. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $parent + * @param AbstractContainer $parent * @param string $docPart * @param mixed $paragraphStyle * @@ -581,9 +589,47 @@ protected function readRunChild(XMLReader $xmlReader, DOMElement $node, Abstract } } elseif ($node->nodeName == 'w:softHyphen') { $element = $parent->addText("\u{200c}", $fontStyle, $paragraphStyle); + } elseif ($node->nodeName == 'w:ruby') { + $rubyPropertiesNode = $xmlReader->getElement('w:rubyPr', $node); + $properties = $this->readRubyProperties($xmlReader, $rubyPropertiesNode); + // read base text node + $baseText = new TextRun($paragraphStyle); + $baseTextNode = $xmlReader->getElement('w:rubyBase/w:r', $node); + $this->readRun($xmlReader, $baseTextNode, $baseText, $docPart, $paragraphStyle); + // read the actual ruby text (e.g. furigana in Japanese) + $rubyText = new TextRun($paragraphStyle); + $rubyTextNode = $xmlReader->getElement('w:rt/w:r', $node); + $this->readRun($xmlReader, $rubyTextNode, $rubyText, $docPart, $paragraphStyle); + // add element to parent + $parent->addRuby($baseText, $rubyText, $properties); } } + /** + * Read w:rubyPr element. + * + * @param XMLReader $xmlReader reader for XML + * @param DOMElement $domNode w:RubyPr element + * + * @return RubyProperties ruby properties from element + */ + protected function readRubyProperties(XMLReader $xmlReader, DOMElement $domNode): RubyProperties + { + $rubyAlignment = $xmlReader->getElement('w:rubyAlign', $domNode)->getAttribute('w:val'); + $rubyHps = $xmlReader->getElement('w:hps', $domNode)->getAttribute('w:val'); // font face + $rubyHpsRaise = $xmlReader->getElement('w:hpsRaise', $domNode)->getAttribute('w:val'); // pts above base text + $rubyHpsBaseText = $xmlReader->getElement('w:hpsBaseText', $domNode)->getAttribute('w:val'); // base text size + $rubyLid = $xmlReader->getElement('w:lid', $domNode)->getAttribute('w:val'); // type of ruby + $properties = new RubyProperties(); + $properties->setAlignment($rubyAlignment); + $properties->setFontFaceSize((float) $rubyHps); + $properties->setFontPointsAboveBaseText((float) $rubyHpsRaise); + $properties->setFontSizeForBaseText((float) $rubyHpsBaseText); + $properties->setLanguageId($rubyLid); + + return $properties; + } + /** * Read w:tbl. * @@ -658,8 +704,10 @@ protected function readParagraphStyle(XMLReader $xmlReader, DOMElement $domNode) 'alignment' => [self::READ_VALUE, 'w:jc'], 'basedOn' => [self::READ_VALUE, 'w:basedOn'], 'next' => [self::READ_VALUE, 'w:next'], - 'indent' => [self::READ_VALUE, 'w:ind', 'w:left'], - 'hanging' => [self::READ_VALUE, 'w:ind', 'w:hanging'], + 'indentLeft' => [self::READ_VALUE, 'w:ind', 'w:left'], + 'indentRight' => [self::READ_VALUE, 'w:ind', 'w:right'], + 'indentHanging' => [self::READ_VALUE, 'w:ind', 'w:hanging'], + 'indentFirstLine' => [self::READ_VALUE, 'w:ind', 'w:firstLine'], 'spaceAfter' => [self::READ_VALUE, 'w:spacing', 'w:after'], 'spaceBefore' => [self::READ_VALUE, 'w:spacing', 'w:before'], 'widowControl' => [self::READ_FALSE, 'w:widowControl'], diff --git a/src/PhpWord/Reader/Word2007/DocPropsApp.php b/src/PhpWord/Reader/Word2007/DocPropsApp.php index 9d6f3cbbe9..c7ecb007b3 100644 --- a/src/PhpWord/Reader/Word2007/DocPropsApp.php +++ b/src/PhpWord/Reader/Word2007/DocPropsApp.php @@ -1,4 +1,5 @@ */ private function readWPNode(XMLReader $xmlReader, DOMElement $node, Section &$section): void { diff --git a/src/PhpWord/Reader/Word2007/Endnotes.php b/src/PhpWord/Reader/Word2007/Endnotes.php index 0c6b18db37..6ab4203579 100644 --- a/src/PhpWord/Reader/Word2007/Endnotes.php +++ b/src/PhpWord/Reader/Word2007/Endnotes.php @@ -1,4 +1,5 @@ setDefaultFontSize($fontDefaultStyle['size']); } + if (array_key_exists('color', $fontDefaultStyle)) { + $phpWord->setDefaultFontColor($fontDefaultStyle['color']); + } if (array_key_exists('lang', $fontDefaultStyle)) { $phpWord->getSettings()->setThemeFontLang(new Language($fontDefaultStyle['lang'])); } diff --git a/src/PhpWord/Settings.php b/src/PhpWord/Settings.php index 984486ccfe..16f49166fa 100644 --- a/src/PhpWord/Settings.php +++ b/src/PhpWord/Settings.php @@ -1,4 +1,5 @@ cssContent); preg_match_all('/(.+?)\s?\{\s?(.+?)\s?\}/', $cssContent, $cssExtracted); - // Check the number of extracted - if (count($cssExtracted) != 3) { - return; - } // Check if there are x selectors and x rules if (count($cssExtracted[1]) != count($cssExtracted[2])) { return; diff --git a/src/PhpWord/Shared/Drawing.php b/src/PhpWord/Shared/Drawing.php index df218108d9..8af7da2ffc 100644 --- a/src/PhpWord/Shared/Drawing.php +++ b/src/PhpWord/Shared/Drawing.php @@ -1,4 +1,5 @@ . * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element Where the parts need to be added + * @param AbstractContainer $element Where the parts need to be added * @param string $html The code to parse * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag * @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed @@ -130,21 +133,21 @@ protected static function parseInlineStyle($node, $styles = []) break; case 'width': // tables, cells + $val = $val === 'auto' ? '100%' : $val; if (false !== strpos($val, '%')) { // e.g. or
$styles['width'] = (int) $val * 50; $styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT; } else { // e.g. , where "2" = 2px (always pixels) - $val = (int) $val . 'px'; - $styles['cellSpacing'] = Converter::cssToTwip($val); + $styles['cellSpacing'] = Converter::pixelToTwip(self::convertHtmlSize($val)); break; case 'bgcolor': @@ -188,7 +191,7 @@ protected static function parseInlineStyle($node, $styles = []) * Parse a node and add a corresponding element to the parent element. * * @param DOMNode $node node to parse - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element object to add an element corresponding with the node + * @param AbstractContainer $element object to add an element corresponding with the node * @param array $styles Array with all styles * @param array $data Array to transport data to a next level in the DOM tree, for example level of listitems */ @@ -241,6 +244,7 @@ protected static function parseNode($node, $element, $styles = [], $data = []): 'a' => ['Link', $node, $element, $styles, null, null, null], 'input' => ['Input', $node, $element, $styles, null, null, null], 'hr' => ['HorizRule', $node, $element, $styles, null, null, null], + 'ruby' => ['Ruby', $node, $element, $styles, null, null, null], ]; $newElement = null; @@ -279,7 +283,7 @@ protected static function parseNode($node, $element, $styles = [], $data = []): * Parse child nodes. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer|Row|Table $element + * @param AbstractContainer|Row|Table $element * @param array $styles * @param array $data */ @@ -301,10 +305,10 @@ protected static function parseChildNodes($node, $element, $styles, $data): void * Parse paragraph node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * - * @return \PhpOffice\PhpWord\Element\PageBreak|\PhpOffice\PhpWord\Element\TextRun + * @return \PhpOffice\PhpWord\Element\PageBreak|TextRun */ protected static function parseParagraph($node, $element, &$styles) { @@ -320,7 +324,7 @@ protected static function parseParagraph($node, $element, &$styles) * Parse input node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles */ protected static function parseInput($node, $element, &$styles): void @@ -344,11 +348,11 @@ protected static function parseInput($node, $element, &$styles): void /** * Parse heading node. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * @param string $argument1 Name of heading style * - * @return \PhpOffice\PhpWord\Element\TextRun + * @return TextRun * * @todo Think of a clever way of defining header styles, now it is only based on the assumption, that * Heading1 - Heading6 are already defined somewhere @@ -365,7 +369,7 @@ protected static function parseHeading($element, &$styles, $argument1) * Parse text node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles */ protected static function parseText($node, $element, &$styles): void @@ -409,7 +413,7 @@ protected static function parseSpan($node, &$styles): void * Parse table node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * * @return Table $element @@ -441,7 +445,7 @@ protected static function parseTable($node, $element, &$styles) * Parse a table row. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\Table $element + * @param Table $element * @param array &$styles * * @return Row $element @@ -464,10 +468,10 @@ protected static function parseRow($node, $element, &$styles) * Parse table cell. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\Table $element + * @param Table $element * @param array &$styles * - * @return \PhpOffice\PhpWord\Element\Cell|\PhpOffice\PhpWord\Element\TextRun $element + * @return \PhpOffice\PhpWord\Element\Cell|TextRun $element */ protected static function parseCell($node, $element, &$styles) { @@ -558,7 +562,7 @@ protected static function filterOutNonInheritedStyles(array $styles) * Parse list node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * @param array &$data */ @@ -631,15 +635,15 @@ protected static function getListStyle($isOrderedList) return [ 'type' => 'hybridMultilevel', 'levels' => [ - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => 'o', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], - ['format' => NumberFormat::BULLET, 'text' => '', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 720, 'left' => 720, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '◦', 'alignment' => 'left', 'tabPos' => 1440, 'left' => 1440, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 2160, 'left' => 2160, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 2880, 'left' => 2880, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '◦', 'alignment' => 'left', 'tabPos' => 3600, 'left' => 3600, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 4320, 'left' => 4320, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 5040, 'left' => 5040, 'hanging' => 360, 'font' => 'Symbol', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '◦', 'alignment' => 'left', 'tabPos' => 5760, 'left' => 5760, 'hanging' => 360, 'font' => 'Courier New', 'hint' => 'default'], + ['format' => NumberFormat::BULLET, 'text' => '•', 'alignment' => 'left', 'tabPos' => 6480, 'left' => 6480, 'hanging' => 360, 'font' => 'Wingdings', 'hint' => 'default'], ], ]; } @@ -648,7 +652,7 @@ protected static function getListStyle($isOrderedList) * Parse list item node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array &$styles * @param array $data * @@ -708,6 +712,10 @@ protected static function parseStyleDeclarations(array $selectors, array $styles case 'text-align': $styles['alignment'] = self::mapAlign($value, $bidi); + break; + case 'ruby-align': + $styles['rubyAlignment'] = self::mapRubyAlign($value); + break; case 'display': $styles['hidden'] = $value === 'none' || $value === 'hidden'; @@ -807,6 +815,58 @@ protected static function parseStyleDeclarations(array $selectors, array $styles $styles['spaceAfter'] = Converter::cssToTwip($value); break; + + case 'padding': + $valueTop = $valueRight = $valueBottom = $valueLeft = null; + $cValue = preg_replace('# +#', ' ', trim($value)); + $paddingArr = explode(' ', $cValue); + $countParams = count($paddingArr); + if ($countParams == 1) { + $valueTop = $valueRight = $valueBottom = $valueLeft = $paddingArr[0]; + } elseif ($countParams == 2) { + $valueTop = $valueBottom = $paddingArr[0]; + $valueRight = $valueLeft = $paddingArr[1]; + } elseif ($countParams == 3) { + $valueTop = $paddingArr[0]; + $valueRight = $valueLeft = $paddingArr[1]; + $valueBottom = $paddingArr[2]; + } elseif ($countParams == 4) { + $valueTop = $paddingArr[0]; + $valueRight = $paddingArr[1]; + $valueBottom = $paddingArr[2]; + $valueLeft = $paddingArr[3]; + } + if ($valueTop !== null) { + $styles['paddingTop'] = Converter::cssToTwip($valueTop); + } + if ($valueRight !== null) { + $styles['paddingRight'] = Converter::cssToTwip($valueRight); + } + if ($valueBottom !== null) { + $styles['paddingBottom'] = Converter::cssToTwip($valueBottom); + } + if ($valueLeft !== null) { + $styles['paddingLeft'] = Converter::cssToTwip($valueLeft); + } + + break; + case 'padding-top': + $styles['paddingTop'] = Converter::cssToTwip($value); + + break; + case 'padding-right': + $styles['paddingRight'] = Converter::cssToTwip($value); + + break; + case 'padding-bottom': + $styles['paddingBottom'] = Converter::cssToTwip($value); + + break; + case 'padding-left': + $styles['paddingLeft'] = Converter::cssToTwip($value); + + break; + case 'border-color': self::mapBorderColor($styles, $value); @@ -907,7 +967,7 @@ protected static function parseStyleDeclarations(array $selectors, array $styles * Parse image node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * * @return \PhpOffice\PhpWord\Element\Image */ @@ -922,36 +982,12 @@ protected static function parseImage($node, $element) break; case 'width': - $width = $attribute->value; - - // pt - if (false !== strpos($width, 'pt')) { - $width = Converter::pointToPixel((float) str_replace('pt', '', $width)); - } - - // px - if (false !== strpos($width, 'px')) { - $width = str_replace('px', '', $width); - } - - $style['width'] = $width; + $style['width'] = self::convertHtmlSize($attribute->value); $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; break; case 'height': - $height = $attribute->value; - - // pt - if (false !== strpos($height, 'pt')) { - $height = Converter::pointToPixel((float) str_replace('pt', '', $height)); - } - - // px - if (false !== strpos($height, 'px')) { - $height = str_replace('px', '', $height); - } - - $style['height'] = $height; + $style['height'] = self::convertHtmlSize($attribute->value); $style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX; break; @@ -991,14 +1027,15 @@ protected static function parseImage($node, $element) $match = []; preg_match('/data:image\/(\w+);base64,(.+)/', $src, $match); + if (!empty($match)) { + $src = $imgFile = $tmpDir . uniqid() . '.' . $match[1]; - $src = $imgFile = $tmpDir . uniqid() . '.' . $match[1]; - - $ifp = fopen($imgFile, 'wb'); + $ifp = fopen($imgFile, 'wb'); - if ($ifp !== false) { - fwrite($ifp, base64_decode($match[2])); - fclose($ifp); + if ($ifp !== false) { + fwrite($ifp, base64_decode($match[2])); + fclose($ifp); + } } } $src = urldecode($src); @@ -1096,6 +1133,23 @@ protected static function mapAlign($cssAlignment, $bidi) } } + /** + * Transforms a HTML/CSS ruby alignment into a \PhpOffice\PhpWord\SimpleType\Jc. + */ + protected static function mapRubyAlign(string $cssRubyAlignment): string + { + switch ($cssRubyAlignment) { + case 'center': + return RubyProperties::ALIGNMENT_CENTER; + case 'start': + return RubyProperties::ALIGNMENT_LEFT; + case 'space-between': + return RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE; + default: + return ''; + } + } + /** * Transforms a HTML/CSS vertical alignment. * @@ -1152,7 +1206,7 @@ protected static function mapListType($cssListType) /** * Parse line break. * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element */ protected static function parseLineBreak($element): void { @@ -1163,7 +1217,7 @@ protected static function parseLineBreak($element): void * Parse link node. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element * @param array $styles */ protected static function parseLink($node, $element, &$styles) @@ -1179,7 +1233,11 @@ protected static function parseLink($node, $element, &$styles) } $styles['font'] = self::parseInlineStyle($node, $styles['font']); - if (strpos($target, '#') === 0) { + if (empty($target)) { + $target = '#'; + } + + if (strpos($target, '#') === 0 && strlen($target) > 1) { return $element->addLink(substr($target, 1), $node->textContent, $styles['font'], $styles['paragraph'], true); } @@ -1191,7 +1249,7 @@ protected static function parseLink($node, $element, &$styles) * Note: Word rule is not the same as HTML's
since it does not support width and thus neither alignment. * * @param DOMNode $node - * @param \PhpOffice\PhpWord\Element\AbstractContainer $element + * @param AbstractContainer $element */ protected static function parseHorizRule($node, $element): void { @@ -1220,6 +1278,59 @@ protected static function parseHorizRule($node, $element): void // - repeated text, e.g. underline "_", because of unpredictable line wrapping } + /** + * Parse ruby node. + * + * @param DOMNode $node + * @param AbstractContainer $element + * @param array $styles + */ + protected static function parseRuby($node, $element, &$styles) + { + $rubyProperties = new RubyProperties(); + $baseTextRun = new TextRun($styles['paragraph']); + $rubyTextRun = new TextRun(null); + if ($node->hasAttributes()) { + $langAttr = $node->attributes->getNamedItem('lang'); + if ($langAttr !== null) { + $rubyProperties->setLanguageId($langAttr->textContent); + } + $styleAttr = $node->attributes->getNamedItem('style'); + if ($styleAttr !== null) { + $styles = self::parseStyle($styleAttr, $styles['paragraph']); + if (isset($styles['rubyAlignment']) && $styles['rubyAlignment'] !== '') { + $rubyProperties->setAlignment($styles['rubyAlignment']); + } + if (isset($styles['size']) && $styles['size'] !== '') { + $rubyProperties->setFontSizeForBaseText($styles['size']); + } + $baseTextRun->setParagraphStyle($styles); + } + } + foreach ($node->childNodes as $child) { + if ($child->nodeName === '#text') { + $content = trim($child->textContent); + if ($content !== '') { + $baseTextRun->addText($content); + } + } elseif ($child->nodeName === 'rt') { + $rubyTextRun->addText(trim($child->textContent)); + if ($child->hasAttributes()) { + $styleAttr = $child->attributes->getNamedItem('style'); + if ($styleAttr !== null) { + $styles = self::parseStyle($styleAttr, []); + if (isset($styles['size']) && $styles['size'] !== '') { + $rubyProperties->setFontFaceSize($styles['size']); + } + $rubyTextRun->setParagraphStyle($styles); + } + } + } + } + + return $element->addRuby($baseTextRun, $rubyTextRun, $rubyProperties); + } + private static function convertRgb(string $rgb): string { if (preg_match(self::RGB_REGEXP, $rgb, $matches) === 1) { @@ -1228,4 +1339,22 @@ private static function convertRgb(string $rgb): string return trim($rgb, '# '); } + + /** + * Transform HTML sizes (pt, px) in pixels. + */ + protected static function convertHtmlSize(string $size): float + { + // pt + if (false !== strpos($size, 'pt')) { + return Converter::pointToPixel((float) str_replace('pt', '', $size)); + } + + // px + if (false !== strpos($size, 'px')) { + return (float) str_replace('px', '', $size); + } + + return (float) $size; + } } diff --git a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php index d6cf69fc6d..45f9a53632 100644 --- a/src/PhpWord/Shared/Microsoft/PasswordEncoder.php +++ b/src/PhpWord/Shared/Microsoft/PasswordEncoder.php @@ -1,4 +1,5 @@ tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename'], 'wb'); - fwrite($handle, $contents); - fclose($handle); + if ($handle) { + fwrite($handle, $contents); + fclose($handle); + } // Add temp file to zip $filename = $this->tempDir . DIRECTORY_SEPARATOR . $filenameParts['basename']; diff --git a/src/PhpWord/SimpleType/Border.php b/src/PhpWord/SimpleType/Border.php index 6cb42f0467..acd1c1a1b1 100644 --- a/src/PhpWord/SimpleType/Border.php +++ b/src/PhpWord/SimpleType/Border.php @@ -1,4 +1,5 @@ vAlign = null; + + return $this; + } + VerticalJc::validate($value); $this->vAlign = $this->setEnumVal($value, VerticalJc::values(), $this->vAlign); @@ -235,7 +262,7 @@ public function setGridSpan($value = null) /** * Get vertical merge (rowspan). * - * @return string + * @return null|string */ public function getVMerge() { @@ -245,12 +272,18 @@ public function getVMerge() /** * Set vertical merge (rowspan). * - * @param string $value + * @param null|string $value * * @return self */ public function setVMerge($value = null) { + if ($value === null) { + $this->vMerge = null; + + return $this; + } + $enum = [self::VMERGE_RESTART, self::VMERGE_CONTINUE]; $this->vMerge = $this->setEnumVal($value, $enum, $this->vMerge); @@ -260,7 +293,7 @@ public function setVMerge($value = null) /** * Get shading. * - * @return \PhpOffice\PhpWord\Style\Shading + * @return Shading */ public function getShading() { @@ -344,4 +377,84 @@ public function getNoWrap(): bool { return $this->noWrap; } + + /** + * Get style padding-top. + */ + public function getPaddingTop(): ?int + { + return $this->paddingTop; + } + + /** + * Set style padding-top. + * + * @return $this + */ + public function setPaddingTop(int $value): self + { + $this->paddingTop = $value; + + return $this; + } + + /** + * Get style padding-bottom. + */ + public function getPaddingBottom(): ?int + { + return $this->paddingBottom; + } + + /** + * Set style padding-bottom. + * + * @return $this + */ + public function setPaddingBottom(int $value): self + { + $this->paddingBottom = $value; + + return $this; + } + + /** + * Get style padding-left. + */ + public function getPaddingLeft(): ?int + { + return $this->paddingLeft; + } + + /** + * Set style padding-left. + * + * @return $this + */ + public function setPaddingLeft(int $value): self + { + $this->paddingLeft = $value; + + return $this; + } + + /** + * Get style padding-right. + */ + public function getPaddingRight(): ?int + { + return $this->paddingRight; + } + + /** + * Set style padding-right. + * + * @return $this + */ + public function setPaddingRight(int $value): self + { + $this->paddingRight = $value; + + return $this; + } } diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php index 9dbc8db0a6..6cffc4d5b0 100644 --- a/src/PhpWord/Style/Chart.php +++ b/src/PhpWord/Style/Chart.php @@ -1,4 +1,5 @@ strikethrough; } @@ -577,20 +576,16 @@ public function isStrikethrough() * Set strikethrough. * * @param bool $value - * - * @return self */ - public function setStrikethrough($value = true) + public function setStrikethrough($value = true): self { return $this->setPairedVal($this->strikethrough, $this->doubleStrikethrough, $value); } /** * Get double strikethrough. - * - * @return bool */ - public function isDoubleStrikethrough() + public function isDoubleStrikethrough(): ?bool { return $this->doubleStrikethrough; } @@ -599,10 +594,8 @@ public function isDoubleStrikethrough() * Set double strikethrough. * * @param bool $value - * - * @return self */ - public function setDoubleStrikethrough($value = true) + public function setDoubleStrikethrough($value = true): self { return $this->setPairedVal($this->doubleStrikethrough, $this->strikethrough, $value); } @@ -690,7 +683,7 @@ public function getBgColor() * * @param string $value * - * @return \PhpOffice\PhpWord\Style\Table + * @return Table */ public function setBgColor($value = null) { @@ -820,7 +813,7 @@ public function setLineHeight($value) /** * Get paragraph style. * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return Paragraph */ public function getParagraph() { @@ -868,7 +861,7 @@ public function setRTL($value = true) /** * Get shading. * - * @return \PhpOffice\PhpWord\Style\Shading + * @return Shading */ public function getShading() { @@ -892,7 +885,7 @@ public function setShading($value = null) /** * Get language. * - * @return null|\PhpOffice\PhpWord\Style\Language + * @return null|Language */ public function getLang() { diff --git a/src/PhpWord/Style/Frame.php b/src/PhpWord/Style/Frame.php index 45fc583ed1..016722f36c 100644 --- a/src/PhpWord/Style/Frame.php +++ b/src/PhpWord/Style/Frame.php @@ -1,4 +1,5 @@ left; } /** * Set left. - * - * @param float|int $value - * - * @return self */ - public function setLeft($value) + public function setLeft(?float $value): self { - $this->left = $this->setNumericVal($value, $this->left); + $this->left = $this->setNumericVal($value); return $this; } /** * Get right. - * - * @return float|int */ - public function getRight() + public function getRight(): ?float { return $this->right; } /** * Set right. - * - * @param float|int $value - * - * @return self */ - public function setRight($value) + public function setRight(?float $value): self { - $this->right = $this->setNumericVal($value, $this->right); + $this->right = $this->setNumericVal($value); return $this; } /** * Get first line. - * - * @return float|int */ - public function getFirstLine() + public function getFirstLine(): ?float { return $this->firstLine; } /** * Set first line. - * - * @param float|int $value - * - * @return self */ - public function setFirstLine($value) + public function setFirstLine(?float $value): self { - $this->firstLine = $this->setNumericVal($value, $this->firstLine); + $this->firstLine = $this->setNumericVal($value); return $this; } /** * Get hanging. - * - * @return float|int */ - public function getHanging() + public function getHanging(): ?float { return $this->hanging; } /** * Set hanging. - * - * @param float|int $value - * - * @return self */ - public function setHanging($value = null) + public function setHanging(?float $value = null): self { - $this->hanging = $this->setNumericVal($value, $this->hanging); + $this->hanging = $this->setNumericVal($value); return $this; } diff --git a/src/PhpWord/Style/Language.php b/src/PhpWord/Style/Language.php index 18e7f76e77..54e4376562 100644 --- a/src/PhpWord/Style/Language.php +++ b/src/PhpWord/Style/Language.php @@ -1,4 +1,5 @@ numId; } /** * Set Id. - * - * @param int $value - * - * @return self */ - public function setNumId($value) + public function setNumId(int $value): self { $this->numId = $this->setIntVal($value, $this->numId); @@ -78,22 +73,16 @@ public function setNumId($value) /** * Get multilevel type. - * - * @return string */ - public function getType() + public function getType(): ?string { return $this->type; } /** * Set multilevel type. - * - * @param string $value - * - * @return self */ - public function setType($value) + public function setType(string $value): self { $enum = ['singleLevel', 'multilevel', 'hybridMultilevel']; $this->type = $this->setEnumVal($value, $enum, $this->type); @@ -106,19 +95,15 @@ public function setType($value) * * @return NumberingLevel[] */ - public function getLevels() + public function getLevels(): array { return $this->levels; } /** * Set multilevel type. - * - * @param array $values - * - * @return self */ - public function setLevels($values) + public function setLevels(array $values): self { if (is_array($values)) { foreach ($values as $key => $value) { diff --git a/src/PhpWord/Style/NumberingLevel.php b/src/PhpWord/Style/NumberingLevel.php index 39c0d839d6..31ec3738c8 100644 --- a/src/PhpWord/Style/NumberingLevel.php +++ b/src/PhpWord/Style/NumberingLevel.php @@ -1,4 +1,5 @@ getChildStyleValue($this->indentation, 'hanging'); + } + /** * Get indentation. * - * @return null|\PhpOffice\PhpWord\Style\Indentation + * @deprecated 1.4.0 Use getIndentLeft + */ + public function getIndent(): ?float + { + return $this->getChildStyleValue($this->indentation, 'left'); + } + + /** + * Get indentation. */ - public function getIndentation() + public function getIndentation(): ?Indentation { return $this->indentation; } /** - * Set shading. - * - * @param mixed $value - * - * @return self + * Get firstLine. */ - public function setIndentation($value = null) + public function getIndentFirstLine(): ?float { - $this->setObjectVal($value, 'Indentation', $this->indentation); + return $this->getChildStyleValue($this->indentation, 'firstLine'); + } - return $this; + /** + * Get left indentation. + */ + public function getIndentLeft(): ?float + { + return $this->getChildStyleValue($this->indentation, 'left'); } /** - * Get indentation. + * Get right indentation. + */ + public function getIndentRight(): ?float + { + return $this->getChildStyleValue($this->indentation, 'right'); + } + + /** + * Set hanging. * - * @return int + * @deprecated 1.4.0 Use setIndentHanging */ - public function getIndent() + public function setHanging(?float $value = null): self { - return $this->getChildStyleValue($this->indentation, 'left'); + return $this->setIndentation(['hanging' => $value]); } /** * Set indentation. * - * @param int $value - * - * @return self + * @deprecated 1.4.0 Use setIndentLeft */ - public function setIndent($value = null) + public function setIndent(?float $value = null): self { return $this->setIndentation(['left' => $value]); } /** - * Get hanging. + * Set indentation. * - * @return int + * @param array{ + * left?:null|float|int|numeric-string, + * right?:null|float|int|numeric-string, + * hanging?:null|float|int|numeric-string, + * firstLine?:null|float|int|numeric-string + * } $value */ - public function getHanging() + public function setIndentation(array $value = []): self { - return $this->getChildStyleValue($this->indentation, 'hanging'); + $value = array_map(function ($indent) { + if (is_string($indent) || is_numeric($indent)) { + $indent = $this->setFloatVal($indent); + } + + return $indent; + }, $value); + $this->setObjectVal($value, 'Indentation', $this->indentation); + + return $this; } /** - * Set hanging. - * - * @param int $value - * - * @return self + * Set hanging indentation. */ - public function setHanging($value = null) + public function setIndentHanging(?float $value = null): self { return $this->setIndentation(['hanging' => $value]); } + /** + * Set firstline indentation. + */ + public function setIndentFirstLine(?float $value = null): self + { + return $this->setIndentation(['firstLine' => $value]); + } + + /** + * Set left indentation. + */ + public function setIndentLeft(?float $value = null): self + { + return $this->setIndentation(['left' => $value]); + } + + /** + * Set right indentation. + */ + public function setIndentRight(?float $value = null): self + { + return $this->setIndentation(['right' => $value]); + } + /** * Get spacing. * - * @return \PhpOffice\PhpWord\Style\Spacing + * @return Spacing * * @todo Rename to getSpacing in 1.0 */ @@ -474,7 +533,7 @@ public function getSpacingLineRule() * * @param string $value Possible values are defined in LineSpacingRule * - * @return \PhpOffice\PhpWord\Style\Paragraph + * @return Paragraph */ public function setSpacingLineRule($value) { @@ -662,7 +721,7 @@ public function setNumLevel($value = 0) /** * Get tabs. * - * @return \PhpOffice\PhpWord\Style\Tab[] + * @return Tab[] */ public function getTabs() { @@ -688,7 +747,7 @@ public function setTabs($value = null) /** * Get shading. * - * @return \PhpOffice\PhpWord\Style\Shading + * @return Shading */ public function getShading() { diff --git a/src/PhpWord/Style/Row.php b/src/PhpWord/Style/Row.php index 765c54f80e..31ae3dedc1 100644 --- a/src/PhpWord/Style/Row.php +++ b/src/PhpWord/Style/Row.php @@ -1,4 +1,5 @@ zip()->AddFromString("word/media/image1.jpg", file_get_contents($file));
* To read a file: $templateProcessor->zip()->getFromName("word/media/image1.jpg"); * - * @return \PhpOffice\PhpWord\Shared\ZipArchive + * @return ZipArchive */ public function zip() { @@ -281,7 +281,7 @@ public function setComplexValue($search, Element\AbstractElement $complexType): $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; $xmlWriter = new XMLWriter(); - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $elementWriter */ + /** @var Writer\Word2007\Element\AbstractElement $elementWriter */ $elementWriter = new $objectClass($xmlWriter, $complexType, true); $elementWriter->write(); @@ -308,7 +308,7 @@ public function setComplexBlock($search, Element\AbstractElement $complexType): $objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $elementName; $xmlWriter = new XMLWriter(); - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $elementWriter */ + /** @var Writer\Word2007\Element\AbstractElement $elementWriter */ $elementWriter = new $objectClass($xmlWriter, $complexType, false); $elementWriter->write(); @@ -406,7 +406,7 @@ public function setChart($search, Element\AbstractElement $chart): void $filename = "charts/chart{$rId}.xml"; // Get the part writer - $writerPart = new \PhpOffice\PhpWord\Writer\Word2007\Part\Chart(); + $writerPart = new Writer\Word2007\Part\Chart(); $writerPart->setElement($chart); // ContentTypes.xml @@ -499,20 +499,22 @@ private function fixImageWidthHeightRatio(&$width, &$height, $actualWidth, $actu $widthFloat = $heightFloat * $imageRatio; $matches = []; preg_match('/\\d([a-z%]+)$/', $height, $matches); - $width = $widthFloat . $matches[1]; + $width = $widthFloat . (!empty($matches) ? $matches[1] : 'px'); } elseif ($height === '') { // defined height is empty $widthFloat = (float) $width; $heightFloat = $widthFloat / $imageRatio; $matches = []; preg_match('/\\d([a-z%]+)$/', $width, $matches); - $height = $heightFloat . $matches[1]; + $height = $heightFloat . (!empty($matches) ? $matches[1] : 'px'); } else { // we have defined size, but we need also check it aspect ratio $widthMatches = []; preg_match('/\\d([a-z%]+)$/', $width, $widthMatches); $heightMatches = []; preg_match('/\\d([a-z%]+)$/', $height, $heightMatches); // try to fix only if dimensions are same - if ($widthMatches[1] == $heightMatches[1]) { + if (!empty($widthMatches) + && !empty($heightMatches) + && $widthMatches[1] == $heightMatches[1]) { $dimention = $widthMatches[1]; $widthFloat = (float) $width; $heightFloat = (float) $height; @@ -1287,7 +1289,7 @@ protected function getSlice($startPosition, $endPosition = 0) * @param int $count * @param string $xmlBlock * - * @return string + * @return array */ protected function indexClonedVariables($count, $xmlBlock) { @@ -1339,7 +1341,7 @@ protected function replaceClonedVariables($variableReplacements, $xmlBlock) * @param string $block New block content * @param string $blockType XML tag type of block * - * @return \PhpOffice\PhpWord\TemplateProcessor Fluent interface + * @return TemplateProcessor Fluent interface */ public function replaceXmlBlock($macro, $block, $blockType = 'w:p') { diff --git a/src/PhpWord/Writer/AbstractWriter.php b/src/PhpWord/Writer/AbstractWriter.php index 8ebf98c7b5..13859d8227 100644 --- a/src/PhpWord/Writer/AbstractWriter.php +++ b/src/PhpWord/Writer/AbstractWriter.php @@ -1,4 +1,5 @@ parts as $partName) { $partClass = 'PhpOffice\\PhpWord\\Writer\\HTML\\Part\\' . $partName; if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Writer\HTML\Part\AbstractPart $part Type hint */ + /** @var HTML\Part\AbstractPart $part Type hint */ $part = new $partClass(); $part->setParentWriter($this); $this->writerParts[strtolower($partName)] = $part; diff --git a/src/PhpWord/Writer/HTML/Element/AbstractElement.php b/src/PhpWord/Writer/HTML/Element/AbstractElement.php index 7c7bde3189..0e6a112eed 100644 --- a/src/PhpWord/Writer/HTML/Element/AbstractElement.php +++ b/src/PhpWord/Writer/HTML/Element/AbstractElement.php @@ -1,4 +1,5 @@ namespace, $elementClass); if (class_exists($writerClass)) { - /** @var \PhpOffice\PhpWord\Writer\HTML\Element\AbstractElement $writer Type hint */ + /** @var AbstractElement $writer Type hint */ $writer = new $writerClass($this->parentWriter, $element, $withoutP); $content .= $writer->write(); } diff --git a/src/PhpWord/Writer/HTML/Element/Endnote.php b/src/PhpWord/Writer/HTML/Element/Endnote.php index 1c35e8faa8..7e7f31d4fc 100644 --- a/src/PhpWord/Writer/HTML/Element/Endnote.php +++ b/src/PhpWord/Writer/HTML/Element/Endnote.php @@ -1,4 +1,5 @@ processFontStyle(); + + /** @var \PhpOffice\PhpWord\Element\Ruby $element Type hint */ + $element = $this->element; + + $baseText = $this->parentWriter->escapeHTML($element->getBaseTextRun()->getText()); + $rubyText = $this->parentWriter->escapeHTML($element->getRubyTextRun()->getText()); + + $rubyTagPropertyCSS = $this->getPropertyCssForRubyTag($element->getProperties()); + $lang = $element->getProperties()->getLanguageId(); + $content = "getParagraphStyleForTextRun($element->getBaseTextRun(), $rubyTagPropertyCSS)} lang=\"{$lang}\">"; + $content .= $baseText; + $content .= ' ('; + $rtTagPropertyCSS = $this->getPropertyCssForRtTag($element->getProperties()); + $content .= "getParagraphStyleForTextRun($element->getRubyTextRun(), $rtTagPropertyCSS)}>"; + $content .= $rubyText; + $content .= ''; + $content .= ')'; + $content .= ''; + + return $content; + } + + /** + * Get property CSS for the tag. + */ + private function getPropertyCssForRubyTag(RubyProperties $properties): string + { + // alignment CSS: https://developer.mozilla.org/en-US/docs/Web/CSS/ruby-align + $alignment = 'space-between'; + switch ($properties->getAlignment()) { + case RubyProperties::ALIGNMENT_CENTER: + $alignment = 'center'; + + break; + case RubyProperties::ALIGNMENT_LEFT: + $alignment = 'start'; + + break; + default: + $alignment = 'space-between'; + + break; + } + + return + 'font-size:' . $properties->getFontSizeForBaseText() . 'pt' . ';' . + 'ruby-align:' . $alignment . ';'; + } + + /** + * Get property CSS for the tag. + */ + private function getPropertyCssForRtTag(RubyProperties $properties): string + { + // alignment CSS: https://developer.mozilla.org/en-US/docs/Web/CSS/ruby-align + return 'font-size:' . $properties->getFontFaceSize() . 'pt' . ';'; + } + + /** + * Write paragraph style for a given TextRun. + */ + private function getParagraphStyleForTextRun(TextRun $textRun, string $extraCSS): string + { + $style = ''; + if (!method_exists($textRun, 'getParagraphStyle')) { + return $style; + } + + $paragraphStyle = $textRun->getParagraphStyle(); + $pStyleIsObject = ($paragraphStyle instanceof Paragraph); + if ($pStyleIsObject) { + $styleWriter = new ParagraphStyleWriter($paragraphStyle); + $styleWriter->setParentWriter($this->parentWriter); + $style = $styleWriter->write(); + } elseif (is_string($paragraphStyle)) { + $style = $paragraphStyle; + } + if ($style !== null && $style !== '') { + if ($pStyleIsObject) { + // CSS pairs (style="...") + $style = " style=\"{$style}{$extraCSS}\""; + } else { + // class name; need to append extra styles manually + $style = " class=\"{$style}\" style=\"{$extraCSS}\""; + } + } elseif ($extraCSS !== '') { + $style = " style=\"{$extraCSS}\""; + } + + return $style; + } +} diff --git a/src/PhpWord/Writer/HTML/Element/Table.php b/src/PhpWord/Writer/HTML/Element/Table.php index 72b82d9872..98f69e3f3f 100644 --- a/src/PhpWord/Writer/HTML/Element/Table.php +++ b/src/PhpWord/Writer/HTML/Element/Table.php @@ -1,4 +1,5 @@ getGridSpan(); $cellRowSpan = 1; $cellVMerge = $cellStyle->getVMerge(); - // If this is the first cell of the vertical merge, find out how man rows it spans + // If this is the first cell of the vertical merge, find out how many rows it spans if ($cellVMerge === 'restart') { - for ($k = $i + 1; $k < $rowCount; ++$k) { - $kRowCells = $rows[$k]->getCells(); - if (isset($kRowCells[$j]) && $kRowCells[$j]->getStyle()->getVMerge() === 'continue') { - ++$cellRowSpan; - } else { - break; - } - } + $cellRowSpan = $this->calculateCellRowSpan($rows, $i, $j); } // Ignore cells that are merged vertically with previous rows if ($cellVMerge !== 'continue') { @@ -132,4 +126,58 @@ private function getTableStyle($tableStyle = null): string return ' style="' . $style . '"'; } + + /** + * Calculates cell rowspan. + * + * @param \PhpOffice\PhpWord\Element\Row[] $rows + */ + private function calculateCellRowSpan(array $rows, int $rowIndex, int $colIndex): int + { + $currentRow = $rows[$rowIndex]; + $currentRowCells = $currentRow->getCells(); + $shiftedColIndex = 0; + + foreach ($currentRowCells as $cell) { + if ($cell === $currentRowCells[$colIndex]) { + break; + } + + $colSpan = 1; + + if ($cell->getStyle()->getGridSpan() !== null) { + $colSpan = $cell->getStyle()->getGridSpan(); + } + + $shiftedColIndex += $colSpan; + } + + $rowCount = count($rows); + $rowSpan = 1; + + for ($i = $rowIndex + 1; $i < $rowCount; ++$i) { + $rowCells = $rows[$i]->getCells(); + $colIndex = 0; + + foreach ($rowCells as $cell) { + if ($colIndex === $shiftedColIndex) { + if ($cell->getStyle()->getVMerge() === 'continue') { + ++$rowSpan; + } + + break; + } + + $colSpan = 1; + + if ($cell->getStyle()->getGridSpan() !== null) { + $colSpan = $cell->getStyle()->getGridSpan(); + } + + $colIndex += $colSpan; + } + } + + return $rowSpan; + } } diff --git a/src/PhpWord/Writer/HTML/Element/Text.php b/src/PhpWord/Writer/HTML/Element/Text.php index 5af9f2ab63..312d3a19c2 100644 --- a/src/PhpWord/Writer/HTML/Element/Text.php +++ b/src/PhpWord/Writer/HTML/Element/Text.php @@ -1,4 +1,5 @@ ' . PHP_EOL; - + $defaultFontColor = Settings::getDefaultFontColor(); // Default styles $astarray = [ 'font-family' => $this->getFontFamily(Settings::getDefaultFontName(), $this->getParentWriter()->getDefaultGenericFont()), 'font-size' => Settings::getDefaultFontSize() . 'pt', + 'color' => "#{$defaultFontColor}", ]; // Mpdf sometimes needs separate tag for body; doesn't harm others. $bodyarray = $astarray; diff --git a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php index a650786769..4672347ba2 100644 --- a/src/PhpWord/Writer/HTML/Style/AbstractStyle.php +++ b/src/PhpWord/Writer/HTML/Style/AbstractStyle.php @@ -1,4 +1,5 @@ getVAlign(); + } foreach (['Top', 'Left', 'Bottom', 'Right'] as $direction) { $method = 'getBorder' . $direction . 'Style'; diff --git a/src/PhpWord/Writer/ODText.php b/src/PhpWord/Writer/ODText.php index 616119e5cc..c9a524e882 100644 --- a/src/PhpWord/Writer/ODText.php +++ b/src/PhpWord/Writer/ODText.php @@ -1,4 +1,5 @@ parts) as $partName) { $partClass = static::class . '\\Part\\' . $partName; if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart $partObject Type hint */ + /** @var AbstractPart $partObject Type hint */ $partObject = new $partClass(); $partObject->setParentWriter($this); $this->writerParts[strtolower($partName)] = $partObject; diff --git a/src/PhpWord/Writer/ODText/Element/AbstractElement.php b/src/PhpWord/Writer/ODText/Element/AbstractElement.php index 5cd396aa51..97d1875cd1 100644 --- a/src/PhpWord/Writer/ODText/Element/AbstractElement.php +++ b/src/PhpWord/Writer/ODText/Element/AbstractElement.php @@ -1,4 +1,5 @@ startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + $text = preg_replace('/^ +/', '', $text); + } + preg_match_all('/([\\s\\S]*?)(\\t| +| ?$)/', $text, $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + $this->writeText($match[1]); + if ($match[2] === '') { + break; + } elseif ($match[2] === "\t") { + $xmlWriter->writeElement('text:tab'); + } elseif ($match[2] === ' ') { + $xmlWriter->writeElement('text:s'); + + break; + } else { + $num = strlen($match[2]); + $xmlWriter->startElement('text:s'); + $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + $xmlWriter->endElement(); + } + } + } } diff --git a/src/PhpWord/Writer/ODText/Element/Container.php b/src/PhpWord/Writer/ODText/Element/Container.php index 6e6b88eabc..6b0fee8c64 100644 --- a/src/PhpWord/Writer/ODText/Element/Container.php +++ b/src/PhpWord/Writer/ODText/Element/Container.php @@ -1,4 +1,5 @@ + */ + protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote']; } diff --git a/src/PhpWord/Writer/ODText/Element/Field.php b/src/PhpWord/Writer/ODText/Element/Field.php index 46f62b0f02..6b54807869 100644 --- a/src/PhpWord/Writer/ODText/Element/Field.php +++ b/src/PhpWord/Writer/ODText/Element/Field.php @@ -1,4 +1,5 @@ getXmlWriter(); $element = $this->getElement(); - if (!$element instanceof \PhpOffice\PhpWord\Element\Image) { + if (!$element instanceof ElementImage) { return; } @@ -43,11 +44,16 @@ public function write(): void $width = Converter::pixelToCm($style->getWidth()); $height = Converter::pixelToCm($style->getHeight()); - $xmlWriter->startElement('text:p'); - $xmlWriter->writeAttribute('text:style-name', 'IM' . $mediaIndex); + $xmlWriter = $this->getXmlWriter(); + + if (!$this->withoutP) { + $xmlWriter->startElement('text:p'); + $xmlWriter->writeAttribute('text:style-name', 'IM' . $mediaIndex); + } $xmlWriter->startElement('draw:frame'); $xmlWriter->writeAttribute('draw:style-name', 'fr' . $mediaIndex); + $xmlWriter->writeAttributeIf($this->withoutP, 'draw:text-style-name', 'IM' . $mediaIndex); $xmlWriter->writeAttribute('draw:name', $element->getElementId()); $xmlWriter->writeAttribute('text:anchor-type', 'as-char'); $xmlWriter->writeAttribute('svg:width', $width . 'cm'); @@ -63,6 +69,8 @@ public function write(): void $xmlWriter->endElement(); // draw:frame - $xmlWriter->endElement(); // text:p + if (!$this->withoutP) { + $xmlWriter->endElement(); // text:p + } } } diff --git a/src/PhpWord/Writer/ODText/Element/Link.php b/src/PhpWord/Writer/ODText/Element/Link.php index 0375b11bc1..9ef35692c8 100644 --- a/src/PhpWord/Writer/ODText/Element/Link.php +++ b/src/PhpWord/Writer/ODText/Element/Link.php @@ -1,4 +1,5 @@ getElement(); + if (!$element instanceof ListItemRunElement) { + return; + } + $depth = $element->getDepth() + 1; + + $xmlWriter = $this->getXmlWriter(); + + for ($iDepth = 1; $iDepth <= $depth; ++$iDepth) { + $xmlWriter->startElement('text:list'); + $xmlWriter->writeAttribute('text:style-name', $element->getStyle()->getNumStyle()); + $xmlWriter->startElement('text:list-item'); + } + + $containerWriter = new Container($xmlWriter, $element, false); + $containerWriter->write(); + + for ($iDepth = 1; $iDepth <= $depth; ++$iDepth) { + $xmlWriter->endElement(); // text:list-item + $xmlWriter->endElement(); // text:list + } + } +} diff --git a/src/PhpWord/Writer/ODText/Element/PageBreak.php b/src/PhpWord/Writer/ODText/Element/PageBreak.php index 367106c0fd..ca9e53f4a6 100644 --- a/src/PhpWord/Writer/ODText/Element/PageBreak.php +++ b/src/PhpWord/Writer/ODText/Element/PageBreak.php @@ -1,4 +1,5 @@ getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Ruby) { + return; + } + $paragraphStyle = $element->getBaseTextRun()->getParagraphStyle(); + + if (!$this->withoutP) { + $xmlWriter->startElement('text:p'); // text:p + } + if (empty($paragraphStyle)) { + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); + } + } elseif (is_string($paragraphStyle)) { + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); + } + } + + $this->replaceTabs($element->getBaseTextRun()->getText(), $xmlWriter); + $this->writeText(' ('); + $this->replaceTabs($element->getRubyTextRun()->getText(), $xmlWriter); + $this->writeText(')'); + + if (!$this->withoutP) { + $xmlWriter->endElement(); // text:p + } + } +} diff --git a/src/PhpWord/Writer/ODText/Element/Table.php b/src/PhpWord/Writer/ODText/Element/Table.php index e12ae24b58..097f6742bb 100644 --- a/src/PhpWord/Writer/ODText/Element/Table.php +++ b/src/PhpWord/Writer/ODText/Element/Table.php @@ -1,4 +1,5 @@ getXmlWriter(); $element = $this->getElement(); - if (!$element instanceof \PhpOffice\PhpWord\Element\Table) { + if (!$element instanceof TableElement) { return; } $rows = $element->getRows(); @@ -77,7 +78,7 @@ private function writeColumns(XMLWriter $xmlWriter, TableElement $element): void private function writeRow(XMLWriter $xmlWriter, RowElement $row): void { $xmlWriter->startElement('table:table-row'); - /** @var \PhpOffice\PhpWord\Element\Row $row Type hint */ + /** @var RowElement $row Type hint */ foreach ($row->getCells() as $cell) { $xmlWriter->startElement('table:table-cell'); $xmlWriter->writeAttribute('office:value-type', 'string'); diff --git a/src/PhpWord/Writer/ODText/Element/Text.php b/src/PhpWord/Writer/ODText/Element/Text.php index 75fb930856..3996972387 100644 --- a/src/PhpWord/Writer/ODText/Element/Text.php +++ b/src/PhpWord/Writer/ODText/Element/Text.php @@ -1,4 +1,5 @@ writeAttribute('text:change-id', $element->getTrackChange()->getElementId()); $xmlWriter->endElement(); } else { - if (empty($fontStyle)) { - if (empty($paragraphStyle)) { - if (!$this->withoutP) { - $xmlWriter->writeAttribute('text:style-name', 'Normal'); - } - } elseif (is_string($paragraphStyle)) { - if (!$this->withoutP) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); - } + if (empty($paragraphStyle)) { + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', 'Normal'); } - $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->replaceTabs($element->getText(), $xmlWriter); - $this->writeChangeInsertion(false, $element->getTrackChange()); - } else { - if (empty($paragraphStyle)) { - if (!$this->withoutP) { - $xmlWriter->writeAttribute('text:style-name', 'Normal'); - } - } elseif (is_string($paragraphStyle)) { - if (!$this->withoutP) { - $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); - } + } elseif (is_string($paragraphStyle)) { + if (!$this->withoutP) { + $xmlWriter->writeAttribute('text:style-name', $paragraphStyle); } + } + + if (!empty($fontStyle)) { // text:span $xmlWriter->startElement('text:span'); if (is_string($fontStyle)) { $xmlWriter->writeAttribute('text:style-name', $fontStyle); } - $this->writeChangeInsertion(true, $element->getTrackChange()); - $this->replaceTabs($element->getText(), $xmlWriter); - $this->writeChangeInsertion(false, $element->getTrackChange()); - $xmlWriter->endElement(); } - } - if (!$this->withoutP) { - $xmlWriter->endElement(); // text:p - } - } - private function replacetabs($text, $xmlWriter): void - { - if (preg_match('/^ +/', $text, $matches)) { - $num = strlen($matches[0]); - $xmlWriter->startElement('text:s'); - $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); - $xmlWriter->endElement(); - $text = preg_replace('/^ +/', '', $text); - } - preg_match_all('/([\\s\\S]*?)(\\t| +| ?$)/', $text, $matches, PREG_SET_ORDER); - foreach ($matches as $match) { - $this->writeText($match[1]); - if ($match[2] === '') { - break; - } elseif ($match[2] === "\t") { - $xmlWriter->writeElement('text:tab'); - } elseif ($match[2] === ' ') { - $xmlWriter->writeElement('text:s'); + $this->writeChangeInsertion(true, $element->getTrackChange()); + $this->replaceTabs($element->getText(), $xmlWriter); + $this->writeChangeInsertion(false, $element->getTrackChange()); - break; - } else { - $num = strlen($match[2]); - $xmlWriter->startElement('text:s'); - $xmlWriter->writeAttributeIf($num > 1, 'text:c', "$num"); + if (!empty($fontStyle)) { $xmlWriter->endElement(); } } + if (!$this->withoutP) { + $xmlWriter->endElement(); // text:p + } } private function writeChangeInsertion($start = true, ?TrackChange $trackChange = null): void diff --git a/src/PhpWord/Writer/ODText/Element/TextBreak.php b/src/PhpWord/Writer/ODText/Element/TextBreak.php index 1bfe398857..1a69700792 100644 --- a/src/PhpWord/Writer/ODText/Element/TextBreak.php +++ b/src/PhpWord/Writer/ODText/Element/TextBreak.php @@ -1,4 +1,5 @@ imageParagraphStyles as $style) { - $styleWriter = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $style); + $styleWriter = new ParagraphStyleWriter($xmlWriter, $style); $styleWriter->write(); } } @@ -256,7 +257,7 @@ private function getAutoStyles(PhpWord $phpWord): void * * Table style can be null or string of the style name * - * @param \PhpOffice\PhpWord\Element\AbstractContainer $container + * @param AbstractContainer $container * @param int $paragraphStyleCount * @param int $fontStyleCount * @@ -277,7 +278,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl $style = $element->getStyle(); $style->setStyleName('fr' . $element->getMediaIndex()); $this->autoStyles['Image'][] = $style; - $sty = new \PhpOffice\PhpWord\Style\Paragraph(); + $sty = new Paragraph(); $sty->setStyleName('IM' . $element->getMediaIndex()); $sty->setAuto(); $sty->setAlignment($style->getAlignment()); @@ -300,7 +301,7 @@ private function getContainerStyle($container, &$paragraphStyleCount, &$fontStyl /** * Get style of individual element. * - * @param \PhpOffice\PhpWord\Element\Text $element + * @param Text $element * @param int $paragraphStyleCount * @param int $fontStyleCount */ @@ -346,7 +347,7 @@ private function getElementStyle($element, &$paragraphStyleCount, &$fontStyleCou /** * Get font style of individual field element. * - * @param \PhpOffice\PhpWord\Element\Field $element + * @param Field $element * @param int $fontStyleCount */ private function getElementStyleField($element, &$fontStyleCount): void @@ -371,7 +372,7 @@ private function getElementStyleField($element, &$fontStyleCount): void /** * Get style of individual element. * - * @param \PhpOffice\PhpWord\Element\TextRun $element + * @param TextRun $element * @param int $paragraphStyleCount */ private function getElementStyleTextRun($element, &$paragraphStyleCount): void diff --git a/src/PhpWord/Writer/ODText/Part/Manifest.php b/src/PhpWord/Writer/ODText/Part/Manifest.php index 37fb797935..200da15836 100644 --- a/src/PhpWord/Writer/ODText/Part/Manifest.php +++ b/src/PhpWord/Writer/ODText/Part/Manifest.php @@ -1,4 +1,5 @@ setStyleName($style->getStyleName()); - $temp2 = new \PhpOffice\PhpWord\Writer\ODText\Style\Paragraph($xmlWriter, $temp1); + $temp2 = new Paragraph($xmlWriter, $temp1); $temp2->write(); } diff --git a/src/PhpWord/Writer/ODText/Style/Image.php b/src/PhpWord/Writer/ODText/Style/Image.php index 79ddfc502e..56c4f57a5b 100644 --- a/src/PhpWord/Writer/ODText/Style/Image.php +++ b/src/PhpWord/Writer/ODText/Style/Image.php @@ -1,4 +1,5 @@ getStyle(); + if (!$style instanceof StyleNumbering) { + return; + } + $xmlWriter = $this->getXmlWriter(); + + $xmlWriter->startElement('text:list-style'); + $xmlWriter->writeAttribute('style:name', $style->getStyleName()); + + foreach ($style->getLevels() as $styleLevel) { + $numLevel = $styleLevel->getLevel() + 1; + + // In Twips + $tabPos = $styleLevel->getTabPos(); + // In Inches + $tabPos /= Converter::INCH_TO_TWIP; + // In Centimeters + $tabPos *= Converter::INCH_TO_CM; + + // In Twips + $hanging = $styleLevel->getHanging(); + // In Inches + $hanging /= Converter::INCH_TO_TWIP; + // In Centimeters + $hanging *= Converter::INCH_TO_CM; + + $xmlWriter->startElement('text:list-level-style-bullet'); + $xmlWriter->writeAttribute('text:level', $numLevel); + $xmlWriter->writeAttribute('text:style-name', $style->getStyleName() . '_' . $numLevel); + $xmlWriter->writeAttribute('text:bullet-char', $styleLevel->getText()); + + $xmlWriter->startElement('style:list-level-properties'); + $xmlWriter->writeAttribute('text:list-level-position-and-space-mode', 'label-alignment'); + + $xmlWriter->startElement('style:list-level-label-alignment'); + $xmlWriter->writeAttribute('text:label-followed-by', 'listtab'); + $xmlWriter->writeAttribute('text:list-tab-stop-position', number_format($tabPos, 2, '.', '') . 'cm'); + $xmlWriter->writeAttribute('fo:text-indent', '-' . number_format($hanging, 2, '.', '') . 'cm'); + $xmlWriter->writeAttribute('fo:margin-left', number_format($tabPos, 2, '.', '') . 'cm'); + + $xmlWriter->endElement(); // style:list-level-label-alignment + $xmlWriter->endElement(); // style:list-level-properties + + $xmlWriter->startElement('style:text-properties'); + $xmlWriter->writeAttribute('style:font-name', $styleLevel->getFont()); + $xmlWriter->endElement(); // style:text-properties + + $xmlWriter->endElement(); // text:list-level-style-bullet + } + + $xmlWriter->endElement(); // text:list-style + } +} diff --git a/src/PhpWord/Writer/ODText/Style/Paragraph.php b/src/PhpWord/Writer/ODText/Style/Paragraph.php index 4459c76c01..99963bd4a3 100644 --- a/src/PhpWord/Writer/ODText/Style/Paragraph.php +++ b/src/PhpWord/Writer/ODText/Style/Paragraph.php @@ -1,4 +1,5 @@ getStyle(); - if (!$style instanceof \PhpOffice\PhpWord\Style\Paragraph) { + if (!$style instanceof Style\Paragraph) { return; } $xmlWriter = $this->getXmlWriter(); @@ -73,13 +74,13 @@ public function write(): void } elseif (substr($styleName, 0, 2) === 'HD') { $styleAuto = true; $psm = 'Heading_' . substr($styleName, 2); - $stylep = \PhpOffice\PhpWord\Style::getStyle($psm); - if ($stylep instanceof \PhpOffice\PhpWord\Style\Font) { + $stylep = Style::getStyle($psm); + if ($stylep instanceof Style\Font) { if (method_exists($stylep, 'getParagraph')) { $stylep = $stylep->getParagraph(); } } - if ($stylep instanceof \PhpOffice\PhpWord\Style\Paragraph) { + if ($stylep instanceof Style\Paragraph) { if ($stylep->hasPageBreakBefore()) { $breakbefore = true; } diff --git a/src/PhpWord/Writer/ODText/Style/Section.php b/src/PhpWord/Writer/ODText/Style/Section.php index 0a250194fd..05152a3944 100644 --- a/src/PhpWord/Writer/ODText/Style/Section.php +++ b/src/PhpWord/Writer/ODText/Style/Section.php @@ -1,4 +1,5 @@ parts as $partName) { $partClass = static::class . '\\Part\\' . $partName; if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Writer\RTF\Part\AbstractPart $part Type hint */ + /** @var RTF\Part\AbstractPart $part Type hint */ $part = new $partClass(); $part->setParentWriter($this); $this->writerParts[strtolower($partName)] = $part; diff --git a/src/PhpWord/Writer/RTF/Element/AbstractElement.php b/src/PhpWord/Writer/RTF/Element/AbstractElement.php index 5c33868a8b..e007e6aa26 100644 --- a/src/PhpWord/Writer/RTF/Element/AbstractElement.php +++ b/src/PhpWord/Writer/RTF/Element/AbstractElement.php @@ -1,4 +1,5 @@ parentWriter; /** @var \PhpOffice\PhpWord\Element\Text $element Type hint */ @@ -188,7 +189,7 @@ protected function writeFontStyle() return ''; } - /** @var \PhpOffice\PhpWord\Writer\RTF $parentWriter Type hint */ + /** @var WriterRTF $parentWriter Type hint */ $parentWriter = $this->parentWriter; // Create style writer and set color/name index diff --git a/src/PhpWord/Writer/RTF/Element/Container.php b/src/PhpWord/Writer/RTF/Element/Container.php index 5e198aec86..dcac8ec071 100644 --- a/src/PhpWord/Writer/RTF/Element/Container.php +++ b/src/PhpWord/Writer/RTF/Element/Container.php @@ -1,4 +1,5 @@ element; + $elementClass = str_replace('\\Writer\\RTF', '', static::class); + if (!$element instanceof $elementClass || !is_string($element->getBaseTextRun()->getText())) { + return ''; + } + + $this->getStyles(); + + $content = ''; + $content .= $this->writeOpening(); + $content .= '{'; + $content .= $this->writeFontStyle(); + $content .= $this->writeText($element->getBaseTextRun()->getText()); + $rubyText = $element->getRubyTextRun()->getText(); + if ($rubyText !== '') { + $content .= ' ('; + $content .= $this->writeText($rubyText); + $content .= ')'; + } + $content .= '}'; + $content .= $this->writeClosing(); + + return $content; + } +} diff --git a/src/PhpWord/Writer/RTF/Element/Table.php b/src/PhpWord/Writer/RTF/Element/Table.php index f2d5f9fb5a..3b08a5db86 100644 --- a/src/PhpWord/Writer/RTF/Element/Table.php +++ b/src/PhpWord/Writer/RTF/Element/Table.php @@ -1,4 +1,5 @@ element; $elementClass = str_replace('\\Writer\\RTF', '', static::class); - if (!$element instanceof $elementClass || !is_string($element->getText())) { + if (!$element instanceof $elementClass) { return ''; } + $textToWrite = $element->getText(); + if ($textToWrite instanceof \PhpOffice\PhpWord\Element\TextRun) { + $textToWrite = $textToWrite->getText(); // gets text from TextRun + } + $this->getStyles(); $content = ''; @@ -82,7 +88,7 @@ public function write() $content .= '{'; $content .= $this->writeFontStyle(); - $content .= $this->writeText($element->getText()); + $content .= $this->writeText($textToWrite); $content .= '}'; $content .= $this->writeClosing(); $content .= $endout; diff --git a/src/PhpWord/Writer/RTF/Part/AbstractPart.php b/src/PhpWord/Writer/RTF/Part/AbstractPart.php index be772b93a0..a07f70bbf7 100644 --- a/src/PhpWord/Writer/RTF/Part/AbstractPart.php +++ b/src/PhpWord/Writer/RTF/Part/AbstractPart.php @@ -1,4 +1,5 @@ getHeaders() as $header) { $type = $header->getType(); - if ($evenOdd || $type !== FOOTER::EVEN) { + if ($evenOdd || $type !== Footer::EVEN) { $content .= '{\\header'; if ($type === Footer::FIRST) { $content .= 'f'; } elseif ($evenOdd) { - $content .= ($type === FOOTER::EVEN) ? 'l' : 'r'; + $content .= ($type === Footer::EVEN) ? 'l' : 'r'; } foreach ($header->getElements() as $element) { $cl = get_class($element); @@ -182,12 +183,12 @@ private function writeSections() } foreach ($section->getFooters() as $footer) { $type = $footer->getType(); - if ($evenOdd || $type !== FOOTER::EVEN) { + if ($evenOdd || $type !== Footer::EVEN) { $content .= '{\\footer'; if ($type === Footer::FIRST) { $content .= 'f'; } elseif ($evenOdd) { - $content .= ($type === FOOTER::EVEN) ? 'l' : 'r'; + $content .= ($type === Footer::EVEN) ? 'l' : 'r'; } foreach ($footer->getElements() as $element) { $cl = get_class($element); diff --git a/src/PhpWord/Writer/RTF/Part/Header.php b/src/PhpWord/Writer/RTF/Part/Header.php index 7f8cc84b97..97644fe4ac 100644 --- a/src/PhpWord/Writer/RTF/Part/Header.php +++ b/src/PhpWord/Writer/RTF/Part/Header.php @@ -1,4 +1,5 @@ parts) as $partName) { $partClass = static::class . '\\Part\\' . $partName; if (class_exists($partClass)) { - /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $part Type hint */ + /** @var Word2007\Part\AbstractPart $part Type hint */ $part = new $partClass(); $part->setParentWriter($this); $this->writerParts[strtolower($partName)] = $part; @@ -179,7 +178,7 @@ private function addHeaderFooterMedia(ZipArchive $zip, $docPart): void $this->registerContentTypes($media); } - /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $writerPart Type hint */ + /** @var Word2007\Part\AbstractPart $writerPart Type hint */ $writerPart = $this->getWriterPart('relspart')->setMedia($media); $zip->addFromString("word/_rels/{$file}.xml.rels", $writerPart->write()); } @@ -206,7 +205,7 @@ private function addHeaderFooterContent(Section &$section, ZipArchive $zip, $elm $this->contentTypes['override']["/word/$elmFile"] = $elmType; $this->relationships[] = ['target' => $elmFile, 'type' => $elmType, 'rID' => $rId]; - /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $writerPart Type hint */ + /** @var Word2007\Part\AbstractPart $writerPart Type hint */ $writerPart = $this->getWriterPart($elmType)->setElement($element); $zip->addFromString("word/$elmFile", $writerPart->write()); } @@ -227,7 +226,6 @@ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote'): void $collection = $phpWord->$method(); // Add footnotes media files, relations, and contents - /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collection Type hint */ if ($collection->countItems() > 0) { $media = Media::getElements($noteType); $this->addFilesToPackage($zip, $media); @@ -237,7 +235,7 @@ private function addNotes(ZipArchive $zip, &$rId, $noteType = 'footnote'): void // Write relationships file, e.g. word/_rels/footnotes.xml if (!empty($media)) { - /** @var \PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart $writerPart Type hint */ + /** @var Word2007\Part\AbstractPart $writerPart Type hint */ $writerPart = $this->getWriterPart('relspart')->setMedia($media); $zip->addFromString("word/_rels/{$partName}.xml.rels", $writerPart->write()); } @@ -260,7 +258,6 @@ private function addComments(ZipArchive $zip, &$rId): void $partName = 'comments'; // Add comment relations and contents - /** @var \PhpOffice\PhpWord\Collection\AbstractCollection $collection Type hint */ if ($collection->countItems() > 0) { $this->relationships[] = ['target' => "{$partName}.xml", 'type' => $partName, 'rID' => ++$rId]; diff --git a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php index abd1324aad..5743c8c7c7 100644 --- a/src/PhpWord/Writer/Word2007/Element/AbstractElement.php +++ b/src/PhpWord/Writer/Word2007/Element/AbstractElement.php @@ -1,4 +1,5 @@ xmlWriter = $xmlWriter; $this->element = $element; @@ -76,7 +75,7 @@ public function __construct(XMLWriter $xmlWriter, Element $element, $withoutP = /** * Get XML Writer. * - * @return \PhpOffice\PhpWord\Shared\XMLWriter + * @return XMLWriter */ protected function getXmlWriter() { @@ -86,7 +85,7 @@ protected function getXmlWriter() /** * Get element. * - * @return \PhpOffice\PhpWord\Element\AbstractElement + * @return Element */ protected function getElement() { @@ -126,14 +125,10 @@ protected function endElementP(): void */ protected function writeCommentRangeStart(): void { - if ($this->element->getCommentRangeStart() != null) { - $comment = $this->element->getCommentRangeStart(); - //only set the ID if it is not yet set, otherwise it will overwrite it - if ($comment->getElementId() == null) { - $comment->setElementId(); + if ($this->element->getCommentsRangeStart() != null) { + foreach ($this->element->getCommentsRangeStart()->getItems() as $comment) { + $this->xmlWriter->writeElementBlock('w:commentRangeStart', ['w:id' => $comment->getElementId()]); } - - $this->xmlWriter->writeElementBlock('w:commentRangeStart', ['w:id' => $comment->getElementId()]); } } @@ -142,28 +137,23 @@ protected function writeCommentRangeStart(): void */ protected function writeCommentRangeEnd(): void { - if ($this->element->getCommentRangeEnd() != null) { - $comment = $this->element->getCommentRangeEnd(); - //only set the ID if it is not yet set, otherwise it will overwrite it, this should normally not happen - if ($comment->getElementId() == null) { - $comment->setElementId(); // @codeCoverageIgnore - } // @codeCoverageIgnore - - $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]); - $this->xmlWriter->startElement('w:r'); - $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]); - $this->xmlWriter->endElement(); - } elseif ($this->element->getCommentRangeStart() != null && $this->element->getCommentRangeStart()->getEndElement() == null) { - $comment = $this->element->getCommentRangeStart(); - //only set the ID if it is not yet set, otherwise it will overwrite it, this should normally not happen - if ($comment->getElementId() == null) { - $comment->setElementId(); // @codeCoverageIgnore - } // @codeCoverageIgnore - - $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]); - $this->xmlWriter->startElement('w:r'); - $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]); - $this->xmlWriter->endElement(); + if ($this->element->getCommentsRangeEnd() != null) { + foreach ($this->element->getCommentsRangeEnd()->getItems() as $comment) { + $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]); + $this->xmlWriter->endElement(); + } + } + if ($this->element->getCommentsRangeStart() != null) { + foreach ($this->element->getCommentsRangeStart()->getItems() as $comment) { + if ($comment->getEndElement() == null) { + $this->xmlWriter->writeElementBlock('w:commentRangeEnd', ['w:id' => $comment->getElementId()]); + $this->xmlWriter->startElement('w:r'); + $this->xmlWriter->writeElementBlock('w:commentReference', ['w:id' => $comment->getElementId()]); + $this->xmlWriter->endElement(); + } + } } } diff --git a/src/PhpWord/Writer/Word2007/Element/Bookmark.php b/src/PhpWord/Writer/Word2007/Element/Bookmark.php index 1e618af987..ba61ad69fd 100644 --- a/src/PhpWord/Writer/Word2007/Element/Bookmark.php +++ b/src/PhpWord/Writer/Word2007/Element/Bookmark.php @@ -1,4 +1,5 @@ + */ + protected $containerWithoutP = ['TextRun', 'Footnote', 'Endnote', 'ListItemRun']; + /** * Write element. */ @@ -46,7 +52,7 @@ public function write(): void return; } $containerClass = substr(get_class($container), strrpos(get_class($container), '\\') + 1); - $withoutP = in_array($containerClass, ['TextRun', 'Footnote', 'Endnote', 'ListItemRun']); + $withoutP = in_array($containerClass, $this->containerWithoutP); $xmlWriter = $this->getXmlWriter(); // Loop through elements @@ -62,7 +68,7 @@ public function write(): void $writeLastTextBreak = ($containerClass == 'Cell') && ($elementClass == '' || $elementClass == 'Table'); if ($writeLastTextBreak) { $writerClass = $this->namespace . '\\TextBreak'; - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ + /** @var AbstractElement $writer Type hint */ $writer = new $writerClass($xmlWriter, new TextBreakElement(), $withoutP); $writer->write(); } @@ -70,18 +76,14 @@ public function write(): void /** * Write individual element. - * - * @param bool $withoutP - * - * @return string */ - private function writeElement(XMLWriter $xmlWriter, Element $element, $withoutP) + private function writeElement(XMLWriter $xmlWriter, Element $element, bool $withoutP): string { $elementClass = substr(get_class($element), strrpos(get_class($element), '\\') + 1); $writerClass = $this->namespace . '\\' . $elementClass; if (class_exists($writerClass)) { - /** @var \PhpOffice\PhpWord\Writer\Word2007\Element\AbstractElement $writer Type hint */ + /** @var AbstractElement $writer Type hint */ $writer = new $writerClass($xmlWriter, $element, $withoutP); $writer->setPart($this->getPart()); $writer->write(); diff --git a/src/PhpWord/Writer/Word2007/Element/Endnote.php b/src/PhpWord/Writer/Word2007/Element/Endnote.php index f96ac7977f..6a00ed5b3b 100644 --- a/src/PhpWord/Writer/Word2007/Element/Endnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Endnote.php @@ -1,4 +1,5 @@ endElement(); // w:r if ($element->getText() != null) { - if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { + if ($element->getText() instanceof TextRun) { $containerWriter = new Container($xmlWriter, $element->getText(), true); $containerWriter->write(); } @@ -262,7 +263,7 @@ protected function writeRef(ElementField $element): void $xmlWriter->endElement(); // w:r if ($element->getText() != null) { - if ($element->getText() instanceof \PhpOffice\PhpWord\Element\TextRun) { + if ($element->getText() instanceof TextRun) { $containerWriter = new Container($xmlWriter, $element->getText(), true); $containerWriter->write(); diff --git a/src/PhpWord/Writer/Word2007/Element/Footnote.php b/src/PhpWord/Writer/Word2007/Element/Footnote.php index 77073a239d..68f998e390 100644 --- a/src/PhpWord/Writer/Word2007/Element/Footnote.php +++ b/src/PhpWord/Writer/Word2007/Element/Footnote.php @@ -1,4 +1,5 @@ getXmlWriter(); + $element = $this->getElement(); + if (!$element instanceof \PhpOffice\PhpWord\Element\Ruby) { + return; + } + /** @var \PhpOffice\PhpWord\Element\Ruby $element */ + $this->startElementP(); + + $xmlWriter->startElement('w:r'); + $xmlWriter->startElement('w:ruby'); + + // write properties + $xmlWriter->startElement('w:rubyPr'); + $properties = $element->getProperties(); + $xmlWriter->startElement('w:rubyAlign'); + $xmlWriter->writeAttribute('w:val', $properties->getAlignment()); + $xmlWriter->endElement(); // w:rubyAlign + $xmlWriter->startElement('w:hps'); + $xmlWriter->writeAttribute('w:val', $properties->getFontFaceSize()); + $xmlWriter->endElement(); // w:hps + $xmlWriter->startElement('w:hpsRaise'); + $xmlWriter->writeAttribute('w:val', $properties->getFontPointsAboveBaseText()); + $xmlWriter->endElement(); // w:hpsRaise + $xmlWriter->startElement('w:hpsBaseText'); + $xmlWriter->writeAttribute('w:val', $properties->getFontSizeForBaseText()); + $xmlWriter->endElement(); // w:hpsBaseText + $xmlWriter->startElement('w:lid'); + $xmlWriter->writeAttribute('w:val', $properties->getLanguageId()); + $xmlWriter->endElement(); // w:lid + + $xmlWriter->endElement(); // w:rubyPr + + // write ruby text + $xmlWriter->startElement('w:rt'); + $rubyTextRun = $element->getRubyTextRun(); + $textRunWriter = new TextRun($xmlWriter, $rubyTextRun, true); + $textRunWriter->write(); + $xmlWriter->endElement(); // w:rt + // write base text + $xmlWriter->startElement('w:rubyBase'); + $baseTextRun = $element->getBaseTextRun(); + $textRunWriter = new TextRun($xmlWriter, $baseTextRun, true); + $textRunWriter->write(); + $xmlWriter->endElement(); // w:rubyBase + + $xmlWriter->endElement(); // w:ruby + $xmlWriter->endElement(); // w:r + + $this->endElementP(); + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/SDT.php b/src/PhpWord/Writer/Word2007/Element/SDT.php index f007dc790f..950c293776 100644 --- a/src/PhpWord/Writer/Word2007/Element/SDT.php +++ b/src/PhpWord/Writer/Word2007/Element/SDT.php @@ -1,4 +1,5 @@ getSalt() == null) { - $documentProtection->setSalt(openssl_random_pseudo_bytes(16)); + $documentProtection->setSalt((string) openssl_random_pseudo_bytes(16)); } $passwordHash = PasswordEncoder::hashPassword($documentProtection->getPassword(), $documentProtection->getAlgorithm(), $documentProtection->getSalt(), $documentProtection->getSpinCount()); $this->settings['w:documentProtection'] = [ diff --git a/src/PhpWord/Writer/Word2007/Part/Styles.php b/src/PhpWord/Writer/Word2007/Part/Styles.php index e715f2944f..a19895cea2 100644 --- a/src/PhpWord/Writer/Word2007/Part/Styles.php +++ b/src/PhpWord/Writer/Word2007/Part/Styles.php @@ -1,4 +1,5 @@ getParentWriter()->getPhpWord(); $fontName = $phpWord->getDefaultFontName(); + $asianFontName = $phpWord->getDefaultAsianFontName(); $fontSize = $phpWord->getDefaultFontSize(); + $fontColor = $phpWord->getDefaultFontColor(); $language = $phpWord->getSettings()->getThemeFontLang(); $latinLanguage = ($language == null || $language->getLatin() === null) ? 'en-US' : $language->getLatin(); @@ -95,9 +98,12 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void $xmlWriter->startElement('w:rFonts'); $xmlWriter->writeAttribute('w:ascii', $fontName); $xmlWriter->writeAttribute('w:hAnsi', $fontName); - $xmlWriter->writeAttribute('w:eastAsia', $fontName); + $xmlWriter->writeAttribute('w:eastAsia', $asianFontName); $xmlWriter->writeAttribute('w:cs', $fontName); $xmlWriter->endElement(); // w:rFonts + $xmlWriter->startElement('w:color'); + $xmlWriter->writeAttribute('w:val', $fontColor); + $xmlWriter->endElement(); $xmlWriter->startElement('w:sz'); $xmlWriter->writeAttribute('w:val', $fontSize * 2); $xmlWriter->endElement(); // w:sz @@ -126,7 +132,7 @@ private function writeDefaultStyles(XMLWriter $xmlWriter, $styles): void if (isset($styles['Normal'])) { $normalStyle = $styles['Normal']; // w:pPr - if ($normalStyle instanceof Fontstyle && $normalStyle->getParagraph() != null) { + if ($normalStyle instanceof FontStyle && $normalStyle->getParagraph() != null) { $styleWriter = new ParagraphStyleWriter($xmlWriter, $normalStyle->getParagraph()); $styleWriter->write(); } elseif ($normalStyle instanceof ParagraphStyle) { diff --git a/src/PhpWord/Writer/Word2007/Part/Theme.php b/src/PhpWord/Writer/Word2007/Part/Theme.php index ad57d66493..a70c248da6 100644 --- a/src/PhpWord/Writer/Word2007/Part/Theme.php +++ b/src/PhpWord/Writer/Word2007/Part/Theme.php @@ -1,4 +1,5 @@ write(); } diff --git a/src/PhpWord/Writer/Word2007/Style/Cell.php b/src/PhpWord/Writer/Word2007/Style/Cell.php index 6e22597dd3..bb0d6d71b0 100644 --- a/src/PhpWord/Writer/Word2007/Style/Cell.php +++ b/src/PhpWord/Writer/Word2007/Style/Cell.php @@ -1,4 +1,5 @@ endElement(); // w:tcW } + $paddingTop = $style->getPaddingTop(); + $paddingLeft = $style->getPaddingLeft(); + $paddingBottom = $style->getPaddingBottom(); + $paddingRight = $style->getPaddingRight(); + + if ($paddingTop !== null || $paddingLeft !== null || $paddingBottom !== null || $paddingRight !== null) { + $xmlWriter->startElement('w:tcMar'); + if ($paddingTop !== null) { + $xmlWriter->startElement('w:top'); + $xmlWriter->writeAttribute('w:w', $paddingTop); + $xmlWriter->writeAttribute('w:type', \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP); + $xmlWriter->endElement(); // w:top + } + if ($paddingLeft !== null) { + $xmlWriter->startElement('w:start'); + $xmlWriter->writeAttribute('w:w', $paddingLeft); + $xmlWriter->writeAttribute('w:type', \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP); + $xmlWriter->endElement(); // w:start + } + if ($paddingBottom !== null) { + $xmlWriter->startElement('w:bottom'); + $xmlWriter->writeAttribute('w:w', $paddingBottom); + $xmlWriter->writeAttribute('w:type', \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP); + $xmlWriter->endElement(); // w:bottom + } + if ($paddingRight !== null) { + $xmlWriter->startElement('w:end'); + $xmlWriter->writeAttribute('w:w', $paddingRight); + $xmlWriter->writeAttribute('w:type', \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP); + $xmlWriter->endElement(); // w:end + } + $xmlWriter->endElement(); // w:tcMar + } + // Text direction $textDir = $style->getTextDirection(); $xmlWriter->writeElementIf(null !== $textDir, 'w:textDirection', 'w:val', $textDir); diff --git a/src/PhpWord/Writer/Word2007/Style/Extrusion.php b/src/PhpWord/Writer/Word2007/Style/Extrusion.php index f6ad622191..8bb9218789 100644 --- a/src/PhpWord/Writer/Word2007/Style/Extrusion.php +++ b/src/PhpWord/Writer/Word2007/Style/Extrusion.php @@ -1,4 +1,5 @@ writeElementIf($style->isItalic() !== null, 'w:iCs', 'w:val', $this->writeOnOf($style->isItalic())); // Strikethrough, double strikethrough - $xmlWriter->writeElementIf($style->isStrikethrough() !== null, 'w:strike', 'w:val', $this->writeOnOf($style->isStrikethrough())); - $xmlWriter->writeElementIf($style->isDoubleStrikethrough() !== null, 'w:dstrike', 'w:val', $this->writeOnOf($style->isDoubleStrikethrough())); + $xmlWriter->writeElementIf($style->isStrikethrough(), 'w:strike', 'w:val', $this->writeOnOf($style->isStrikethrough())); + $xmlWriter->writeElementIf($style->isDoubleStrikethrough(), 'w:dstrike', 'w:val', $this->writeOnOf($style->isDoubleStrikethrough())); // Small caps, all caps $xmlWriter->writeElementIf($style->isSmallCaps() !== null, 'w:smallCaps', 'w:val', $this->writeOnOf($style->isSmallCaps())); diff --git a/src/PhpWord/Writer/Word2007/Style/Frame.php b/src/PhpWord/Writer/Word2007/Style/Frame.php index 0ba52ec5ab..a7aab43e61 100644 --- a/src/PhpWord/Writer/Word2007/Style/Frame.php +++ b/src/PhpWord/Writer/Word2007/Style/Frame.php @@ -1,4 +1,5 @@ startElement('w:numPr'); diff --git a/src/PhpWord/Writer/Word2007/Style/Row.php b/src/PhpWord/Writer/Word2007/Style/Row.php index 7e1468e87b..2b9d804f39 100644 --- a/src/PhpWord/Writer/Word2007/Style/Row.php +++ b/src/PhpWord/Writer/Word2007/Style/Row.php @@ -1,4 +1,5 @@ getAlignment()); + self::assertTrue($properties->getAlignment() !== '' && $properties->getAlignment() !== null); + self::assertIsFloat($properties->getFontFaceSize()); + self::assertIsFloat($properties->getFontPointsAboveBaseText()); + self::assertIsFloat($properties->getFontSizeForBaseText()); + self::assertIsString($properties->getLanguageId()); + self::assertTrue($properties->getLanguageId() !== '' && $properties->getLanguageId() !== null); + } + + /** + * Get/set alignment. + */ + public function testAlignment(): void + { + $properties = new RubyProperties(); + self::assertIsString($properties->getAlignment()); + self::assertTrue($properties->getAlignment() !== '' && $properties->getAlignment() !== null); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + self::assertEquals(RubyProperties::ALIGNMENT_RIGHT_VERTICAL, $properties->getAlignment()); + } + + /** + * Set valid alignments. Make sure we can set all valid types - should not throw exception. + */ + public function testValidAlignments(): void + { + $properties = new RubyProperties(); + $types = [ + RubyProperties::ALIGNMENT_CENTER, + RubyProperties::ALIGNMENT_DISTRIBUTE_LETTER, + RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, + RubyProperties::ALIGNMENT_LEFT, + RubyProperties::ALIGNMENT_RIGHT, + RubyProperties::ALIGNMENT_RIGHT_VERTICAL, + ]; + foreach ($types as $type) { + $properties->setAlignment($type); + self::assertEquals($type, $properties->getAlignment()); + } + } + + /** + * Test throws exception on invalid alignment type. + */ + public function testInvalidAlignment(): void + { + $this->expectException(InvalidArgumentException::class); + $properties = new RubyProperties(); + $properties->setAlignment('invalid alignment type'); + } + + /** + * Get/set font face size. + */ + public function testFontFaceSize(): void + { + $properties = new RubyProperties(); + + self::assertTrue($properties->getFontFaceSize() > 0); + $properties->setFontFaceSize(42.42); + self::assertEqualsWithDelta(42.42, $properties->getFontFaceSize(), 0.00001); // use delta as it is a float compare + self::assertIsFloat($properties->getFontFaceSize()); + } + + /** + * Get/set font points above base text. + */ + public function testFontPointsAboveBaseText(): void + { + $properties = new RubyProperties(); + + self::assertTrue($properties->getFontPointsAboveBaseText() > 0); + $properties->setFontPointsAboveBaseText(43.42); + self::assertEqualsWithDelta(43.42, $properties->getFontPointsAboveBaseText(), 0.00001); // use delta as it is a float compare + self::assertIsFloat($properties->getFontPointsAboveBaseText()); + } + + /** + * Get/set font size for base text. + */ + public function testFontSizeForBaseText(): void + { + $properties = new RubyProperties(); + + self::assertTrue($properties->getFontSizeForBaseText() > 0); + $properties->setFontSizeForBaseText(45.42); + self::assertEqualsWithDelta(45.42, $properties->getFontSizeForBaseText(), 0.00001); // use delta as it is a float compare + self::assertIsFloat($properties->getFontSizeForBaseText()); + } + + /** + * Get/set language id. + */ + public function testLanguageId(): void + { + $properties = new RubyProperties(); + + self::assertTrue($properties->getLanguageId() !== '' && $properties->getLanguageId() !== null); + $properties->setLanguageId('en-US'); + self::assertIsString($properties->getLanguageId()); + self::assertEquals('en-US', $properties->getLanguageId()); + } +} diff --git a/tests/PhpWordTests/Element/AbstractElementTest.php b/tests/PhpWordTests/Element/AbstractElementTest.php index a059712b1a..8219871f73 100644 --- a/tests/PhpWordTests/Element/AbstractElementTest.php +++ b/tests/PhpWordTests/Element/AbstractElementTest.php @@ -1,4 +1,5 @@ getEndElement()); } + /** + * Two comments on same text. + */ + public function testTwoCommentsOnSameText(): void + { + $section = new Section(0); + $text = $section->addText('Text'); + + $comment1 = new Comment('Author1', new DateTime(), 'A1'); + $comment1->addText('Comment1'); + + $comment2 = new Comment('Author2', new DateTime(), 'A2'); + $comment2->addText('Comment2'); + + $comment1->setStartElement($text); + $comment2->setStartElement($text); + + $text->setCommentRangeStart($comment1); + $text->setCommentRangeEnd($comment1); + + $text->setCommentRangeStart($comment2); + $text->setCommentRangeEnd($comment2); + + self::assertEquals(2, $text->getCommentsRangeStart()->countItems()); + self::assertEquals(2, $text->getCommentsRangeEnd()->countItems()); + + self::assertEquals($text->getCommentsRangeStart()->getItem(0)->getElementId(), $comment1->getElementId()); + self::assertEquals($text->getCommentsRangeEnd()->getItem(0)->getElementId(), $comment1->getElementId()); + + self::assertEquals($text->getCommentsRangeStart()->getItem(1)->getElementId(), $comment2->getElementId()); + self::assertEquals($text->getCommentsRangeEnd()->getItem(1)->getElementId(), $comment2->getElementId()); + } + /** * Add text. */ diff --git a/tests/PhpWordTests/Element/FieldTest.php b/tests/PhpWordTests/Element/FieldTest.php index 06f7c6841b..f3accf8789 100644 --- a/tests/PhpWordTests/Element/FieldTest.php +++ b/tests/PhpWordTests/Element/FieldTest.php @@ -1,4 +1,5 @@ getSource()); - self::assertEquals(md5($source), $image->getMediaId()); + self::assertEquals(md5((string) $source), $image->getMediaId()); self::assertEquals('image/jpeg', $image->getImageType()); self::assertEquals('jpg', $image->getImageExtension()); self::assertEquals('imagecreatefromstring', $image->getImageCreateFunction()); diff --git a/tests/PhpWordTests/Element/LineTest.php b/tests/PhpWordTests/Element/LineTest.php index 101c7309fb..98298fc76c 100644 --- a/tests/PhpWordTests/Element/LineTest.php +++ b/tests/PhpWordTests/Element/LineTest.php @@ -1,4 +1,5 @@ getBaseTextRun()->getText()); + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getBaseTextRun()); + self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $ruby->getBaseTextRun()->getParagraphStyle()); + self::assertEquals('', $ruby->getRubyTextRun()->getText()); + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getRubyTextRun()); + self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $ruby->getRubyTextRun()->getParagraphStyle()); + self::assertInstanceOf('PhpOffice\\PhpWord\\ComplexType\\RubyProperties', $ruby->getProperties()); + self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $ruby->getProperties()->getAlignment()); + } + + /** + * Get/set base text. + */ + public function testBaseText(): void + { + $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties()); + + self::assertEquals('', $ruby->getBaseTextRun()->getText()); + $tr = new TextRun(); + $tr->addText('Hello, world'); + $ruby->setBaseTextRun($tr); + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getBaseTextRun()); + self::assertEquals('Hello, world', $ruby->getBaseTextRun()->getText()); + } + + /** + * Get/set ruby text. + */ + public function testRubyText(): void + { + $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties()); + + self::assertEquals('', $ruby->getRubyTextRun()->getText()); + $tr = new TextRun(); + $tr->addText('Hello, ruby'); + $ruby->setRubyTextRun($tr); + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\TextRun', $ruby->getRubyTextRun()); + self::assertEquals('Hello, ruby', $ruby->getRubyTextRun()->getText()); + } + + /** + * Get/set ruby properties. + */ + public function testRubyProperties(): void + { + $ruby = new Ruby(new TextRun(), new TextRun(), new RubyProperties()); + + self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $ruby->getProperties()->getAlignment()); + + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + $properties->setFontFaceSize(1); + $properties->setFontPointsAboveBaseText(2); + $properties->setFontSizeForBaseText(3); + $properties->setLanguageId('en-US'); + $ruby->setProperties($properties); + + self::assertInstanceOf('PhpOffice\\PhpWord\\ComplexType\\RubyProperties', $ruby->getProperties()); + self::assertEquals(RubyProperties::ALIGNMENT_RIGHT_VERTICAL, $ruby->getProperties()->getAlignment()); + self::assertEquals(1, $ruby->getProperties()->getFontFaceSize()); + self::assertEquals(2, $ruby->getProperties()->getFontPointsAboveBaseText()); + self::assertEquals(3, $ruby->getProperties()->getFontSizeForBaseText()); + self::assertEquals('en-US', $ruby->getProperties()->getLanguageId()); + } +} diff --git a/tests/PhpWordTests/Element/SDTTest.php b/tests/PhpWordTests/Element/SDTTest.php index b33dde141b..505ef14fe4 100644 --- a/tests/PhpWordTests/Element/SDTTest.php +++ b/tests/PhpWordTests/Element/SDTTest.php @@ -1,4 +1,5 @@ setParagraphStyle(['alignment' => Jc::CENTER, 'spaceAfter' => 100]); self::assertInstanceOf('PhpOffice\\PhpWord\\Style\\Paragraph', $oText->getParagraphStyle()); } + + /** + * Add ruby element and get raw text. + */ + public function testRubyElementGetText(): void + { + $oTextRun = new TextRun(); + $oTextRun->setPhpWord(new PhpWord()); + + $properties = new RubyProperties(); + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + $element = $oTextRun->addRuby($baseTextRun, $rubyTextRun, $properties); + + self::assertInstanceOf('PhpOffice\\PhpWord\\Element\\Ruby', $element); + self::assertCount(1, $oTextRun->getElements()); + self::assertEquals('私 (わたし)', $oTextRun->getText()); + } } diff --git a/tests/PhpWordTests/Element/TextTest.php b/tests/PhpWordTests/Element/TextTest.php index f2e2066eeb..ee3c67edd9 100644 --- a/tests/PhpWordTests/Element/TextTest.php +++ b/tests/PhpWordTests/Element/TextTest.php @@ -1,4 +1,5 @@ expectException(\PhpOffice\PhpWord\Exception\CopyFileException::class); + $this->expectException(CopyFileException::class); throw new CopyFileException('C:\source\dummy.txt', 'C:\destination\dummy.txt'); } diff --git a/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php b/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php index 834a1c09fc..dd8f395318 100644 --- a/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php +++ b/tests/PhpWordTests/Exception/CreateTemporaryFileExceptionTest.php @@ -1,4 +1,5 @@ expectException(\PhpOffice\PhpWord\Exception\CreateTemporaryFileException::class); + $this->expectException(CreateTemporaryFileException::class); throw new CreateTemporaryFileException(); } diff --git a/tests/PhpWordTests/Exception/ExceptionTest.php b/tests/PhpWordTests/Exception/ExceptionTest.php index e186e94fad..09ee933c86 100644 --- a/tests/PhpWordTests/Exception/ExceptionTest.php +++ b/tests/PhpWordTests/Exception/ExceptionTest.php @@ -1,4 +1,5 @@ expectException(\PhpOffice\PhpWord\Exception\InvalidImageException::class); + $this->expectException(InvalidImageException::class); throw new InvalidImageException(); } diff --git a/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php b/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php index d1da3b2a85..7f2a1650e4 100644 --- a/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php +++ b/tests/PhpWordTests/Exception/InvalidStyleExceptionTest.php @@ -1,4 +1,5 @@ expectException(\PhpOffice\PhpWord\Exception\InvalidStyleException::class); + $this->expectException(InvalidStyleException::class); throw new InvalidStyleException(); } diff --git a/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php b/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php index e978b97254..2252b874ef 100644 --- a/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php +++ b/tests/PhpWordTests/Exception/UnsupportedImageTypeExceptionTest.php @@ -1,4 +1,5 @@ expectException(\PhpOffice\PhpWord\Exception\UnsupportedImageTypeException::class); + $this->expectException(UnsupportedImageTypeException::class); throw new UnsupportedImageTypeException(); } diff --git a/tests/PhpWordTests/IOFactoryTest.php b/tests/PhpWordTests/IOFactoryTest.php index 79f0fd0c76..6a8d746bd0 100644 --- a/tests/PhpWordTests/IOFactoryTest.php +++ b/tests/PhpWordTests/IOFactoryTest.php @@ -1,4 +1,5 @@ getDefaultFontSize()); } + /** + * Test set/get default asian font name. + */ + public function testSetGetDefaultAsianFontName(): void + { + $phpWord = new PhpWord(); + $fontName = 'Times New Roman'; + self::assertEquals(Settings::DEFAULT_FONT_NAME, $phpWord->getDefaultAsianFontName()); + $phpWord->setDefaultAsianFontName($fontName); + self::assertEquals($fontName, $phpWord->getDefaultAsianFontName()); + } + + /** + * Test set/get default font color. + */ + public function testSetGetDefaultFontColor(): void + { + $phpWord = new PhpWord(); + $fontColor = 'FF0000'; + self::assertEquals(Settings::DEFAULT_FONT_COLOR, $phpWord->getDefaultFontColor()); + $phpWord->setDefaultFontColor($fontColor); + self::assertEquals($fontColor, $phpWord->getDefaultFontColor()); + } + /** * Test set default paragraph style. */ diff --git a/tests/PhpWordTests/Reader/HTMLTest.php b/tests/PhpWordTests/Reader/HTMLTest.php index f091e5a275..7a35a06f78 100644 --- a/tests/PhpWordTests/Reader/HTMLTest.php +++ b/tests/PhpWordTests/Reader/HTMLTest.php @@ -1,4 +1,5 @@ canRead($filename)); } - /** - * Load. - */ - public function testLoad(): void + public function testLoadBasic(): void { $filename = __DIR__ . '/../_files/documents/reader.doc'; $phpWord = IOFactory::load($filename, 'MsDoc'); - self::assertInstanceOf('PhpOffice\\PhpWord\\PhpWord', $phpWord); + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + /** @var Text $element0 */ + $element0 = $elements[0]; + self::assertInstanceOf(Text::class, $element0); + self::assertEquals('Welcome to PhpWord', $element0->getText()); } public function testLoadHalfPointFont(): void @@ -76,6 +85,54 @@ public function testLoadHalfPointFont(): void } } + public function testLoadChinese(): void + { + $filename = __DIR__ . '/../_files/documents/docChinese.doc'; + $phpWord = IOFactory::load($filename, 'MsDoc'); + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + /** @var Text $element0 */ + $element0 = $elements[0]; + self::assertInstanceOf(Text::class, $element0); + self::assertEquals('OKKI AI 客户案例', $element0->getText()); + } + + public function testLoadCzech(): void + { + $filename = __DIR__ . '/../_files/documents/docCzech.doc'; + $phpWord = IOFactory::load($filename, 'MsDoc'); + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + /** @var Text $element0 */ + $element0 = $elements[0]; + self::assertInstanceOf(Text::class, $element0); + self::assertEquals('Příliš žluťoučký kůň pěl ďábelské ódy', $element0->getText()); + } + + public function testLoadSlovak(): void + { + $filename = __DIR__ . '/../_files/documents/docSlovak.doc'; + $phpWord = IOFactory::load($filename, 'MsDoc'); + self::assertInstanceOf(PhpWord::class, $phpWord); + + $sections = $phpWord->getSections(); + self::assertCount(1, $sections); + $elements = $sections[0]->getElements(); + self::assertArrayHasKey(0, $elements); + /** @var Text $element0 */ + $element0 = $elements[0]; + self::assertInstanceOf(Text::class, $element0); + self::assertEquals('Pondelok', $element0->getText()); + } + /** * Test exception on not existing file. */ diff --git a/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php index 0a1a4512db..8567dbcbea 100644 --- a/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php +++ b/tests/PhpWordTests/Reader/ODText/ODTextSectionTest.php @@ -1,4 +1,5 @@ getElement(1)->getText()); self::assertNotNull($textRun->getElement(1)->getTrackChange()); - /** @var \PhpOffice\PhpWord\Element\TrackChange $trackChange */ + /** @var TrackChange $trackChange */ $trackChange = $textRun->getElement(1)->getTrackChange(); self::assertEquals(TrackChange::DELETED, $trackChange->getChangeType()); self::assertEquals('three', $textRun->getElement(2)->getText()); self::assertNotNull($textRun->getElement(2)->getTrackChange()); - /** @var \PhpOffice\PhpWord\Element\TrackChange $trackChange */ + /** @var TrackChange $trackChange */ $trackChange = $textRun->getElement(2)->getTrackChange(); self::assertEquals(TrackChange::INSERTED, $trackChange->getChangeType()); } @@ -543,4 +546,134 @@ public function testReadFormFieldCheckbox(): void self::assertEquals('checkbox', $subElements[0]->getType()); self::assertEquals('SomeCheckbox', $subElements[0]->getName()); } + + /** + * Test reading of ruby. + */ + public function testReadRuby(): void + { + $documentXml = ' + + + + + + + + + + + + + + + + わたし + + + + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $elements[0]); + $subElements = $elements[0]->getElements(); // + self::assertInstanceOf('PhpOffice\PhpWord\Element\Ruby', $subElements[0]); + /** @var RubyProperties $rubyProperties */ + $rubyProperties = $subElements[0]->getProperties(); + self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $rubyProperties->getAlignment()); + self::assertEquals(12, $rubyProperties->getFontFaceSize()); + self::assertEquals(22, $rubyProperties->getFontPointsAboveBaseText()); + self::assertEquals(24, $rubyProperties->getFontSizeForBaseText()); + self::assertEquals('ja-JP', $rubyProperties->getLanguageId()); + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $subElements[0]->getBaseTextRun(); + self::assertEquals('私', $textRun->getText()); + $textRun = $subElements[0]->getRubyTextRun(); + self::assertEquals('わたし', $textRun->getText()); + } + + /** + * Test reading of ruby title. + */ + public function testReadRubyTitle(): void + { + $documentXml = ' + + + + + + + + + + + + + + + + + + + かみ + + + + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + $elements = $phpWord->getSection(0)->getElements(); + self::assertInstanceOf('PhpOffice\PhpWord\Element\Title', $elements[0]); + /** @var \PhpOffice\PhpWord\Element\Title $title */ + $title = $elements[0]; + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $title->getText(); + $subElements = $textRun->getElements(); // + self::assertInstanceOf('PhpOffice\PhpWord\Element\Ruby', $subElements[0]); + /** @var Ruby $ruby */ + $ruby = $subElements[0]; + /** @var RubyProperties $rubyProperties */ + $rubyProperties = $ruby->getProperties(); + self::assertEquals(RubyProperties::ALIGNMENT_DISTRIBUTE_SPACE, $rubyProperties->getAlignment()); + self::assertEquals(20, $rubyProperties->getFontFaceSize()); + self::assertEquals(38, $rubyProperties->getFontPointsAboveBaseText()); + self::assertEquals(40, $rubyProperties->getFontSizeForBaseText()); + self::assertEquals('ja-JP', $rubyProperties->getLanguageId()); + /** @var \PhpOffice\PhpWord\Element\TextRun $textRun */ + $textRun = $ruby->getBaseTextRun(); + self::assertEquals('神', $textRun->getText()); + $textRun = $ruby->getRubyTextRun(); + self::assertEquals('かみ', $textRun->getText()); + } } diff --git a/tests/PhpWordTests/Reader/Word2007/PartTest.php b/tests/PhpWordTests/Reader/Word2007/PartTest.php index 46089e8f02..4f19f8b91f 100644 --- a/tests/PhpWordTests/Reader/Word2007/PartTest.php +++ b/tests/PhpWordTests/Reader/Word2007/PartTest.php @@ -1,4 +1,5 @@ getStyle()); self::assertNotNull($elements[0]->getStyle()->getPosition()); self::assertInstanceOf('PhpOffice\PhpWord\Style\TablePosition', $elements[0]->getStyle()->getPosition()); - /** @var \PhpOffice\PhpWord\Style\TablePosition $tableStyle */ + /** @var TablePosition $tableStyle */ $tableStyle = $elements[0]->getStyle()->getPosition(); self::assertEquals(10, $tableStyle->getLeftFromText()); self::assertEquals(20, $tableStyle->getRightFromText()); @@ -118,7 +121,7 @@ public function testReadTableCellSpacing(): void $elements = $phpWord->getSection(0)->getElements(); self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); self::assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); - /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + /** @var Table $tableStyle */ $tableStyle = $elements[0]->getStyle(); self::assertEquals(TblWidth::AUTO, $tableStyle->getUnit()); self::assertEquals(10.5, $tableStyle->getCellSpacing()); @@ -165,6 +168,44 @@ public function testReadTableCellStyle(): void self::assertEquals('auto', $styleCell->getBorderBottomColor()); } + public function testReadTableCellsWithVerticalMerge(): void + { + $documentXml = ' + + + + + + + + + + + + + + + + + + '; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $table = $phpWord->getSection(0)->getElements()[0]; + self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $table); + + $rows = $table->getRows(); + self::assertCount(3, $rows); + foreach ($rows as $row) { + self::assertCount(1, $row->getCells()); + } + + self::assertSame('restart', $rows[0]->getCells()[0]->getStyle()->getVMerge()); + self::assertSame('continue', $rows[1]->getCells()[0]->getStyle()->getVMerge()); + self::assertNull($rows[2]->getCells()[0]->getStyle()->getVMerge()); + } + /** * Test reading of position. */ @@ -182,12 +223,12 @@ public function testReadPosition(): void $phpWord = $this->getDocumentFromString(['document' => $documentXml]); $elements = $phpWord->getSection(0)->getElements(); - /** @var \PhpOffice\PhpWord\Element\TextRun $elements */ + /** @var TextRun $elements */ $textRun = $elements[0]; self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); self::assertInstanceOf('PhpOffice\PhpWord\Style\Font', $textRun->getElement(0)->getFontStyle()); - /** @var \PhpOffice\PhpWord\Style\Font $fontStyle */ + /** @var Style\Font $fontStyle */ $fontStyle = $textRun->getElement(0)->getFontStyle(); self::assertEquals(15, $fontStyle->getPosition()); } @@ -205,7 +246,7 @@ public function testReadIndent(): void $elements = $phpWord->getSection(0)->getElements(); self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); self::assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); - /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + /** @var Table $tableStyle */ $tableStyle = $elements[0]->getStyle(); self::assertSame(TblWidth::TWIP, $tableStyle->getIndent()->getType()); self::assertSame(2160, $tableStyle->getIndent()->getValue()); @@ -224,7 +265,7 @@ public function testReadTableRTL(): void $elements = $phpWord->getSection(0)->getElements(); self::assertInstanceOf('PhpOffice\PhpWord\Element\Table', $elements[0]); self::assertInstanceOf('PhpOffice\PhpWord\Style\Table', $elements[0]->getStyle()); - /** @var \PhpOffice\PhpWord\Style\Table $tableStyle */ + /** @var Table $tableStyle */ $tableStyle = $elements[0]->getStyle(); self::assertTrue($tableStyle->isBidiVisual()); } @@ -243,12 +284,12 @@ public function testReadHidden(): void $phpWord = $this->getDocumentFromString(['document' => $documentXml]); $elements = $phpWord->getSection(0)->getElements(); - /** @var \PhpOffice\PhpWord\Element\TextRun $elements */ + /** @var TextRun $elements */ $textRun = $elements[0]; self::assertInstanceOf('PhpOffice\PhpWord\Element\TextRun', $textRun); self::assertInstanceOf('PhpOffice\PhpWord\Element\Text', $textRun->getElement(0)); self::assertInstanceOf('PhpOffice\PhpWord\Style\Font', $textRun->getElement(0)->getFontStyle()); - /** @var \PhpOffice\PhpWord\Style\Font $fontStyle */ + /** @var Style\Font $fontStyle */ $fontStyle = $textRun->getElement(0)->getFontStyle(); self::assertTrue($fontStyle->isHidden()); } @@ -289,4 +330,45 @@ public function testPageVerticalAlign(): void $sectionStyle = $phpWord->getSection(0)->getStyle(); self::assertEquals(VerticalJc::CENTER, $sectionStyle->getVAlign()); } + + /** + * @dataProvider providerIndentation + */ + public function testIndentation(string $indent, float $left, float $right, ?float $hanging, float $firstLine): void + { + $documentXml = " + + $indent + + + 1. + + "; + + $phpWord = $this->getDocumentFromString(['document' => $documentXml]); + + $section = $phpWord->getSection(0); + $textRun = $section->getElements()[0]; + self::assertInstanceOf(TextRun::class, $textRun); + + $paragraphStyle = $textRun->getParagraphStyle(); + self::assertInstanceOf(Style\Paragraph::class, $paragraphStyle); + + $indentation = $paragraphStyle->getIndentation(); + self::assertSame($left, $indentation->getLeft()); + self::assertSame($right, $indentation->getRight()); + self::assertSame($hanging, $indentation->getHanging()); + self::assertSame($firstLine, $indentation->getFirstLine()); + } + + /** + * @return Generator + */ + public static function providerIndentation() + { + yield ['', 709.00, 488.00, 10.0, 490.00]; + yield ['', 0, 0, 10.0, 490.00]; + yield ['', 709.00, 0, 0, 0]; + yield ['', 0, 488.00, 0, 0]; + } } diff --git a/tests/PhpWordTests/Reader/Word2007Test.php b/tests/PhpWordTests/Reader/Word2007Test.php index ebfd8ad7a2..65c8a4a71b 100644 --- a/tests/PhpWordTests/Reader/Word2007Test.php +++ b/tests/PhpWordTests/Reader/Word2007Test.php @@ -1,4 +1,5 @@ getSection(2); self::assertInstanceOf(Section::class, $section2); - $element2_31 = $section2->getElement(31); - self::assertInstanceOf(TextRun::class, $element2_31); - self::assertEquals('This is a paragraph with border differents', $element2_31->getText()); + $element2e31 = $section2->getElement(31); + self::assertInstanceOf(TextRun::class, $element2e31); + self::assertEquals('This is a paragraph with border differents', $element2e31->getText()); - /** @var Paragraph $element2_31_pStyle */ - $element2_31_pStyle = $element2_31->getParagraphStyle(); - self::assertInstanceOf(Paragraph::class, $element2_31_pStyle); + /** @var Paragraph $element2e31pStyle */ + $element2e31pStyle = $element2e31->getParagraphStyle(); + self::assertInstanceOf(Paragraph::class, $element2e31pStyle); // Top - self::assertEquals('FFFF00', $element2_31_pStyle->getBorderTopColor()); - self::assertEquals('10', $element2_31_pStyle->getBorderTopSize()); - self::assertEquals('dotted', $element2_31_pStyle->getBorderTopStyle()); + self::assertEquals('FFFF00', $element2e31pStyle->getBorderTopColor()); + self::assertEquals('10', $element2e31pStyle->getBorderTopSize()); + self::assertEquals('dotted', $element2e31pStyle->getBorderTopStyle()); // Right - self::assertEquals('00A933', $element2_31_pStyle->getBorderRightColor()); - self::assertEquals('4', $element2_31_pStyle->getBorderRightSize()); - self::assertEquals('dashed', $element2_31_pStyle->getBorderRightStyle()); + self::assertEquals('00A933', $element2e31pStyle->getBorderRightColor()); + self::assertEquals('4', $element2e31pStyle->getBorderRightSize()); + self::assertEquals('dashed', $element2e31pStyle->getBorderRightStyle()); // Bottom - self::assertEquals('F10D0C', $element2_31_pStyle->getBorderBottomColor()); - self::assertEquals('8', $element2_31_pStyle->getBorderBottomSize()); - self::assertEquals('dashSmallGap', $element2_31_pStyle->getBorderBottomStyle()); + self::assertEquals('F10D0C', $element2e31pStyle->getBorderBottomColor()); + self::assertEquals('8', $element2e31pStyle->getBorderBottomSize()); + self::assertEquals('dashSmallGap', $element2e31pStyle->getBorderBottomStyle()); // Left - self::assertEquals('3465A4', $element2_31_pStyle->getBorderLeftColor()); - self::assertEquals('8', $element2_31_pStyle->getBorderLeftSize()); - self::assertEquals('dashed', $element2_31_pStyle->getBorderLeftStyle()); + self::assertEquals('3465A4', $element2e31pStyle->getBorderLeftColor()); + self::assertEquals('8', $element2e31pStyle->getBorderLeftSize()); + self::assertEquals('dashed', $element2e31pStyle->getBorderLeftStyle()); } /** @@ -162,7 +163,7 @@ public function testLoadWord2011SettingsImageLoading(bool $hasImageLoading): voi } } - public function providerSettingsImageLoading(): iterable + public static function providerSettingsImageLoading(): iterable { return [ [true], diff --git a/tests/PhpWordTests/SettingsTest.php b/tests/PhpWordTests/SettingsTest.php index 46c72eab28..13b32e1293 100644 --- a/tests/PhpWordTests/SettingsTest.php +++ b/tests/PhpWordTests/SettingsTest.php @@ -1,4 +1,5 @@ compatibility = Settings::hasCompatibility(); + $this->defaultFontColor = Settings::getDefaultFontColor(); $this->defaultFontSize = Settings::getDefaultFontSize(); $this->defaultFontName = Settings::getDefaultFontName(); $this->defaultPaper = Settings::getDefaultPaper(); @@ -75,6 +80,7 @@ protected function setUp(): void protected function tearDown(): void { Settings::setCompatibility($this->compatibility); + Settings::setDefaultFontColor($this->defaultFontColor); Settings::setDefaultFontSize($this->defaultFontSize); Settings::setDefaultFontName($this->defaultFontName); Settings::setDefaultPaper($this->defaultPaper); @@ -216,6 +222,20 @@ public function testSetGetDefaultFontName(): void self::assertEquals('Times New Roman', Settings::getDefaultFontName()); } + /** + * Test set/get default font name. + */ + public function testSetGetDefaultAsianFontName(): void + { + self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultAsianFontName()); + self::assertFalse(Settings::setDefaultAsianFontName(' ')); + self::assertEquals(Settings::DEFAULT_FONT_NAME, Settings::getDefaultAsianFontName()); + self::assertTrue(Settings::setDefaultAsianFontName('Times New Roman')); + self::assertEquals('Times New Roman', Settings::getDefaultAsianFontName()); + self::assertFalse(Settings::setDefaultAsianFontName(' ')); + self::assertEquals('Times New Roman', Settings::getDefaultAsianFontName()); + } + /** * Test set/get default font size. */ @@ -236,6 +256,20 @@ public function testSetGetDefaultFontSize(): void self::assertEquals(12.5, Settings::getDefaultFontSize()); } + /** + * Test set/get default font color. + */ + public function testSetGetDefaultFontColor(): void + { + self::assertEquals(Settings::DEFAULT_FONT_COLOR, Settings::getDefaultFontColor()); + self::assertFalse(Settings::setDefaultFontColor(' ')); + self::assertEquals(Settings::DEFAULT_FONT_COLOR, Settings::getDefaultFontColor()); + self::assertTrue(Settings::setDefaultFontColor('FF0000')); + self::assertEquals('FF0000', Settings::getDefaultFontColor()); + self::assertFalse(Settings::setDefaultFontColor(' ')); + self::assertEquals('FF0000', Settings::getDefaultFontColor()); + } + /** * Test set/get default paper. */ @@ -271,6 +305,7 @@ public function testLoadConfig(): void 'pdfRendererPath' => '', 'defaultFontName' => 'Arial', 'defaultFontSize' => 10, + 'defaultFontColor' => '000000', 'outputEscapingEnabled' => false, 'defaultPaper' => 'A4', ]; diff --git a/tests/PhpWordTests/Shared/ConverterTest.php b/tests/PhpWordTests/Shared/ConverterTest.php index 95981210ec..36ba797aeb 100644 --- a/tests/PhpWordTests/Shared/ConverterTest.php +++ b/tests/PhpWordTests/Shared/ConverterTest.php @@ -1,4 +1,5 @@ test'; + $html = 'test'; $phpWord = new PhpWord(); $section = $phpWord->addSection(); Html::addHtml($section, $html); @@ -170,11 +174,11 @@ public function testParseUnderline(): void } /** - * Test text-decoration style. + * Test underline. */ - public function testParseTextDecoration(): void + public function testParseUnderline(): void { - $html = 'test'; + $html = 'test'; $phpWord = new PhpWord(); $section = $phpWord->addSection(); Html::addHtml($section, $html); @@ -184,6 +188,25 @@ public function testParseTextDecoration(): void self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); } + /** + * Test width. + * + * @dataProvider providerParseWidth + */ + public function testParseWidth(string $htmlSize, float $docxSize, string $docxUnit): void + { + $html = '
A
'; + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblW'; + self::assertTrue($doc->elementExists($xpath)); + self::assertEquals($docxSize, $doc->getElement($xpath)->getAttribute('w:w')); + self::assertEquals($docxUnit, $doc->getElement($xpath)->getAttribute('w:type')); + } + /** * Test font-variant style. */ @@ -249,6 +272,66 @@ public function testParseLineHeight(): void self::assertEquals(LineSpacingRule::AUTO, $doc->getElementAttribute('/w:document/w:body/w:p[5]/w:pPr/w:spacing', 'w:lineRule')); } + public function testParseCellPaddingStyle(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $top = 10; + $right = 11; + $bottom = 12; + $left = 13; + + $testValTop = Converter::pixelToTwip($top); + $testValRight = Converter::pixelToTwip($right); + $testValBottom = Converter::pixelToTwip($bottom); + $testValLeft = Converter::pixelToTwip($left); + + $html = ' + + + + + + + + + +
fullmixtopbottomleft
'; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:top'; + self::assertTrue($doc->elementExists($path)); + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:bottom'; + self::assertTrue($doc->elementExists($path)); + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:end'; + self::assertTrue($doc->elementExists($path)); + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[1]/w:tcPr/w:tcMar/w:start'; + self::assertTrue($doc->elementExists($path)); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[2]/w:tcPr/w:tcMar/w:end'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValRight, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[3]/w:tcPr/w:tcMar/w:top'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValTop, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[4]/w:tcPr/w:tcMar/w:bottom'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValBottom, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc[5]/w:tcPr/w:tcMar/w:start'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValLeft, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + } + /** * Test text-indent style. */ @@ -460,31 +543,31 @@ public function testParseTableAndCellWidth(): void $xpath = '/w:document/w:body/w:tbl/w:tblGrid/w:gridCol'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(25 * 50, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type')); //
elementExists($xpath)); self::assertEquals(6000, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type')); // elementExists($xpath)); self::assertEquals(4500, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type')); } /** @@ -598,7 +681,7 @@ public function testParseTableCellspacingRowBgColor(): void $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(3 * 15, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type')); $xpath = '/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:shd'; self::assertTrue($doc->elementExists($xpath)); @@ -631,7 +714,7 @@ public function testParseTableStyleAttributeInlineStyle(): void $xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblW'; self::assertTrue($doc->elementExists($xpath)); self::assertEquals(100 * 50, $doc->getElement($xpath)->getAttribute('w:w')); - self::assertEquals('pct', $doc->getElement($xpath)->getAttribute('w:type')); + self::assertEquals(TblWidth::PERCENT, $doc->getElement($xpath)->getAttribute('w:type')); $xpath = '/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:shd'; self::assertTrue($doc->elementExists($xpath)); @@ -984,6 +1067,27 @@ public function testParseLink2(): void self::assertEquals('bookmark', $doc->getElement('/w:document/w:body/w:p/w:hyperlink')->getAttribute('w:anchor')); } + public function testParseLinkAllowsAbsenceOfHref(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $html = '

text of href-less link

'; + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); + self::assertEquals('text of href-less link', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $html = '

text of empty-href link

'; + Html::addHtml($section, $html); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:hyperlink')); + self::assertEquals('text of empty-href link', $doc->getElement('/w:document/w:body/w:p/w:hyperlink/w:r/w:t')->nodeValue); + } + public function testParseMalformedStyleIsIgnored(): void { $phpWord = new PhpWord(); @@ -1203,4 +1307,62 @@ public function testDontDecodeAlreadyEncodedDoubleQuotes(): void $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); self::assertIsObject($doc); } + + public static function providerParseWidth(): array + { + return [ + ['auto', 5000, TblWidth::PERCENT], + ['100%', 5000, TblWidth::PERCENT], + ['200pt', 3999.999999999999, TblWidth::TWIP], + ['300px', 4500, TblWidth::TWIP], + ['400', 6000, TblWidth::TWIP], + ]; + } + + /** + * Test ruby. + */ + public function testParseRubyHtml(): void + { + $html = << + base text + ( + ruby text + ) + +HTML; + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby')); + self::assertEquals('ruby text', $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')->textContent); + self::assertEquals( + 'base text', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')->textContent + ); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign')); + self::assertEquals( + RubyProperties::ALIGNMENT_CENTER, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign', 'w:val') + ); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps')); + self::assertEquals( + 10, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps', 'w:val') + ); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText')); + self::assertEquals( + 20, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText', 'w:val') + ); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid')); + self::assertEquals( + 'en-US', + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid', 'w:val') + ); + } } diff --git a/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php b/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php index 9389c97411..d3c13bf8b4 100644 --- a/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php +++ b/tests/PhpWordTests/Shared/Microsoft/PasswordEncoderTest.php @@ -1,4 +1,5 @@ */ public function testZipArchive($zipClass = 'ZipArchive'): void { @@ -107,8 +106,6 @@ public function testZipArchive($zipClass = 'ZipArchive'): void /** * Test PclZip. - * - * @covers :: */ public function testPCLZip(): void { diff --git a/tests/PhpWordTests/Style/AbstractStyleTest.php b/tests/PhpWordTests/Style/AbstractStyleTest.php index 47c265738a..2f1585fd5a 100644 --- a/tests/PhpWordTests/Style/AbstractStyleTest.php +++ b/tests/PhpWordTests/Style/AbstractStyleTest.php @@ -1,4 +1,5 @@ setStyleValue('borderSize', $value); self::assertEquals($expected, $object->getBorderSize()); } + + /** + * Test cell padding. + */ + public function testPadding(): void + { + $object = new Cell(); + $methods = [ + 'paddingTop' => 10, + 'paddingBottom' => 20, + 'paddingLeft' => 30, + 'paddingRight' => 40, + ]; + + foreach ($methods as $methodName => $methodValue) { + $object->setStyleValue($methodName, $methodValue); + $getterName = 'get' . ucfirst($methodName); + + self::assertEquals($methodValue, $object->$getterName()); + } + } } diff --git a/tests/PhpWordTests/Style/ChartTest.php b/tests/PhpWordTests/Style/ChartTest.php index c756362fbd..cece336e0f 100644 --- a/tests/PhpWordTests/Style/ChartTest.php +++ b/tests/PhpWordTests/Style/ChartTest.php @@ -1,4 +1,5 @@ 240, 'marginLeft' => 240, 'position' => 10, - 'positioning' => \PhpOffice\PhpWord\Style\Image::POSITION_ABSOLUTE, - 'posHorizontal' => \PhpOffice\PhpWord\Style\Image::POSITION_HORIZONTAL_CENTER, - 'posVertical' => \PhpOffice\PhpWord\Style\Image::POSITION_VERTICAL_TOP, - 'posHorizontalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_COLUMN, - 'posVerticalRel' => \PhpOffice\PhpWord\Style\Image::POSITION_RELATIVE_TO_IMARGIN, + 'positioning' => Image::POSITION_ABSOLUTE, + 'posHorizontal' => Image::POSITION_HORIZONTAL_CENTER, + 'posVertical' => Image::POSITION_VERTICAL_TOP, + 'posHorizontalRel' => Image::POSITION_RELATIVE_TO_COLUMN, + 'posVerticalRel' => Image::POSITION_RELATIVE_TO_IMARGIN, 'wrapDistanceLeft' => 10, 'wrapDistanceRight' => 20, 'wrapDistanceTop' => 30, diff --git a/tests/PhpWordTests/Style/IndentationTest.php b/tests/PhpWordTests/Style/IndentationTest.php index 4de664477a..db13407ff3 100644 --- a/tests/PhpWordTests/Style/IndentationTest.php +++ b/tests/PhpWordTests/Style/IndentationTest.php @@ -1,4 +1,5 @@ \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT, - 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, - 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, - 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, + 'connectorType' => Line::CONNECTOR_TYPE_STRAIGHT, + 'beginArrow' => Line::ARROW_STYLE_BLOCK, + 'endArrow' => Line::ARROW_STYLE_OVAL, + 'dash' => Line::DASH_STYLE_LONG_DASH_DOT_DOT, 'weight' => 10, 'color' => 'red', ]; @@ -59,10 +60,10 @@ public function testSetStyleValue(): void $object = new Line(); $properties = [ - 'connectorType' => \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT, - 'beginArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK, - 'endArrow' => \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_OVAL, - 'dash' => \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT, + 'connectorType' => Line::CONNECTOR_TYPE_STRAIGHT, + 'beginArrow' => Line::ARROW_STYLE_BLOCK, + 'endArrow' => Line::ARROW_STYLE_OVAL, + 'dash' => Line::DASH_STYLE_LONG_DASH_DOT_DOT, 'weight' => 10, 'color' => 'red', ]; @@ -89,7 +90,7 @@ public function testSetGetFlip(): void */ public function testSetGetConnectorType(): void { - $expected = \PhpOffice\PhpWord\Style\Line::CONNECTOR_TYPE_STRAIGHT; + $expected = Line::CONNECTOR_TYPE_STRAIGHT; $object = new Line(); $object->setConnectorType($expected); self::assertEquals($expected, $object->getConnectorType()); @@ -122,7 +123,7 @@ public function testSetGetColor(): void */ public function testSetGetDash(): void { - $expected = \PhpOffice\PhpWord\Style\Line::DASH_STYLE_LONG_DASH_DOT_DOT; + $expected = Line::DASH_STYLE_LONG_DASH_DOT_DOT; $object = new Line(); $object->setDash($expected); self::assertEquals($expected, $object->getDash()); @@ -133,7 +134,7 @@ public function testSetGetDash(): void */ public function testSetGetBeginArrow(): void { - $expected = \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_BLOCK; + $expected = Line::ARROW_STYLE_BLOCK; $object = new Line(); $object->setBeginArrow($expected); self::assertEquals($expected, $object->getBeginArrow()); @@ -144,7 +145,7 @@ public function testSetGetBeginArrow(): void */ public function testSetGetEndArrow(): void { - $expected = \PhpOffice\PhpWord\Style\Line::ARROW_STYLE_CLASSIC; + $expected = Line::ARROW_STYLE_CLASSIC; $object = new Line(); $object->setEndArrow($expected); self::assertEquals($expected, $object->getEndArrow()); diff --git a/tests/PhpWordTests/Style/ListItemTest.php b/tests/PhpWordTests/Style/ListItemTest.php index bc1ad67014..59cdfeeda1 100644 --- a/tests/PhpWordTests/Style/ListItemTest.php +++ b/tests/PhpWordTests/Style/ListItemTest.php @@ -1,4 +1,5 @@ getTabs()); } + public function testHanging(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging($rand)); + self::assertEquals($rand, $object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging(null)); + self::assertNull($object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging($rand)); + self::assertEquals($rand, $object->getHanging()); + self::assertInstanceOf(Paragraph::class, $object->setHanging()); + self::assertNull($object->getHanging()); + } + + public function testIndent(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent($rand)); + self::assertEquals($rand, $object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent(null)); + self::assertNull($object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent($rand)); + self::assertEquals($rand, $object->getIndent()); + self::assertInstanceOf(Paragraph::class, $object->setIndent()); + self::assertNull($object->getIndent()); + } + + public function testIndentation(): void + { + $rand = mt_rand(0, 255); + $rand2 = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentation()); + // Set Basic indentation + self::assertInstanceOf(Paragraph::class, $object->setIndentation([])); + self::assertNotNull($object->getIndentation()); + self::assertEquals(0, $object->getIndentation()->getLeft()); + self::assertEquals(0, $object->getIndentation()->getRight()); + self::assertEquals(0, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : left + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'left' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals(0, $object->getIndentation()->getRight()); + self::assertEquals(0, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : right + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'right' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals(0, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : hanging + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'hanging' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals(0, $object->getIndentation()->getFirstLine()); + // Set indentation : firstline + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'firstline' => $rand, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals($rand, $object->getIndentation()->getFirstLine()); + // Replace indentation : left & firstline + self::assertInstanceOf(Paragraph::class, $object->setIndentation([ + 'left' => $rand2, + 'firstline' => $rand2, + ])); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand2, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals($rand2, $object->getIndentation()->getFirstLine()); + // Replace indentation : N/A + self::assertInstanceOf(Paragraph::class, $object->setIndentation()); + self::assertNotNull($object->getIndentation()); + self::assertEquals($rand2, $object->getIndentation()->getLeft()); + self::assertEquals($rand, $object->getIndentation()->getRight()); + self::assertEquals($rand, $object->getIndentation()->getHanging()); + self::assertEquals($rand2, $object->getIndentation()->getFirstLine()); + } + + public function testIndentFirstLine(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine($rand)); + self::assertEquals($rand, $object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine(null)); + self::assertNull($object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine($rand)); + self::assertEquals($rand, $object->getIndentFirstLine()); + self::assertInstanceOf(Paragraph::class, $object->setIndentFirstLine()); + self::assertNull($object->getIndentFirstLine()); + } + + public function testIndentLeft(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft($rand)); + self::assertEquals($rand, $object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft(null)); + self::assertNull($object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft($rand)); + self::assertEquals($rand, $object->getIndentLeft()); + self::assertInstanceOf(Paragraph::class, $object->setIndentLeft()); + self::assertNull($object->getIndentLeft()); + } + + public function testIndentRight(): void + { + $rand = mt_rand(0, 255); + + $object = new Paragraph(); + self::assertNull($object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight($rand)); + self::assertEquals($rand, $object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight(null)); + self::assertNull($object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight($rand)); + self::assertEquals($rand, $object->getIndentRight()); + self::assertInstanceOf(Paragraph::class, $object->setIndentRight()); + self::assertNull($object->getIndentRight()); + } + /** * Line height. */ diff --git a/tests/PhpWordTests/Style/RowTest.php b/tests/PhpWordTests/Style/RowTest.php index 6a53b9e25d..688a6b7b35 100644 --- a/tests/PhpWordTests/Style/RowTest.php +++ b/tests/PhpWordTests/Style/RowTest.php @@ -1,4 +1,5 @@ addSection(); $section->addText('${Test:width=100:ratio=true}'); - $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'Word2007'); + $objWriter = IOFactory::createWriter($phpWord, 'Word2007'); $objWriter->save($testFileName); self::assertFileExists($testFileName, "Generated file '{$testFileName}' not found!"); $resultFileName = 'images-test-result.docx'; - $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor($testFileName); + $templateProcessor = new TemplateProcessor($testFileName); unlink($testFileName); $templateProcessor->setImageValue('Test', $imagePath); $templateProcessor->setImageValue('Test1', $imagePath); @@ -1025,7 +1026,7 @@ public function testCloneBlockCanCloneABlockTwice(): void // and the placeholders have been replaced correctly $phpWord = IOFactory::load($templatePath); $sections = $phpWord->getSections(); - /** @var \PhpOffice\PhpWord\Element\TextRun[] $actualElements */ + /** @var TextRun[] $actualElements */ $actualElements = $sections[0]->getElements(); unlink($templatePath); $expectedElements = [ @@ -1079,7 +1080,7 @@ public function testCloneBlockCanCloneABlockTwiceWithCustomMacro(): void // and the placeholders have been replaced correctly $phpWord = IOFactory::load($templatePath); $sections = $phpWord->getSections(); - /** @var \PhpOffice\PhpWord\Element\TextRun[] $actualElements */ + /** @var TextRun[] $actualElements */ $actualElements = $sections[0]->getElements(); unlink($templatePath); diff --git a/tests/PhpWordTests/TestHelperDOCX.php b/tests/PhpWordTests/TestHelperDOCX.php index de9f1a81b7..2a6fbabae0 100644 --- a/tests/PhpWordTests/TestHelperDOCX.php +++ b/tests/PhpWordTests/TestHelperDOCX.php @@ -1,4 +1,5 @@ addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(20); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + $section->addRuby($baseTextRun, $rubyTextRun, $properties); + + $dom = Helper::getAsHTML($phpWord, '', '', ['ruby', 'rt', 'rp']); + $xpath = new DOMXPath($dom); + self::assertEquals(1, $xpath->query('/html/body/div/ruby')->length); + // ensure text is right + $rubyElement = $dom->getElementsByTagName('ruby')->item(0); + $rtElement = $dom->getElementsByTagName('rt')->item(0); + self::assertNotNull($rubyElement); + self::assertNotNull($rtElement); + self::assertEquals($baseTextRun->getText() . ' (' . $rubyTextRun->getText() . ')', $rubyElement->textContent); + self::assertEquals($rubyTextRun->getText(), $rtElement->textContent); + // check style + self::assertEquals('font-size:20pt;ruby-align:center;', $rubyElement->attributes->getNamedItem('style')->textContent); + self::assertEquals('font-size:10pt;', $rtElement->attributes->getNamedItem('style')->textContent); + } + + /** + * Tests writing ruby HTML. + */ + public function testWriteRubyHtmlParagraphStyle(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_CENTER); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(20); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(['lineHeight' => '8']); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(['lineHeight' => '4']); + $rubyTextRun->addText('わたし'); + $section->addRuby($baseTextRun, $rubyTextRun, $properties); + + $dom = Helper::getAsHTML($phpWord, '', '', ['ruby', 'rt', 'rp']); + $xpath = new DOMXPath($dom); + self::assertEquals(1, $xpath->query('/html/body/div/ruby')->length); + // ensure text is right + $rubyElement = $dom->getElementsByTagName('ruby')->item(0); + $rtElement = $dom->getElementsByTagName('rt')->item(0); + self::assertNotNull($rubyElement); + self::assertNotNull($rtElement); + self::assertEquals($baseTextRun->getText() . ' (' . $rubyTextRun->getText() . ')', $rubyElement->textContent); + self::assertEquals($rubyTextRun->getText(), $rtElement->textContent); + // check style + self::assertEquals('line-height: 8;font-size:20pt;ruby-align:center;', $rubyElement->attributes->getNamedItem('style')->textContent); + self::assertEquals('line-height: 4;font-size:10pt;', $rtElement->attributes->getNamedItem('style')->textContent); + } +} diff --git a/tests/PhpWordTests/Writer/HTML/Element/TableTest.php b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php index 032b7b69cd..cd0bafaab0 100644 --- a/tests/PhpWordTests/Writer/HTML/Element/TableTest.php +++ b/tests/PhpWordTests/Writer/HTML/Element/TableTest.php @@ -1,4 +1,5 @@ addSection(); + + $table = $section->addTable(); + $row = $table->addRow(); + + $cell = $row->addCell(); + $cell->addText('top text'); + $cell->getStyle()->setVAlign(VerticalJc::TOP); + + $cell = $row->addCell(); + $cell->addText('bottom text'); + $cell->getStyle()->setVAlign(VerticalJc::BOTTOM); + + $cell = $row->addCell(); + $cell->addText('no vAlign'); + $cell->getStyle()->setVAlign(VerticalJc::BOTTOM); + $cell->getStyle()->setVAlign(); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + $cell1Style = Helper::getTextContent($xpath, '//table/tr/td[1]', 'style'); + $cell2Style = Helper::getTextContent($xpath, '//table/tr/td[2]', 'style'); + self::assertSame('vertical-align: top;', $cell1Style); + self::assertSame('vertical-align: bottom;', $cell2Style); + + $cell3Query = $xpath->query('//table/tr/td[3]'); + self::assertNotFalse($cell3Query); + self::assertCount(1, $cell3Query); + + $cell3Style = $cell3Query->item(0)->attributes->getNamedItem('style'); + self::assertNull($cell3Style); + } + + public function testWriteTableCellVMerge(): void + { + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + + $table = $section->addTable(); + + $cell = $table->addRow()->addCell(); + $cell->addText('text'); + $cell->getStyle()->setVMerge(Style\Cell::VMERGE_RESTART); + + $cell = $table->addRow()->addCell(); + $cell->getStyle()->setVMerge(Style\Cell::VMERGE_CONTINUE); + + $cell = $table->addRow()->addCell(); + $cell->addText('no vMerge'); + $cell->getStyle()->setVMerge(Style\Cell::VMERGE_CONTINUE); + $cell->getStyle()->setVMerge(); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + $cell1Style = Helper::getTextContent($xpath, '//table/tr[1]/td[1]', 'rowspan'); + self::assertSame('2', $cell1Style); + + $cell3Query = $xpath->query('//table/tr[3]/td[1]'); + self::assertNotFalse($cell3Query); + self::assertCount(1, $cell3Query); + self::assertNull($cell3Query->item(0)->attributes->getNamedItem('rowspan')); + } } diff --git a/tests/PhpWordTests/Writer/HTML/ElementTest.php b/tests/PhpWordTests/Writer/HTML/ElementTest.php index 64fa5a31ff..3b2580381f 100644 --- a/tests/PhpWordTests/Writer/HTML/ElementTest.php +++ b/tests/PhpWordTests/Writer/HTML/ElementTest.php @@ -1,4 +1,5 @@ addText('my other text'); $text2->setTrackChange(new TrackChange(TrackChange::DELETED, 'another author', new DateTime())); - $dom = $this->getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord); $xpath = new DOMXPath($dom); self::assertEquals(1, $xpath->query('/html/body/div/p[1]/ins')->length); @@ -97,7 +98,7 @@ public function testWriteColSpan(): void $cell22 = $row2->addCell(500); $cell22->addText('second cell'); - $dom = $this->getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord); $xpath = new DOMXPath($dom); self::assertEquals(1, $xpath->query('/html/body/div/table/tr[1]/td')->length); @@ -131,7 +132,7 @@ public function testWriteRowSpan(): void $row3->addCell(null, ['vMerge' => 'continue']); $row3->addCell(500)->addText('third cell being spanned'); - $dom = $this->getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord); $xpath = new DOMXPath($dom); self::assertEquals(2, $xpath->query('/html/body/div/table/tr[1]/td')->length); @@ -139,13 +140,41 @@ public function testWriteRowSpan(): void self::assertEquals(1, $xpath->query('/html/body/div/table/tr[2]/td')->length); } - private function getAsHTML(PhpWord $phpWord) + /** + * Tests writing table with rowspan and colspan. + */ + public function testWriteRowSpanAndColSpan(): void { - $htmlWriter = new HTML($phpWord); - $dom = new DOMDocument(); - $dom->loadHTML($htmlWriter->getContent()); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $table = $section->addTable(); + + $row1 = $table->addRow(); + $row1->addCell(500)->addText('A'); + $row1->addCell(1000, ['gridSpan' => 2])->addText('B'); + $row1->addCell(500, ['vMerge' => 'restart'])->addText('C'); + + $row2 = $table->addRow(); + $row2->addCell(1500, ['gridSpan' => 3])->addText('D'); + $row2->addCell(null, ['vMerge' => 'continue']); + + $row3 = $table->addRow(); + $row3->addCell(500)->addText('E'); + $row3->addCell(500)->addText('F'); + $row3->addCell(500)->addText('G'); + $row3->addCell(null, ['vMerge' => 'continue']); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + + self::assertEquals(3, $xpath->query('/html/body/div/table/tr[1]/td')->length); + self::assertEquals('2', $xpath->query('/html/body/div/table/tr[1]/td[2]')->item(0)->attributes->getNamedItem('colspan')->textContent); + self::assertEquals('3', $xpath->query('/html/body/div/table/tr[1]/td[3]')->item(0)->attributes->getNamedItem('rowspan')->textContent); + + self::assertEquals(1, $xpath->query('/html/body/div/table/tr[2]/td')->length); + self::assertEquals('3', $xpath->query('/html/body/div/table/tr[2]/td[1]')->item(0)->attributes->getNamedItem('colspan')->textContent); - return $dom; + self::assertEquals(3, $xpath->query('/html/body/div/table/tr[3]/td')->length); } public function testWriteTitleTextRun(): void @@ -208,7 +237,7 @@ public function testWriteTableLayout(): void $row2 = $table2->addRow(); $row2->addCell()->addText('auto layout table'); - $dom = $this->getAsHTML($phpWord); + $dom = Helper::getAsHTML($phpWord); $xpath = new DOMXPath($dom); self::assertEquals('table-layout: fixed;', $xpath->query('/html/body/div/table[1]')->item(0)->attributes->getNamedItem('style')->textContent); diff --git a/tests/PhpWordTests/Writer/HTML/FontTest.php b/tests/PhpWordTests/Writer/HTML/FontTest.php index 442c2639c9..0a203b7237 100644 --- a/tests/PhpWordTests/Writer/HTML/FontTest.php +++ b/tests/PhpWordTests/Writer/HTML/FontTest.php @@ -1,4 +1,5 @@ defaultFontName = Settings::getDefaultFontName(); $this->defaultFontSize = Settings::getDefaultFontSize(); + $this->defaultFontColor = Settings::getDefaultFontColor(); } /** @@ -49,6 +54,38 @@ protected function tearDown(): void { Settings::setDefaultFontName($this->defaultFontName); Settings::setDefaultFontSize($this->defaultFontSize); + Settings::setDefaultFontColor($this->defaultFontColor); + } + + public function testDefaultDefaults(): void + { + $phpWord = new PhpWord(); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + $style = Helper::getTextContent($xpath, '/html/head/style[1]'); + + $prg = preg_match('/body {(.*?)}/', $style, $matches); + self::assertNotEmpty($matches); + self::assertNotFalse($prg); + self::assertEquals('body {font-family: \'Arial\'; font-size: 12pt; color: #000000;}', $matches[0]); + } + + public function testSettingDefaultFontColor(): void + { + $phpWord = new PhpWord(); + + $defaultFontColor = '00FF00'; + $phpWord->setDefaultFontColor($defaultFontColor); + + $dom = Helper::getAsHTML($phpWord); + $xpath = new DOMXPath($dom); + $style = Helper::getTextContent($xpath, '/html/head/style[1]'); + + $prg = preg_match('/body {(.*?)}/', $style, $matches); + self::assertNotEmpty($matches); + self::assertNotFalse($prg); + self::assertEquals('body {font-family: \'Arial\'; font-size: 12pt; color: #00FF00;}', $matches[0]); } /** @@ -85,21 +122,27 @@ public function testFontNames1(): void $style = Helper::getTextContent($xpath, '/html/head/style'); $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); - self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]); + self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt; color: #000000;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]); $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style2 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style3 {font-family: \'hack attempt'}; display:none\'; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style4 {font-family: \'padmaa 1.1\'; font-size: 10pt; font-weight: bold;}', $matches[0]); $prg = preg_match('/^[.]style5[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style5 {font-family: \'MingLiU-ExtB\'; font-size: 10pt; font-weight: bold;}', $matches[0]); } @@ -135,18 +178,23 @@ public function testFontNames2(): void $style = Helper::getTextContent($xpath, '/html/head/style'); $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); - self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt;}', $matches[0]); + self::assertEquals('* {font-family: \'Courier New\'; font-size: 12pt; color: #000000;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]); $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style2 {font-family: \'Arial\', sans-serif; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style3 {font-family: \'DejaVu Sans Monospace\', monospace; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style4 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]); } @@ -182,18 +230,23 @@ public function testFontNames3(): void $style = Helper::getTextContent($xpath, '/html/head/style'); $prg = preg_match('/^[*][^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); - self::assertEquals('* {font-family: \'Courier New\', monospace; font-size: 12pt;}', $matches[0]); + self::assertEquals('* {font-family: \'Courier New\', monospace; font-size: 12pt; color: #000000;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style1 {font-family: \'Tahoma\'; font-size: 10pt; color: #1B2232; font-weight: bold;}', $matches[0]); $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style2 {font-family: \'Arial\', sans-serif; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style3 {font-family: \'DejaVu Sans Monospace\', monospace; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style4 {font-family: \'Arial\'; font-size: 10pt;}', $matches[0]); } @@ -222,17 +275,21 @@ public function testWhiteSpace(): void $style = Helper::getTextContent($xpath, '/html/head/style'); self::assertNotFalse(preg_match('/^[*][^\\r\\n]*/m', $style, $matches)); - self::assertEquals('* {font-family: \'Arial\'; font-size: 12pt; white-space: pre-wrap;}', $matches[0]); + self::assertEquals('* {font-family: \'Arial\'; font-size: 12pt; color: #000000; white-space: pre-wrap;}', $matches[0]); $prg = preg_match('/^[.]style1[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style1 {font-family: \'Courier New\'; font-size: 10pt; white-space: pre-wrap;}', $matches[0]); $prg = preg_match('/^[.]style2[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style2 {font-family: \'Courier New\'; font-size: 10pt;}', $matches[0]); $prg = preg_match('/^[.]style3[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style3 {font-family: \'Courier New\'; font-size: 10pt; white-space: normal;}', $matches[0]); $prg = preg_match('/^[.]style4[^\\r\\n]*/m', $style, $matches); + self::assertNotEmpty($matches); self::assertNotFalse($prg); self::assertEquals('.style4 {font-family: \'Courier New\'; font-size: 10pt;}', $matches[0]); } diff --git a/tests/PhpWordTests/Writer/HTML/Helper.php b/tests/PhpWordTests/Writer/HTML/Helper.php index b777d4be14..37f640d28a 100644 --- a/tests/PhpWordTests/Writer/HTML/Helper.php +++ b/tests/PhpWordTests/Writer/HTML/Helper.php @@ -1,4 +1,5 @@ setDefaultWhiteSpace($defaultWhiteSpace); $htmlWriter->setDefaultGenericFont($defaultGenericFont); $dom = new DOMDocument(); + // DOMDocument does not always accept HTML5 tags like + // So, we can manually filter out those errors for testing purposes ONLY. + $original = libxml_use_internal_errors(true); $dom->loadHTML($htmlWriter->getContent()); + $errors = libxml_get_errors(); + $errorsToReport = []; + foreach ($errors as $error) { + /** @var LibXMLError $error */ + if ($error->code === 801) { + $didFindValidTag = false; + foreach ($validTags as $tag) { + if (trim($error->message) === ('Tag ' . $tag . ' invalid')) { + $didFindValidTag = true; + + break; + } + } + if (!$didFindValidTag) { + $errorsToReport[] = $error; + } + } else { + $errorsToReport[] = $error; + } + } + libxml_clear_errors(); + libxml_use_internal_errors($original); + if (count($errorsToReport) > 0) { + throw new Exception('Errors when loading DOMDocument: ' . print_r($errors, true)); + } return $dom; } diff --git a/tests/PhpWordTests/Writer/HTML/ParagraphTest.php b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php index dc306df978..2b2724dba8 100644 --- a/tests/PhpWordTests/Writer/HTML/ParagraphTest.php +++ b/tests/PhpWordTests/Writer/HTML/ParagraphTest.php @@ -1,4 +1,5 @@ addSection(); $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); $section->addImage(__DIR__ . '/../../../_files/images/mario.gif', ['align' => 'end']); @@ -59,9 +61,11 @@ public function testImage1(): void $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; self::assertTrue($doc->elementExists($path)); + self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name')); self::assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name')); $path = '/office:document-content/office:body/office:text/text:section/text:p[3]'; self::assertTrue($doc->elementExists($path)); + self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name')); self::assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name')); } @@ -70,7 +74,7 @@ public function testImage1(): void */ public function testImage2(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); Settings::setDefaultRtl(false); $section = $phpWord->addSection(); $section->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); @@ -89,8 +93,36 @@ public function testImage2(): void $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; self::assertTrue($doc->elementExists($path)); self::assertEquals('IM1', $doc->getElementAttribute($path, 'text:style-name')); + self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name')); $path = '/office:document-content/office:body/office:text/text:section/text:p[3]'; self::assertTrue($doc->elementExists($path)); self::assertEquals('IM2', $doc->getElementAttribute($path, 'text:style-name')); + self::assertFalse($doc->hasElementAttribute($path, 'draw:text-style-name')); + } + + /** + * Test writing image not in a section. + */ + public function testImageInTextRun(): void + { + $phpWord = new PhpWord(); + Settings::setDefaultRtl(false); + $section = $phpWord->addSection(); + $textRun = $section->addTextRun(); + $textRun->addImage(__DIR__ . '/../../../_files/images/earth.jpg'); + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $s2a = '/office:document-content/office:automatic-styles'; + $element = "$s2a/style:style[4]"; + self::assertEquals('IM1', $doc->getElementAttribute($element, 'style:name')); + $element .= '/style:paragraph-properties'; + self::assertEquals('left', $doc->getElementAttribute($element, 'fo:text-align')); + + $path = '/office:document-content/office:body/office:text/text:section/text:p[2]'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals('P1', $doc->getElementAttribute($path, 'text:style-name')); + $path = '/office:document-content/office:body/office:text/text:section/text:p[2]/draw:frame'; + self::assertTrue($doc->elementExists($path)); + self::assertTrue($doc->hasElementAttribute($path, 'draw:text-style-name')); + self::assertEquals('IM1', $doc->getElementAttribute($path, 'draw:text-style-name')); } } diff --git a/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php b/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php new file mode 100644 index 0000000000..9f531255fc --- /dev/null +++ b/tests/PhpWordTests/Writer/ODText/Element/ListItemRunTest.php @@ -0,0 +1,83 @@ +addSection() + ->addListItemRun() + ->addText($expected); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $xPath = '/office:document-content/office:body/office:text/text:section/text:list'; + + self::assertTrue($doc->elementExists($xPath)); + self::assertTrue($doc->hasElementAttribute($xPath, 'text:style-name')); + self::assertEquals('PHPWordListType3', $doc->getElementAttribute($xPath, 'text:style-name')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p/text:span')); + self::assertEquals($expected, $doc->getElement($xPath . '/text:list-item/text:p/text:span')->nodeValue); + } + + public function testAddListItemRunLevels(): void + { + $expected = 'List item run : '; + + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $section->addListItemRun(0)->addText($expected . '1'); + $section->addListItemRun(1)->addText($expected . '2'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + + $xPath = '/office:document-content/office:body/office:text/text:section/text:list'; + + self::assertTrue($doc->elementExists($xPath)); + self::assertTrue($doc->hasElementAttribute($xPath, 'text:style-name')); + self::assertEquals('PHPWordListType3', $doc->getElementAttribute($xPath, 'text:style-name')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:p/text:span')); + self::assertEquals($expected . '1', $doc->getElement($xPath . '/text:list-item/text:p/text:span')->nodeValue); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:list/text:list-item')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:list/text:list-item/text:p')); + self::assertTrue($doc->elementExists($xPath . '/text:list-item/text:list/text:list-item/text:p/text:span')); + self::assertEquals($expected . '2', $doc->getElement($xPath . '/text:list-item/text:list/text:list-item/text:p/text:span')->nodeValue); + } +} diff --git a/tests/PhpWordTests/Writer/ODText/ElementTest.php b/tests/PhpWordTests/Writer/ODText/ElementTest.php index 0ad0325656..4df140aaa4 100644 --- a/tests/PhpWordTests/Writer/ODText/ElementTest.php +++ b/tests/PhpWordTests/Writer/ODText/ElementTest.php @@ -1,4 +1,5 @@ addTitleStyle(1, ['name' => 'Times New Roman', 'size' => 18, 'bold' => true]); $section = $phpWord->addSection(); $section->addTitle('Text Title', 1); $section->addText('Text following Text Title'); - $textRun = new \PhpOffice\PhpWord\Element\TextRun(); + $textRun = new TextRun(); $textRun->addText('Text Run'); $textRun->addText(' Title'); $section->addTitle($textRun, 1); @@ -275,7 +278,7 @@ public function testPageBreak(): void */ public function testTrackedChanges(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); // New portrait section $section = $phpWord->addSection(); @@ -327,4 +330,36 @@ public function testTrackedChanges(): void $element = "$p2t/text:change"; self::AssertEquals($tc3id, $doc->getElementAttribute($element, 'text:change-id')); } + + /** + * Test ruby output. + * Note that this test will need to be updated when ODT Ruby output supports + * ODT's native ruby functionality. + */ + public function testRubyText(): void + { + $esc = \PhpOffice\PhpWord\Settings::isOutputEscapingEnabled(); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled(true); + $phpWord = new PhpWord(); + $section = $phpWord->addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(18); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + $section->addRuby($baseTextRun, $rubyTextRun, $properties); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + \PhpOffice\PhpWord\Settings::setOutputEscapingEnabled($esc); + $p2t = '/office:document-content/office:body/office:text/text:section'; + $element = "$p2t/text:p[2]"; + self::assertTrue($doc->elementExists($element)); + self::assertEquals('私 (わたし)', $doc->getElement($element)->nodeValue); + } } diff --git a/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php index 3ebc534b21..6742b20ad5 100644 --- a/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/ODText/Part/AbstractPartTest.php @@ -1,4 +1,5 @@ getMockForAbstractClass(\PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart::class); + $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); $object->setParentWriter(new ODText()); self::assertEquals(new ODText(), $object->getParentWriter()); } @@ -45,7 +46,7 @@ public function testSetGetParentWriterNull(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('No parent WriterInterface assigned.'); - $object = $this->getMockForAbstractClass(\PhpOffice\PhpWord\Writer\ODText\Part\AbstractPart::class); + $object = $this->getMockForAbstractClass(ODText\Part\AbstractPart::class); $object->getParentWriter(); } } diff --git a/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php b/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php index 834b4d4fbb..e6cad15ea0 100644 --- a/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php +++ b/tests/PhpWordTests/Writer/ODText/Part/ContentTest.php @@ -1,4 +1,5 @@ addSection(); $section->addText('This is red (800) in rtf/html, default in docx/odt', ['color' => '800']); $section->addText('This should be cyanish (008787)', ['color' => '008787']); - $section->addText('This should be dark green (FGCOLOR_DARKGREEN)', ['color' => \PhpOffice\PhpWord\Style\Font::FGCOLOR_DARKGREEN]); + $section->addText('This should be dark green (FGCOLOR_DARKGREEN)', ['color' => Font::FGCOLOR_DARKGREEN]); $section->addText('This color is default (unknow)', ['color' => 'unknow']); $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); @@ -219,7 +220,7 @@ public function testFieldStyles(): void $fld->setFontStyle(['color' => '008000']); $textrun = $section->addTextRun(); $fld = $textrun->addField('DATE'); - $font = new \PhpOffice\PhpWord\Style\Font(); + $font = new Font(); $font->setColor('000080'); $fld->setFontStyle($font); $textrun = $section->addTextRun(); diff --git a/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php b/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php new file mode 100644 index 0000000000..b06242706d --- /dev/null +++ b/tests/PhpWordTests/Writer/ODText/Style/NumberingTest.php @@ -0,0 +1,70 @@ +addNumberingStyle($expected, [ + 'type' => 'multilevel', + 'levels' => [ + [ + 'start' => 1, + 'format' => 'decimal', + 'restart' => 1, + 'suffix' => 'space', + 'text' => '%1.', + 'alignment' => Jc::START, + ], + ], + ]); + $phpWord->addSection() + ->addListItemRun(0, $expected) + ->addText('List item run 1'); + + $doc = TestHelperDOCX::getDocument($phpWord, 'ODText'); + $doc->setDefaultFile('styles.xml'); + + $xPath = '/office:document-styles/office:styles'; + self::assertTrue($doc->elementExists($xPath)); + self::assertTrue($doc->elementExists($xPath . '/text:list-style')); + self::assertTrue($doc->hasElementAttribute($xPath . '/text:list-style', 'style:name')); + self::assertEquals($expected, $doc->getElementAttribute($xPath . '/text:list-style', 'style:name')); + self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet')); + self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet/style:list-level-properties')); + self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet/style:list-level-properties/style:list-level-label-alignment')); + self::assertTrue($doc->elementExists($xPath . '/text:list-style/text:list-level-style-bullet/style:text-properties')); + } +} diff --git a/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php index b638b380b6..bc02ca8ea0 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php +++ b/tests/PhpWordTests/Writer/ODText/Style/Paragraph2Test.php @@ -1,4 +1,5 @@ addParagraphStyle('parstyle1', ['align' => 'start']); $phpWord->addParagraphStyle('parstyle2', ['align' => 'end']); $section = $phpWord->addSection(); @@ -403,7 +404,7 @@ public function testTextRun(): void */ public function testTextRunUnnamed(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $parstyle1 = ['align' => 'start']; $parstyle2 = ['align' => 'end']; $section = $phpWord->addSection(); @@ -437,7 +438,7 @@ public function testTextRunUnnamed(): void */ public function testEmptyFontAndParagraphStyles(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $phpWord->addFontStyle('namedfont', ['name' => 'Courier New', 'size' => 8]); $phpWord->addParagraphStyle('namedpar', ['lineHeight' => 1.08]); diff --git a/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php b/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php index cbd58da455..83f5962944 100644 --- a/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php +++ b/tests/PhpWordTests/Writer/ODText/Style/SectionTest.php @@ -1,4 +1,5 @@ addFontStyle('hdrstyle1', ['name' => 'Courier New', 'size' => 8]); $section = $phpWord->addSection(['paperSize' => 'Letter', 'marginTop' => $margins, 'marginBottom' => $margins]); diff --git a/tests/PhpWordTests/Writer/ODText/StyleTest.php b/tests/PhpWordTests/Writer/ODText/StyleTest.php index 0d36b4899c..21d4c8bb53 100644 --- a/tests/PhpWordTests/Writer/ODText/StyleTest.php +++ b/tests/PhpWordTests/Writer/ODText/StyleTest.php @@ -1,4 +1,5 @@ addRow(); diff --git a/tests/PhpWordTests/Writer/RTF/Element2Test.php b/tests/PhpWordTests/Writer/RTF/Element2Test.php index 7d36fac869..2220d93b68 100644 --- a/tests/PhpWordTests/Writer/RTF/Element2Test.php +++ b/tests/PhpWordTests/Writer/RTF/Element2Test.php @@ -1,4 +1,5 @@ removeCr($field)); } @@ -58,7 +59,7 @@ public function testFilenameFieldOptionsPath(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('FILENAME', [], ['Path']); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{\\field{\\*\\fldinst FILENAME \\\\p}{\\fldrslt}}\\par\n", $this->removeCr($field)); } @@ -67,7 +68,7 @@ public function testPageField(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('PAGE'); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{\\field{\\*\\fldinst PAGE}{\\fldrslt}}\\par\n", $this->removeCr($field)); } @@ -76,7 +77,7 @@ public function testNumpageField(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('NUMPAGES'); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{\\field{\\*\\fldinst NUMPAGES}{\\fldrslt}}\\par\n", $this->removeCr($field)); } @@ -85,7 +86,7 @@ public function testDateField(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('DATE', ['dateformat' => 'd MM yyyy H:mm:ss']); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{\\field{\\*\\fldinst DATE \\\\@ \"d MM yyyy H:mm:ss\"}{\\fldrslt}}\\par\n", $this->removeCr($field)); } @@ -94,7 +95,7 @@ public function testIndexField(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Field('INDEX'); - $field = new \PhpOffice\PhpWord\Writer\RTF\Element\Field($parentWriter, $element); + $field = new RTF\Element\Field($parentWriter, $element); self::assertEquals("{}\\par\n", $this->removeCr($field)); } @@ -115,7 +116,7 @@ public function testTable(): void $tce->addText('3'); $tce = $element->addCell($width); $tce->addText('4'); - $table = new \PhpOffice\PhpWord\Writer\RTF\Element\Table($parentWriter, $element); + $table = new RTF\Element\Table($parentWriter, $element); $expect = implode("\n", [ '\\pard', "\\trowd \\cellx$width \\cellx$width2 ", @@ -147,7 +148,7 @@ public function testTextRun(): void $element = new \PhpOffice\PhpWord\Element\TextRun(); $element->addText('Hello '); $element->addText('there.'); - $textrun = new \PhpOffice\PhpWord\Writer\RTF\Element\TextRun($parentWriter, $element); + $textrun = new RTF\Element\TextRun($parentWriter, $element); $expect = "\\pard\\nowidctlpar {{\\cf0\\f0 Hello }{\\cf0\\f0 there.}}\\par\n"; self::assertEquals($expect, $this->removeCr($textrun)); } @@ -158,7 +159,7 @@ public function testTextRunParagraphStyle(): void $element = new \PhpOffice\PhpWord\Element\TextRun(['spaceBefore' => 0, 'spaceAfter' => 0]); $element->addText('Hello '); $element->addText('there.'); - $textrun = new \PhpOffice\PhpWord\Writer\RTF\Element\TextRun($parentWriter, $element); + $textrun = new RTF\Element\TextRun($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\sb0\\sa0{{\\cf0\\f0 Hello }{\\cf0\\f0 there.}}\\par\n"; self::assertEquals($expect, $this->removeCr($textrun)); } @@ -170,8 +171,49 @@ public function testTitle(): void $phpWord->addTitleStyle(1, [], ['spaceBefore' => 0, 'spaceAfter' => 0]); $section = $phpWord->addSection(); $element = $section->addTitle('First Heading', 1); - $elwrite = new \PhpOffice\PhpWord\Writer\RTF\Element\Title($parentWriter, $element); + $elwrite = new RTF\Element\Title($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\sb0\\sa0{\\outlinelevel0{\\cf0\\f0 First Heading}\\par\n}"; self::assertEquals($expect, $this->removeCr($elwrite)); } + + public function testRuby(): void + { + $parentWriter = new RTF(); + $properties = new \PhpOffice\PhpWord\ComplexType\RubyProperties(); + $baseTextRun = new \PhpOffice\PhpWord\Element\TextRun(null); + $baseTextRun->addText('base text'); + $rubyTextRun = new \PhpOffice\PhpWord\Element\TextRun(null); + $rubyTextRun->addText('ruby'); + $element = new \PhpOffice\PhpWord\Element\TextRun(); + $element->addRuby($baseTextRun, $rubyTextRun, $properties); + + $textrun = new RTF\Element\TextRun($parentWriter, $element); + $expect = "\\pard\\nowidctlpar {{base text (ruby)}}\\par\n"; + self::assertEquals($expect, $this->removeCr($textrun)); + } + + public function testRubyTitle(): void + { + $parentWriter = new RTF(); + $properties = new \PhpOffice\PhpWord\ComplexType\RubyProperties(); + $baseTextRun = new \PhpOffice\PhpWord\Element\TextRun(null); + $baseTextRun->addText('base text'); + $rubyTextRun = new \PhpOffice\PhpWord\Element\TextRun(null); + $rubyTextRun->addText('ruby'); + $textRun = new \PhpOffice\PhpWord\Element\TextRun(); + $textRun->addRuby($baseTextRun, $rubyTextRun, $properties); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord->addTitleStyle( + 1, + ['size' => 24, 'bold' => true, 'color' => '000099'], + ['spaceBefore' => 0, 'spaceAfter' => 2] + ); + $section = $phpWord->addSection(); + $element = $section->addTitle($textRun, 1); + $elwrite = new RTF\Element\Title($parentWriter, $element); + + $expect = "\\pard\\nowidctlpar \\sb0\\sa2{\\outlinelevel0{\\cf0\\f0\\fs48\\b base text (ruby)}\\par\n}"; + self::assertEquals($expect, $this->removeCr($elwrite)); + } } diff --git a/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php b/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php index ec71b2f078..3b4f86c7d7 100644 --- a/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php +++ b/tests/PhpWordTests/Writer/RTF/HeaderFooterTest.php @@ -1,4 +1,5 @@ setRight(2); $indentation->setFirstLine(3); - $indentWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Indentation($indentation); + $indentWriter = new RTF\Style\Indentation($indentation); $indentWriter->setParentWriter(new RTF()); $result = $indentWriter->write(); @@ -89,7 +90,7 @@ public function testRightTab(): void $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_RIGHT); $tabRight->setPosition(5); - $tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight); + $tabWriter = new RTF\Style\Tab($tabRight); $tabWriter->setParentWriter(new RTF()); $result = $tabWriter->write(); @@ -101,7 +102,7 @@ public function testCenterTab(): void $tabRight = new \PhpOffice\PhpWord\Style\Tab(); $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_CENTER); - $tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight); + $tabWriter = new RTF\Style\Tab($tabRight); $tabWriter->setParentWriter(new RTF()); $result = $tabWriter->write(); @@ -113,7 +114,7 @@ public function testDecimalTab(): void $tabRight = new \PhpOffice\PhpWord\Style\Tab(); $tabRight->setType(\PhpOffice\PhpWord\Style\Tab::TAB_STOP_DECIMAL); - $tabWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Tab($tabRight); + $tabWriter = new RTF\Style\Tab($tabRight); $tabWriter->setParentWriter(new RTF()); $result = $tabWriter->write(); @@ -124,7 +125,7 @@ public function testRTL(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('אב גד', ['RTL' => true]); - $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $text = new RTF\Element\Text($parentWriter, $element); $expect = "\\pard\\nowidctlpar {\\rtlch\\cf0\\f0 \\uc0{\\u1488}\\uc0{\\u1489} \\uc0{\\u1490}\\uc0{\\u1491}}\\par\n"; self::assertEquals($expect, $this->removeCr($text)); } @@ -134,7 +135,7 @@ public function testRTL2(): void Settings::setDefaultRtl(true); $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('אב גד'); - $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $text = new RTF\Element\Text($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\qr{\\rtlch\\cf0\\f0 \\uc0{\\u1488}\\uc0{\\u1489} \\uc0{\\u1490}\\uc0{\\u1491}}\\par\n"; self::assertEquals($expect, $this->removeCr($text)); } @@ -143,7 +144,7 @@ public function testPageBreakLineHeight(): void { $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('New page', null, ['lineHeight' => 1.08, 'pageBreakBefore' => true]); - $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $text = new RTF\Element\Text($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\sl259\\slmult1\\page{\\cf0\\f0 New page}\\par\n"; self::assertEquals($expect, $this->removeCr($text)); } @@ -153,7 +154,7 @@ public function testPageBreakLineHeight2(): void Settings::setDefaultRtl(false); $parentWriter = new RTF(); $element = new \PhpOffice\PhpWord\Element\Text('New page', null, ['lineHeight' => 1.08, 'pageBreakBefore' => true]); - $text = new \PhpOffice\PhpWord\Writer\RTF\Element\Text($parentWriter, $element); + $text = new RTF\Element\Text($parentWriter, $element); $expect = "\\pard\\nowidctlpar \\ql\\sl259\\slmult1\\page{\\cf0\\f0 New page}\\par\n"; self::assertEquals($expect, $this->removeCr($text)); } @@ -163,7 +164,7 @@ public function testPageNumberRestart(): void //$parentWriter = new RTF(); $phpword = new \PhpOffice\PhpWord\PhpWord(); $section = $phpword->addSection(['pageNumberingStart' => 5]); - $styleWriter = new \PhpOffice\PhpWord\Writer\RTF\Style\Section($section->getStyle()); + $styleWriter = new RTF\Style\Section($section->getStyle()); $wstyle = $this->removeCr($styleWriter); // following have default values which might change so don't use them $wstyle = preg_replace('/\\\\pgwsxn\\d+/', '', $wstyle); diff --git a/tests/PhpWordTests/Writer/RTFTest.php b/tests/PhpWordTests/Writer/RTFTest.php index c56bc9f3dc..4f9f8944ac 100644 --- a/tests/PhpWordTests/Writer/RTFTest.php +++ b/tests/PhpWordTests/Writer/RTFTest.php @@ -1,4 +1,5 @@ getElement('/w:document/w:body/w:p/w:r[2]/w:t')->nodeValue); self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r[2]/w:rPr/w:b')); } + + /** + * Test Ruby writing. + */ + public function testRubyWriting(): void + { + $phpWord = new PhpWord(); + + $section = $phpWord->addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(18); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + $section->addRuby($baseTextRun, $rubyTextRun, $properties); + + $doc = TestHelperDOCX::getDocument($phpWord); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby')); + // check props + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr')); + self::assertEquals( + RubyProperties::ALIGNMENT_RIGHT_VERTICAL, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign', 'w:val') + ); + self::assertEquals( + 10, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps', 'w:val') + ); + self::assertEquals( + 4, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsRaise', 'w:val') + ); + self::assertEquals( + 18, + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText', 'w:val') + ); + self::assertEquals( + 'ja-JP', + $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid', 'w:val') + ); + // check ruby text + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')); + self::assertEquals( + 'わたし', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')->nodeValue + ); + // check base text + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')); + self::assertEquals( + '私', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')->nodeValue + ); + } + + /** + * Test Ruby title writing. + */ + public function testRubyTitleWriting(): void + { + $phpWord = new PhpWord(); + $phpWord->addTitleStyle(1, ['name' => 'Arial', 'size' => 24, 'bold' => true, 'color' => '990000']); + + $section = $phpWord->addSection(); + $properties = new RubyProperties(); + $properties->setAlignment(RubyProperties::ALIGNMENT_RIGHT_VERTICAL); + $properties->setFontFaceSize(10); + $properties->setFontPointsAboveBaseText(4); + $properties->setFontSizeForBaseText(18); + $properties->setLanguageId('ja-JP'); + + $baseTextRun = new TextRun(null); + $baseTextRun->addText('私'); + $rubyTextRun = new TextRun(null); + $rubyTextRun->addText('わたし'); + + $textRun = new TextRun(); + $textRun->addRuby($baseTextRun, $rubyTextRun, $properties); + $section->addTitle($textRun, 1); + + $doc = TestHelperDOCX::getDocument($phpWord); + // make sure style made it in + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:pPr/w:pStyle')); + self::assertEquals( + 'Heading1', + $doc->getElement('/w:document/w:body/w:p/w:pPr/w:pStyle')->getAttribute('w:val') + ); + // check ruby props + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby')); + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr')); + self::assertEquals( + RubyProperties::ALIGNMENT_RIGHT_VERTICAL, + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:rubyAlign')->getAttribute('w:val') + ); + self::assertEquals( + 10, + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hps')->getAttribute('w:val') + ); + self::assertEquals( + 4, + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsRaise')->getAttribute('w:val') + ); + self::assertEquals( + 18, + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:hpsBaseText')->getAttribute('w:val') + ); + self::assertEquals( + 'ja-JP', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyPr/w:lid')->getAttribute('w:val') + ); + // check ruby text + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')); + self::assertEquals( + 'わたし', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rt/w:r/w:t')->nodeValue + ); + // check base text + self::assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')); + self::assertEquals( + '私', + $doc->getElement('/w:document/w:body/w:p/w:r/w:ruby/w:rubyBase/w:r/w:t')->nodeValue + ); + } } diff --git a/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php index 6e376f3e82..04cdb5ff52 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/AbstractPartTest.php @@ -1,4 +1,5 @@ getMockForAbstractClass(\PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart::class); + $object = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); $object->setParentWriter(new Word2007()); self::assertEquals(new Word2007(), $object->getParentWriter()); } @@ -43,7 +44,7 @@ public function testSetGetParentWriterNull(): void { $this->expectException(Exception::class); $this->expectExceptionMessage('No parent WriterInterface assigned.'); - $object = $this->getMockForAbstractClass(\PhpOffice\PhpWord\Writer\Word2007\Part\AbstractPart::class); + $object = $this->getMockForAbstractClass(Word2007\Part\AbstractPart::class); $object->getParentWriter(); } } diff --git a/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php b/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php index 383203636b..8f8c8240a9 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/CommentsTest.php @@ -1,4 +1,5 @@ elementExists("{$parent}/w:i")); self::assertEquals($styles['underline'], $doc->getElementAttribute("{$parent}/w:u", 'w:val')); self::assertTrue($doc->elementExists("{$parent}/w:strike")); + self::assertFalse($doc->elementExists("{$parent}/w:dstrike")); self::assertEquals('superscript', $doc->getElementAttribute("{$parent}/w:vertAlign", 'w:val')); self::assertEquals($styles['color'], $doc->getElementAttribute("{$parent}/w:color", 'w:val')); self::assertEquals($styles['fgColor'], $doc->getElementAttribute("{$parent}/w:highlight", 'w:val')); self::assertTrue($doc->elementExists("{$parent}/w:smallCaps")); } + /** + * covers ::_writeTextStyle. + * + * @dataProvider providerFontStyleStrikethrough + */ + public function testWriteFontStyleStrikethrough( + bool $isStrikethrough, + bool $isDoubleStrikethrough, + bool $expectedStrikethrough, + bool $expectedDoubleStrikethrough + ): void { + $phpWord = new PhpWord(); + $styles['strikethrough'] = $isStrikethrough; + $styles['doublestrikethrough'] = $isDoubleStrikethrough; + + $section = $phpWord->addSection(); + $section->addText('Test', $styles); + $doc = TestHelperDOCX::getDocument($phpWord); + + $parent = '/w:document/w:body/w:p/w:r/w:rPr'; + self::assertSame($expectedStrikethrough, $doc->elementExists("{$parent}/w:strike")); + self::assertSame($expectedDoubleStrikethrough, $doc->elementExists("{$parent}/w:dstrike")); + } + + public static function providerFontStyleStrikethrough(): iterable + { + return [ + [true, true, false, true], + [true, false, true, false], + [false, true, false, true], + [false, false, false, false], + ]; + } + /** * Tests that if no color is set on a cell a border gets writen with the default color. */ diff --git a/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php b/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php index 0dc99e7e37..beb6e971e2 100644 --- a/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Part/FooterTest.php @@ -1,4 +1,5 @@ getElement($path, $file); self::assertEquals('Generation', $element->getAttribute('w:val')); } + + /** + * Test default font color. + */ + public function testDefaultDefaultFontColor(): void + { + $phpWord = new PhpWord(); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/styles.xml'; + + $path = '/w:styles/w:docDefaults/w:rPrDefault/w:rPr/w:color'; + self::assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + self::assertEquals('000000', $element->getAttribute('w:val')); + } + + /** + * Test default font color. + */ + public function testDefaultFontColor(): void + { + $phpWord = new PhpWord(); + $defaultFontColor = '00FF00'; + $phpWord->setDefaultFontColor($defaultFontColor); + + $doc = TestHelperDOCX::getDocument($phpWord); + + $file = 'word/styles.xml'; + + $path = '/w:styles/w:docDefaults/w:rPrDefault/w:rPr/w:color'; + self::assertTrue($doc->elementExists($path, $file)); + $element = $doc->getElement($path, $file); + + self::assertEquals($defaultFontColor, $element->getAttribute('w:val')); + } } diff --git a/tests/PhpWordTests/Writer/Word2007/PartTest.php b/tests/PhpWordTests/Writer/Word2007/PartTest.php index a3bc47b4c9..be69e587e3 100644 --- a/tests/PhpWordTests/Writer/Word2007/PartTest.php +++ b/tests/PhpWordTests/Writer/Word2007/PartTest.php @@ -1,4 +1,5 @@ addSection(); $textrun = $section->addTextRun(); $textrun->addText('سلام این یک پاراگراف راست به چپ است', ['rtl' => true, 'lang' => 'ar-DZ']); @@ -56,7 +57,7 @@ public function testFontRTL(): void public function testFontRTLNamed(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $stnam = 'fstyle'; $phpWord->addFontStyle($stnam, [ 'rtl' => true, @@ -81,7 +82,7 @@ public function testFontRTLNamed(): void public function testFontNotRTLNamed(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $stnam = 'fstyle'; $phpWord->addFontStyle($stnam, [ //'rtl' => true, @@ -106,7 +107,7 @@ public function testFontNotRTLNamed(): void public function testNoProof(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $fontStyle = [ 'noProof' => true, 'name' => 'Courier New', @@ -133,7 +134,7 @@ public function testNoProof(): void */ public function testFontWithLang(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('Ce texte-ci est en français.', ['lang' => \PhpOffice\PhpWord\Style\Language::FR_BE]); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); @@ -148,7 +149,7 @@ public function testFontWithLang(): void */ public function testPosition(): void { - $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $phpWord = new PhpWord(); $section = $phpWord->addSection(); $section->addText('This text is lowered', ['position' => -20]); $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); diff --git a/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php b/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php index 53ecba2dd9..2b5c25e01f 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/ImageTest.php @@ -1,4 +1,5 @@ addSection(); diff --git a/tests/PhpWordTests/Writer/Word2007/Style/TableCellTest.php b/tests/PhpWordTests/Writer/Word2007/Style/TableCellTest.php new file mode 100644 index 0000000000..bd3f587b75 --- /dev/null +++ b/tests/PhpWordTests/Writer/Word2007/Style/TableCellTest.php @@ -0,0 +1,86 @@ +addSection(); + $table = $section->addTable(); + $table->addRow(); + + $testValTop = Converter::pixelToTwip(10); + $testValRight = Converter::pixelToTwip(11); + $testValBottom = Converter::pixelToTwip(12); + $testValLeft = Converter::pixelToTwip(13); + + $cellStyle = [ + 'paddingTop' => $testValTop, + 'paddingRight' => $testValRight, + 'paddingBottom' => $testValBottom, + 'paddingLeft' => $testValLeft, + ]; + $table->addCell(null, $cellStyle)->addText('Some text'); + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:top'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValTop, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:start'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValLeft, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:bottom'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValBottom, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + + $path = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcMar/w:end'; + self::assertTrue($doc->elementExists($path)); + self::assertEquals($testValRight, $doc->getElementAttribute($path, 'w:w')); + self::assertEquals(TblWidth::TWIP, $doc->getElementAttribute($path, 'w:type')); + } +} diff --git a/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php b/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php index b072bb8ab2..b10d836568 100644 --- a/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php +++ b/tests/PhpWordTests/Writer/Word2007/Style/TableTest.php @@ -1,4 +1,5 @@ getElement($path, $file)->getAttribute($attribute); } + /** + * Return if element attribute exists. + */ + public function hasElementAttribute(string $path, string $attribute, string $file = ''): bool + { + return $this->getElement($path, $file)->hasAttribute($attribute); + } + /** * Check if element exists. */ diff --git a/tests/PhpWordTests/_files/documents/docChinese.doc b/tests/PhpWordTests/_files/documents/docChinese.doc new file mode 100644 index 0000000000..db245953e5 Binary files /dev/null and b/tests/PhpWordTests/_files/documents/docChinese.doc differ diff --git a/tests/PhpWordTests/_files/documents/docCzech.doc b/tests/PhpWordTests/_files/documents/docCzech.doc new file mode 100644 index 0000000000..8def81b13e Binary files /dev/null and b/tests/PhpWordTests/_files/documents/docCzech.doc differ diff --git a/tests/PhpWordTests/_files/documents/docSlovak.doc b/tests/PhpWordTests/_files/documents/docSlovak.doc new file mode 100644 index 0000000000..dede581e55 Binary files /dev/null and b/tests/PhpWordTests/_files/documents/docSlovak.doc differ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 845e59db70..7c4e0a3e1b 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,4 +1,5 @@