mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-17 06:18:44 +02:00
Merge remote-tracking branch 'origin/support/3.2' into develop
# Conflicts: # .doc/README.md # .doc/phpdoc-templates/combodo-wiki/graphs/class.html.twig # composer.lock # lib/composer/InstalledVersions.php # lib/composer/autoload_classmap.php # lib/composer/autoload_psr4.php # lib/composer/autoload_static.php # lib/composer/installed.json # lib/composer/installed.php # lib/symfony/cache/Traits/Relay/MoveTrait.php # lib/symfony/http-foundation/Request.php # lib/symfony/runtime/SymfonyRuntime.php
This commit is contained in:
101
.doc/README.md
101
.doc/README.md
@@ -1,101 +0,0 @@
|
||||
# Phpdoc dokuwiki template
|
||||
This directory contains a template for rendering iTop phpdoc as dokuwiki pages.
|
||||
|
||||
|
||||
Conventional tags that you should use:
|
||||
* `@internal` : exclude from the documentation.
|
||||
* `@api` : it means that a method is an api, thus it may be interacted with.
|
||||
* `@see` : it points to another documented method
|
||||
* `@link` : external url
|
||||
* if you point to another page of the wiki, please use relative links.
|
||||
* `@example` : let you provide example of code
|
||||
* `@param`, `@return`, `@throws`, ...
|
||||
|
||||
|
||||
## Special instructions
|
||||
|
||||
Some iTop specific tags were added :
|
||||
* `@api-advanced`: it means that a method is an `@api` but mark it also as "complex" to use
|
||||
* `@overwritable-hook`: used to mark a method as "designed to be extended"
|
||||
* `@extension-hook`: not used for now
|
||||
* `@phpdoc-tuning-exclude-inherited`: once this tag is present on a class, it's inherited methods won't be showed.
|
||||
|
||||
|
||||
### known limitations:
|
||||
#### `@see` tags must be very specific:
|
||||
* always prefix class members (attributes or methods) with `ClassName::` (do not use self)
|
||||
* for methods always suffix them with `()`,
|
||||
* do not reference variables since they are not documented. If you have to, always prefix them with `$`
|
||||
|
||||
examples:
|
||||
```
|
||||
/**
|
||||
* @see DBObject
|
||||
* @see DBObject::Get()
|
||||
* @see DBObject::$foo
|
||||
*/
|
||||
```
|
||||
|
||||
#### Do not use inline tags, they do not work properly, example:
|
||||
```
|
||||
/**
|
||||
* This is a texts with an inline tag {@see [FQSEN] [<description>]} it must never be used
|
||||
*/
|
||||
```
|
||||
|
||||
#### The `@example` tag must respect this very precise syntax
|
||||
* the sentence in the first line (next to the tag) is the title, it must be enclosed by double quotes
|
||||
* the following lines are the sample code.
|
||||
* 💔 since we simply hack the official tag, this syntax must be respected carefully 💔
|
||||
example:
|
||||
```
|
||||
/**
|
||||
* @example "This is the title of the multiline example"
|
||||
* $foo = DBObject::Get('foo');
|
||||
* DBObject::Set('foo', ++$foo);
|
||||
*/
|
||||
```
|
||||
|
||||
## How content is included into the documentation
|
||||
|
||||
**For a class** those requirements have to be respected:
|
||||
- the file containing the class must be listed in `/phpdoc/files/file[]` of `.doc/phpdoc-objects-manipulation.dist.xml`
|
||||
- the class **must not** have the tag `@internal`
|
||||
- the class **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
|
||||
|
||||
Then, **for a method** of an eligible class:
|
||||
- **public** methods **must** have at least one of: `@api`, `@api-advanced`, `@overwritable-hook`, `@extension-hook`
|
||||
- **protected** methods **must** have at least one of: `@overwritable-hook`, `@extension-hook`
|
||||
- **private** methods are **always excluded**
|
||||
|
||||
**Class properties** and **constants** are never documented (this is subject to change).
|
||||
|
||||
|
||||
|
||||
|
||||
## A note about the rendering engine
|
||||
|
||||
:notebook: as spaces are used to mark code, the templates (`.doc/phpdoc-templates/combodo-wiki/*`) have very few indentation, thus they are awful to read (sorry).
|
||||
|
||||
## Installation
|
||||
|
||||
Note : PHP7 is required. Migrating to PHP8 requires some additional work which is questionable as an alternative way to generate a documentation is being considered.
|
||||
|
||||
```
|
||||
cd .doc
|
||||
composer require phpdocumentor/phpdocumentor:~2 --dev
|
||||
```
|
||||
|
||||
## Generation
|
||||
|
||||
1. Switch to this directory : `cd /path/to/itop/.doc`
|
||||
2. `composer install`
|
||||
3. `./bin/build-doc-object-manipulation`
|
||||
3. `./bin/build-doc-extensions`
|
||||
4. Get the generated files from `/path/to/itop/data/phpdocumentor/output`
|
||||
|
||||
## Dokuwiki requirements
|
||||
* the template uses the [wrap plugin](https://www.dokuwiki.org/plugin:wrap).
|
||||
* the generated files have to be placed under an arbitrary directory of `[/path/to/dokuwiki]/data/pages`.
|
||||
* the html has to be activated [config:htmlok](https://www.dokuwiki.org/config:htmlok)
|
||||
* the generated files have to be in lowercase
|
||||
@@ -1,6 +0,0 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf data/phpdocumentor/output/extensions/ && rm -rf data/phpdocumentor/temp/extensions/ && ./vendor/bin/phpdoc -c ./phpdoc-extensions.dist.xml -vvv
|
||||
|
||||
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
|
||||
cd ../data/phpdocumentor/output/extensions/ && for i in $(ls | grep [A-Z]); do mv -i $i $(echo $i | tr 'A-Z' 'a-z'); done
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/bin/sh -x
|
||||
|
||||
rm -rf /tmp/phpdoc-twig-cache/ && rm -rf ../data/phpdocumentor/output/objects-manipulation/ && rm -rf ../data/phpdocumentor/temp/objects-manipulation/ && ./vendor/bin/phpdoc -c ./phpdoc-objects-manipulation.dist.xml -vvv
|
||||
|
||||
|
||||
# now wee need to lowercase every generated file because dokuwiki can't handle uppercase
|
||||
cd ../data/phpdocumentor/output/objects-manipulation/ && for i in $( ls | grep [A-Z] ); do mv -i $i `echo $i | tr 'A-Z' 'a-z'`; done
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"require-dev": {
|
||||
"phpdocumentor/phpdocumentor": "~2",
|
||||
"jms/serializer": "1.7.*"
|
||||
}
|
||||
}
|
||||
3015
.doc/composer.lock
generated
3015
.doc/composer.lock
generated
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 983 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.8 MiB |
@@ -1,104 +0,0 @@
|
||||
# iTop version history
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'themeVariables': {
|
||||
'git0': 'lawngreen',
|
||||
'git3': 'dodgerblue',
|
||||
'git4': 'grey',
|
||||
'git5': 'grey',
|
||||
'git6': 'grey',
|
||||
'git7': 'grey'
|
||||
}, 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
|
||||
gitGraph
|
||||
commit id: "2016-07-06" tag: "2.3.0" type: HIGHLIGHT
|
||||
branch support/2.3 order: 900
|
||||
commit id: "2016-07-08" tag: "2.3.1"
|
||||
commit id: "2016-12-22" tag: "2.3.3"
|
||||
commit id: "2017-04-14" tag: "2.3.4"
|
||||
checkout develop
|
||||
commit id: "2017-07-12" tag: "2.4.0-beta" type: REVERSE
|
||||
commit id: "2017-11-16" tag: "2.4.0" type: HIGHLIGHT
|
||||
branch support/2.4 order: 890
|
||||
commit id: "2018-02-14" tag: "2.4.1"
|
||||
checkout develop
|
||||
commit id: "2018-04-25" tag: "2.5.0-beta" type: REVERSE
|
||||
checkout support/2.4
|
||||
commit id: "2018-06-14" tag: "2.4.2"
|
||||
checkout develop
|
||||
commit id: "2018-06-27" tag: "2.5.0" type: HIGHLIGHT
|
||||
branch support/2.5 order: 880
|
||||
checkout develop
|
||||
commit id: "2019-01-09" tag: "2.6.0" type: HIGHLIGHT
|
||||
branch support/2.6 order: 870
|
||||
commit id: "2019-03-28" tag: "2.6.1"
|
||||
checkout develop
|
||||
commit id: "2019-12-18" tag: "2.7.0-beta" type: REVERSE
|
||||
checkout support/2.5
|
||||
commit id: "2020-01-22" tag: "2.5.4"
|
||||
checkout support/2.6
|
||||
commit id: "2020-01-23" tag: "2.6.3"
|
||||
checkout develop
|
||||
commit id: "2020-01-29" tag: "2.7.0-beta2" type: REVERSE
|
||||
commit id: "2020-04-01" tag: "2.7.0-1" type: HIGHLIGHT
|
||||
checkout support/2.6
|
||||
commit id: "2020-04-22" tag: "2.6.4"
|
||||
checkout develop
|
||||
branch support/2.7 order: 860
|
||||
commit id: "2020-06-26" tag: "2.7.1"
|
||||
checkout support/2.7
|
||||
commit id: "2020-12-09" tag: "2.7.3"
|
||||
commit id: "2021-03-31" tag: "2.7.4"
|
||||
checkout develop
|
||||
commit id: "2021-04-06" tag: "3.0.0-beta" type: REVERSE
|
||||
checkout support/2.7
|
||||
commit id: "2021-07-05" tag: "2.7.5"
|
||||
checkout develop
|
||||
commit id: "2021-07-05." tag: "3.0.0-beta2" type: REVERSE
|
||||
checkout support/2.7
|
||||
commit id: "2021-12-17" tag: "2.7.6"
|
||||
checkout develop
|
||||
commit id: "2022-01-04" tag: "3.0.0" type: HIGHLIGHT
|
||||
branch support/3.0 order: 850
|
||||
commit id: "2022-04-08" tag: "3.0.1"
|
||||
checkout support/2.7
|
||||
commit id: "2022-07-11" tag: "2.7.7"
|
||||
checkout support/3.0
|
||||
commit id: "2022-09-12" tag: "3.0.2-1"
|
||||
checkout develop
|
||||
checkout support/2.7
|
||||
commit id: "2022-12-28" tag: "2.7.8"
|
||||
checkout support/3.0
|
||||
commit id: "2023-04-12" tag: "3.0.3"
|
||||
checkout develop
|
||||
commit id: "2023-06-19" tag: "3.1.0-beta" type: REVERSE
|
||||
commit id: "2023-07-26" tag: "3.1.0-1" type: HIGHLIGHT
|
||||
branch support/3.1 order: 840
|
||||
checkout support/3.1
|
||||
commit id: "2023-08-09" tag: "3.1.0-2"
|
||||
checkout support/2.7
|
||||
commit id: "2023-08-10" tag: "2.7.9"
|
||||
checkout support/3.1
|
||||
commit id: "2023-12-20" tag: "3.1.1"
|
||||
checkout develop
|
||||
commit id: "2024-01-15" tag: "Start 3.2" type: HIGHLIGHT
|
||||
branch support/3.2 order: 830
|
||||
checkout support/2.7
|
||||
commit id: "2024-01-17a" tag: "2.7.10"
|
||||
checkout support/3.0
|
||||
commit id: "2024-01-17b" tag: "3.0.4"
|
||||
checkout support/2.7
|
||||
commit id: "2024-09-28" tag: "2.7.11"
|
||||
checkout support/3.1
|
||||
commit id: "2024-09-27" tag: "3.1.2"
|
||||
checkout support/3.2
|
||||
commit id: "2024-06-25" tag: "3.2.0-beta1" type: REVERSE
|
||||
commit id: "2024-08-07" tag: "3.2.0"
|
||||
checkout support/2.7
|
||||
commit id: "2025-02-25" tag: "2.7.12"
|
||||
checkout support/3.1
|
||||
commit id: "2025-02-25 " tag: "3.1.3"
|
||||
checkout support/3.2
|
||||
commit id: "2025-02-25 " tag: "3.2.1"
|
||||
```
|
||||
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpdoc>
|
||||
<title><![CDATA[iTop extensions]]></title>
|
||||
|
||||
<parser>
|
||||
<target>../data/phpdocumentor/temp/extensions</target>
|
||||
</parser>
|
||||
|
||||
<transformer>
|
||||
<target>../data/phpdocumentor/output/extensions</target>
|
||||
</transformer>
|
||||
|
||||
<transformations>
|
||||
<template name="phpdoc-templates/combodo-wiki"/>
|
||||
</transformations>
|
||||
|
||||
<files>
|
||||
<file>../application/applicationextension.inc.php</file>
|
||||
</files>
|
||||
</phpdoc>
|
||||
@@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<phpdoc>
|
||||
|
||||
<!--
|
||||
/**
|
||||
The documentation of this file can be found here : https://docs.phpdoc.org/references/configuration.html
|
||||
it has to be completed by the CLI parameters documentation which is more comprehensive: https://docs.phpdoc.org/references/commands/project_run.html#usage
|
||||
|
||||
usage:
|
||||
vendor/bin/phpdoc -c phpdoc-objects-manipulation.dist.xml
|
||||
|
||||
*/
|
||||
-->
|
||||
|
||||
<title><![CDATA[iTop's objects manipulation API]]></title>
|
||||
|
||||
<parser>
|
||||
<default-package-name>iTopORM</default-package-name>
|
||||
<target>../data/phpdocumentor/temp/objects-manipulation</target>
|
||||
<visibility>public,protected</visibility>
|
||||
<markers>
|
||||
<!--<item>TODO</item>-->
|
||||
<!--<item>FIXME</item>-->
|
||||
</markers>
|
||||
<extensions>
|
||||
<extension>php</extension>
|
||||
</extensions>
|
||||
</parser>
|
||||
|
||||
<transformer>
|
||||
<target>../data/phpdocumentor/output/objects-manipulation</target>
|
||||
</transformer>
|
||||
|
||||
<transformations>
|
||||
<template name="phpdoc-templates/combodo-wiki"/>
|
||||
</transformations>
|
||||
|
||||
<!--<logging>-->
|
||||
<!--<level>warn</level>-->
|
||||
<!--<paths>-->
|
||||
<!--<!–<default>data/phpdocumentor/log/objects-manipulation/{DATE}.log</default>–>-->
|
||||
<!--<!–<errors>data/phpdocumentor/log/objects-manipulation/{DATE}.errors.log</errors>–>-->
|
||||
|
||||
<!--<default>{APP_ROOT}/data/log/{DATE}.log</default>-->
|
||||
<!--<errors>{APP_ROOT}/data/log/{DATE}.errors.log</errors>-->
|
||||
<!--</paths>-->
|
||||
<!--</logging>-->
|
||||
|
||||
<files>
|
||||
<file>../core/dbobject.class.php</file>
|
||||
<file>../core/dbobjectsearch.class.php</file>
|
||||
<file>../core/metamodel.class.php</file>
|
||||
<file>../core/dbobjectset.class.php</file>
|
||||
<file>../core/dbsearch.class.php</file>
|
||||
<file>../core/dbunionsearch.class.php</file>
|
||||
</files>
|
||||
|
||||
</phpdoc>
|
||||
@@ -1,136 +0,0 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
|
||||
{% if node.tags['internal'] is defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This class is "internal", and thus is not documented!</WRAP>
|
||||
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This class is neither "api", "api-advanced", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
|
||||
{% else %}
|
||||
|
||||
====== {{ node.name }} ======
|
||||
|
||||
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
|
||||
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
|
||||
{% if node.final %}<wrap notice>final</wrap>{% endif %}
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
|
||||
|
||||
|
||||
{% if node.deprecated %}
|
||||
=== **<del>Deprecated</del>**===
|
||||
//{{ node.tags.deprecated[0].description }}//
|
||||
{% endif %}
|
||||
|
||||
|
||||
== {{ node.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ node.description|markdown|raw }}</html>
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
|
||||
|
||||
|
||||
{% set class = node.parent %}
|
||||
{% block hierarchy_element %}
|
||||
|
||||
{% if class and class.name is defined and class.name|trim != '' %}
|
||||
==== parent ====
|
||||
{% set child = class %}
|
||||
{% set class = class.parent %}
|
||||
{{ block('hierarchy_element') }}
|
||||
[[{{ child.name }}|{{ child.name }}]]
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% for interface in node.interfaces|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Implements ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% for trait in node.usedTraits|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Uses traits ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
|
||||
|
||||
{% set methods = node.inheritedMethods.merge(node.methods.merge(node.magicMethods)) %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '=====', sub_title_level: '=='} %}
|
||||
|
||||
<WRAP clear />
|
||||
|
||||
{% for method in methods|sort_asc
|
||||
if method.visibility == 'public'
|
||||
and (
|
||||
method.tags['api'] is defined
|
||||
or method.tags['api-advanced'] is defined
|
||||
or method.tags['overwritable-hook'] is defined
|
||||
or method.tags['extension-hook'] is defined
|
||||
)
|
||||
and (
|
||||
node.tags['phpdoc-tuning-exclude-inherited'] is not defined
|
||||
or method.parent.name == node.name
|
||||
)
|
||||
%}
|
||||
{%- if loop.first %}
|
||||
===== Public methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
{% for method in methods|sort_asc if method.visibility == 'protected' and (method.tags['overwritable-hook'] is defined or method.tags['extension-hook'] is defined) %}
|
||||
{%- if loop.first %}
|
||||
===== Protected methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{% set constants = node.inheritedConstants.merge(node.constants) %}
|
||||
{% if constants|length > 0 %}
|
||||
===== Constants =====
|
||||
{% for constant in constants|sort_asc %}
|
||||
{{ block('constant') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{#{% set properties = node.inheritedProperties.merge(node.properties.merge(node.magicProperties)) %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Public properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Protected properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
|
||||
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
|
||||
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
{% endblock %}
|
||||
@@ -1,31 +0,0 @@
|
||||
{% block constant %}
|
||||
|
||||
<WRAP group box >
|
||||
<WRAP twothirds column >
|
||||
==== {{ constant.name }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column>
|
||||
{% if constant.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
|
||||
{% if (node.parent is not null and constant.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
== {{ constant.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ constant.description|markdown|raw }}</html>
|
||||
|
||||
{% if constant.deprecated %}
|
||||
=== Deprecated ===
|
||||
{{ constant.tags.deprecated[0].description|raw }}
|
||||
{% endif %}
|
||||
|
||||
{% include 'includes/inherited-from.txt.twig' with {structure:constant} %}
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:constant, title_level: '=='} %}
|
||||
|
||||
{% include 'includes/uses.txt.twig' with {structure:constant, title_level: '=='} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:constant, title_level: '==', blacklist: ['link', 'see', 'var', 'deprecated', 'uses', 'package', 'subpackage', 'todo', 'code-example']} %}
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,95 +0,0 @@
|
||||
{% block method %}
|
||||
|
||||
|
||||
<WRAP group box >
|
||||
<WRAP twothirds column >
|
||||
==== {{ method.name }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
<WRAP third column >
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:method, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
{% if method.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
|
||||
{% if (node.parent is not null and method.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
{% if method.abstract %}<wrap warning>abstract</wrap> {% endif %}
|
||||
{% if method.final %}<wrap notice>final</wrap> {% endif %}
|
||||
<wrap notice>{{ method.visibility }}</wrap>
|
||||
{% if method.static %}<wrap warning>static</wrap> {% endif %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
== {{ method.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ method.description|markdown|raw }}</html>
|
||||
|
||||
<code php>{% if method.abstract %}abstract {% endif %}{% if method.final %}final {% endif %}{{ method.visibility }} {% if method.static %}static {% endif %}{{ method.name }}({% for argument in method.arguments %}{{ argument.isVariadic ? '...' }}{{ argument.name }}{{ argument.default ? (' = '~argument.default)|raw }}{% if not loop.last %}, {% endif %}{% endfor %})</code>
|
||||
|
||||
<WRAP twothirds column >
|
||||
|
||||
|
||||
=== Parameters ===
|
||||
{% if method.arguments|length > 0 -%}
|
||||
^ types ^ name ^ default ^ description ^
|
||||
{% for argument in method.arguments -%}
|
||||
| **<nowiki>{{ argument.types|join('|')|raw }}</nowiki>** | {{ argument.name }} {{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }} | <nowiki>{{ argument.default|raw }}</nowiki> | {{ argument.description|trim|replace("\n", ' ')|raw }} |{{ "\r\n" }}
|
||||
{%- endfor %}
|
||||
{% else %}
|
||||
//none//
|
||||
{% endif %}
|
||||
|
||||
|
||||
{#=== Parameters ===#}
|
||||
{#{% if method.arguments|length > 0 -%}#}
|
||||
{#{% for argument in method.arguments -%}#}
|
||||
{#== {{ argument.name }} ==#}
|
||||
|
||||
|
||||
{#{% set varDesc %}#}
|
||||
{#<span style="margin:0 10px; 0 20px; font-weight: bold;">{{ argument.types|join('|') }}</span>#}
|
||||
{#{{ argument.isVariadic ? '<small style="color: gray">variadic</small>' }}#}
|
||||
{#{{ argument.description|raw }}#}
|
||||
{#{% endset %}#}
|
||||
{#<html>{{ varDesc|markdown|raw }}</html>#}
|
||||
{#{%- endfor %}#}
|
||||
{#{% else %}#}
|
||||
{#<wrap tip>This method has no parameter</wrap>#}
|
||||
{#{% endif %}#}
|
||||
|
||||
|
||||
{% if method.response and method.response.types|join() != 'void' %}
|
||||
=== Returns ===
|
||||
<html>{{ ('**' ~ method.response.types|join('|')|trim ~ '** ' ~ method.response.description)|markdown|raw }}</html>
|
||||
{% endif %}
|
||||
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column >
|
||||
|
||||
{% if method.tags.throws|length > 0 or method.tags.throw|length > 0 %}
|
||||
=== Throws ===
|
||||
{% for exception in method.tags.throws -%}
|
||||
{% if loop.length > 1 %} * {% endif %}''{{ exception.types|join('|')|raw }}'' <nowiki>{{ exception.description|raw }}</nowiki>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% include 'includes/inherited-from.txt.twig' with {structure:method} %}
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/uses.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/used-by.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/tags-with-description.txt.twig' with {structure:method, title_level: '===', WRAP: 'info', tagsWithDescription: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:method, title_level: '===', blacklist: ['todo', 'link', 'see', 'abstract', 'example', 'param', 'return', 'access', 'deprecated', 'throws', 'throw', 'uses', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'used-by', 'inheritdoc', 'code-example']} %}
|
||||
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:method, title_level: '==='} %}
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,49 +0,0 @@
|
||||
{% block property %}
|
||||
|
||||
<WRAP group box>
|
||||
<WRAP twothirds column >
|
||||
==== ${{ property.name }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column>
|
||||
{% if property.deprecated %}<wrap danger>deprecated</wrap> {% endif %}
|
||||
{% if (node.parent is not null and property.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
|
||||
|
||||
== {{ property.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ property.description|markdown|raw }}</html>
|
||||
{% if property.var.0.description %}<html>{{ property.var.0.description|markdown|raw }}</html>{% endif %}
|
||||
|
||||
|
||||
|
||||
{#{% if property.types %}#}
|
||||
{#== Type ==#}
|
||||
{#{% for type in property.types %}#}
|
||||
{#{% if loop.length > 1 %} * {% endif %}{{ type|raw }} : {{ type.description|raw }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{{ property.types|join('|')|raw }}#}
|
||||
{#{% endif %}#}
|
||||
|
||||
|
||||
{% if property.deprecated %}
|
||||
== Deprecated ==
|
||||
{{ property.tags.deprecated[0].description }}
|
||||
{% endif %}
|
||||
|
||||
{% include 'includes/inherited-from.txt.twig' with {structure:property} %}
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:property, title_level: '=='} %}
|
||||
|
||||
{% include 'includes/uses.txt.twig' with {structure:property, title_level: ''} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:property, title_level: '==', blacklist: ['link', 'see', 'access', 'var', 'deprecated', 'uses', 'todo', 'code-example']} %}
|
||||
|
||||
|
||||
<code php>{{ property.visibility }} ${{ property.name }}{% if property.types %} : {{ property.types|join('|')|raw }}{% endif %}</code>
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endblock %}
|
||||
@@ -1 +0,0 @@
|
||||
{{ node.source|raw }}
|
||||
@@ -1,122 +0,0 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block javascripts %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{#<section class="row-fluid">#}
|
||||
{#<div class="span2 sidebar">#}
|
||||
{#{% set namespace = project.namespace %}#}
|
||||
{#{{ block('sidebarNamespaces') }}#}
|
||||
{#</div>#}
|
||||
{#</section>#}
|
||||
{#<section class="row-fluid">#}
|
||||
====== {{ node.path|split('/')|slice(0,-1)|join('/') }}{{ node.name }} ======
|
||||
{{ node.summary }}
|
||||
<html>{{ node.description|markdown|raw }}</html>
|
||||
|
||||
{% if node.traits|length > 0 %}
|
||||
|
||||
===== Traits =====
|
||||
{% for trait in node.traits %}
|
||||
<tr>
|
||||
<td>{{ trait|raw }}</td>
|
||||
<td><em>{{ trait.summary }}</em></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if node.interfaces|length > 0 %}
|
||||
===== Interfaces =====
|
||||
{% for interface in node.interfaces %}
|
||||
<tr>
|
||||
<td>{{ interface|raw }}</td>
|
||||
<td><em>{{ interface.summary }}</em></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if node.classes|length > 0 %}
|
||||
===== Classes =====
|
||||
{% for class in node.classes %}
|
||||
{{ class|raw }}
|
||||
<em>{{ class.summary }}</em>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if node.package is not empty and node.package != '\\' %}
|
||||
===== Package =====
|
||||
{{ node.subpackage ? (node.package ~ '\\' ~ node.subpackage) : node.package }}
|
||||
{% endif %}
|
||||
|
||||
{% for tagName,tags in node.tags if tagName in ['link', 'see'] %}
|
||||
{% if loop.first %}
|
||||
===== See also =====
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
<dd><a href="{{ tag.reference ?: tag.link }}"><div class="namespace-wrapper">{{ tag.description ?: tag.reference }}</div></a></dd>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
<h2>Tags</h2>
|
||||
<table class="table table-condensed">
|
||||
{% for tagName,tags in node.tags if tagName not in ['link', 'see', 'package', 'subpackage'] %}
|
||||
<tr>
|
||||
<th>
|
||||
{{ tagName }}
|
||||
</th>
|
||||
<td>
|
||||
{% for tag in tags %}
|
||||
{{ tag.description|markdown|raw }}
|
||||
{% endfor %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr><td colspan="2"><em>None found</em></td></tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
{% if node.constants|length > 0 %}
|
||||
<div class="row-fluid">
|
||||
<section class="span8 content file">
|
||||
<h2>Constants</h2>
|
||||
</section>
|
||||
<aside class="span4 detailsbar"></aside>
|
||||
</div>
|
||||
|
||||
{% for constant in node.constants %}
|
||||
{{ block('constant') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if node.functions|length > 0 %}
|
||||
<div class="row-fluid">
|
||||
<section class="span8 content file">
|
||||
<h2>Functions</h2>
|
||||
</section>
|
||||
<aside class="span4 detailsbar"></aside>
|
||||
</div>
|
||||
|
||||
{% for method in node.functions %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="source-view" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="source-view-label" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="source-view-label">{{ node.file.name }}</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<pre data-src="{{ path('files/' ~ node.path ~ '.txt')|raw }}" class="language-php line-numbers"></pre>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,42 +0,0 @@
|
||||
{% extends 'layout.html.twig' %}
|
||||
|
||||
{% block stylesheets %}
|
||||
<link href="{{ path('css/jquery.iviewer.css') }}" rel="stylesheet" media="all"/>
|
||||
<style>
|
||||
#viewer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.wrapper {
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascripts %}
|
||||
<script src="{{ path('js/jquery.mousewheel.js') }}" type="text/javascript"></script>
|
||||
<script src="{{ path('js/jquery.iviewer.js') }}" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
$(window).resize(function(){
|
||||
$("#viewer").height($(window).height() - 100);
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
$("#viewer").iviewer({src: '{{ path('graphs/classes.svg') }}', zoom_animation: false});
|
||||
$('#viewer img').on('dragstart', function(event){
|
||||
event.preventDefault();
|
||||
});
|
||||
$(window).resize();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div class="wrapper">
|
||||
<div id="viewer" class="viewer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,5 +0,0 @@
|
||||
# Fixes a vulnerability in CentOS: http://stackoverflow.com/questions/20533279/prevent-php-from-parsing-non-php-files-such-as-somefile-php-txt
|
||||
<FilesMatch \.php\.txt$>
|
||||
RemoveHandler .php
|
||||
ForceType text/plain
|
||||
</FilesMatch>
|
||||
@@ -1,34 +0,0 @@
|
||||
{% if title_level is not defined %}
|
||||
{%- set title_level = '==' -%}
|
||||
{% endif %}
|
||||
|
||||
{% if sub_title_level is not defined %}
|
||||
{%- set sub_title_level = title_level|slice(1) -%}
|
||||
{% endif %}
|
||||
{% if sub_title_level == '=' %}
|
||||
{%- set sub_title_level = '' -%}
|
||||
{% endif %}
|
||||
|
||||
{#{% for tagName,tags in structure.tags if tagName in ['code-example'] %}#}
|
||||
{#{% if loop.first %}#}
|
||||
{#{{title_level}} Examples {{title_level}}#}
|
||||
{#{% endif %}#}
|
||||
{#{% for tag in tags %}#}
|
||||
{#{%- set descToken = tag.description|split("\n", 2) -%}#}
|
||||
{#{%- set title = descToken[0] -%}#}
|
||||
{#{%- set code = descToken[1] -%}#}
|
||||
{#{{sub_title_level}} {{ title }} {{sub_title_level}}#}
|
||||
{#<code php>{{ code|raw }}</code>#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
|
||||
{% for tagName,tags in structure.tags if tagName in ['example'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} Examples {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{{ sub_title_level }} {{ tag.filePath|escape }}{{ sub_title_level }}
|
||||
<code php>{{ tag.description|raw }}</code>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
@@ -1,12 +0,0 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='' %}
|
||||
{% endif %}
|
||||
|
||||
{% if (node.parent is null) %}
|
||||
{{title_level}} File {{ structure.path }} {{title_level}}
|
||||
{% endif %}
|
||||
|
||||
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}
|
||||
{{title_level}} Inherited from {{title_level}}
|
||||
[[{{structure.parent}}|{{structure.parent}}]]
|
||||
{% endif %}
|
||||
@@ -1,26 +0,0 @@
|
||||
{% for structure in structures|sort_asc if structure.tags['internal'] is not defined and (structure.tags['api'] is defined or structure.tags['api-advanced'] is defined or structure.tags['overwritable-hook'] is defined or structure.tags['extension-hook'] is defined ) %}
|
||||
{#{{ structure|raw }}#}
|
||||
|
||||
{% set structureName = structure|trim('\\', 'left') %}
|
||||
|
||||
<WRAP group box>
|
||||
<WRAP twothirds column >
|
||||
==== {{ structureName }} ====
|
||||
</WRAP>{# twothirds column#}
|
||||
|
||||
<WRAP third column>
|
||||
{% if structure.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
|
||||
{% if structure.abstract %}<wrap warning>abstract</wrap>{% endif %}
|
||||
{% if structure.final %}<wrap notice>final</wrap>{% endif %}
|
||||
{% if (node.parent is not null and structure.parent.fullyQualifiedStructuralElementName != node.fullyQualifiedStructuralElementName) %}<wrap notice>inherited</wrap> {% endif %}
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:structure, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
|
||||
{{ structure.summary|raw }}
|
||||
[[{{structureName}}|More information]]
|
||||
|
||||
</WRAP>{# group #}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
{% if title_level is not defined %}
|
||||
{%- set title_level='==' -%}
|
||||
{% endif %}
|
||||
{% for tagName,tags in structure.tags if tagName in ['link', 'see'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} See also {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{%- set linkTag = tag.reference|trim('\\', 'left') -%}
|
||||
{% if not('()' in linkTag or '$' in linkTag or node.name in linkTag or '::' in linkTag ) %}
|
||||
{%- set linkTag = linkTag|lower -%}
|
||||
{% elseif node.name~'::' in linkTag %}
|
||||
{%- set linkTag = linkTag|replace({(node.name~'::'): '#'})|lower -%}
|
||||
{% elseif '::' in linkTag -%}
|
||||
{%- set linkTag = linkTag|replace({'::': '#'})|lower -%}
|
||||
{% else %}
|
||||
{%- set linkTag = '#' ~ linkTag|lower -%}
|
||||
{%- endif %}
|
||||
|
||||
{% if loop.length > 1 %} * {% endif %}{% if tag.reference is not empty -%}
|
||||
[[{{linkTag}}|{{ (tag.reference)|trim('\\', 'left') }}]] {% if tag.description|trim is not empty %}: {{ tag.description|trim('\\', 'left') }} {% endif %}
|
||||
{%- else -%}
|
||||
{#{{ tag.description|trim('\\', 'left') }}#}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
@@ -1,56 +0,0 @@
|
||||
{% if tag is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set tag = "api" -%}
|
||||
{%- endif %}
|
||||
|
||||
{% if hidden_by is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set hidden_by = {"api" : "api-advanced"} -%}
|
||||
{%- endif %}
|
||||
|
||||
|
||||
|
||||
{% for method in methods|sort_asc
|
||||
if (method.visibility == 'public')
|
||||
and (
|
||||
method.tags[tag] is defined
|
||||
and (
|
||||
hidden_by[tag] is not defined or method.tags[hidden_by[tag]] is not defined
|
||||
)
|
||||
)
|
||||
%}
|
||||
{%- if loop.first %}
|
||||
{% if tag == 'api' %}
|
||||
===== API synthesis =====
|
||||
<WRAP>
|
||||
List of the public API methods.
|
||||
When manipulating {{ node.name }}, You can call those methods:
|
||||
</WRAP>
|
||||
{% elseif tag == 'api-advanced' %}
|
||||
===== Advanced API synthesis =====
|
||||
<WRAP>
|
||||
List of advanced API methods
|
||||
Beware they usage is recommended to advanced users only.
|
||||
</WRAP>
|
||||
{% elseif tag == 'overwritable-hook' %}
|
||||
===== overwritable-hook synthesis =====
|
||||
<WRAP >When inheriting from {{ node.name }},
|
||||
you can overwrite those methods in order to add custom logic:
|
||||
</WRAP>
|
||||
{% elseif tag == 'extension-hook' %}
|
||||
===== extension-hook synthesis =====
|
||||
<WRAP >
|
||||
When inheriting from {{ node.name }},
|
||||
you can extend the behaviour of iTop by implementing:
|
||||
</WRAP>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% set sanitizedMethod = method|trim('\\', 'left')|replace({(node.name~'::'): ''}) %}
|
||||
{% if '::' in sanitizedMethod -%}
|
||||
{%- if node.tags['phpdoc-tuning-exclude-inherited'] is not defined %}
|
||||
* [[{{sanitizedMethod|replace({'::': '#'})|lower}}|↪{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
|
||||
{% endif %}
|
||||
{%- else %}
|
||||
* [[#{{sanitizedMethod}}|{{sanitizedMethod}}]] — {{ method.summary|replace({"\n":""})|raw }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -1,20 +0,0 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level = '==' %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{%- for tagName,tags in structure.tags if tagName in tagsWithDescription -%}
|
||||
{%- for tag in tags -%}
|
||||
{%- if tag.description is not empty -%}
|
||||
{%- if WRAP is defined -%}
|
||||
<WRAP {{WRAP}}>
|
||||
{%- endif -%}
|
||||
{{title_level}} {{ tagName }} {{title_level}}
|
||||
{{ tag.description|escape }}
|
||||
{%- if WRAP is defined -%}
|
||||
</WRAP>
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endfor -%}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='=====' %}
|
||||
{% endif %}
|
||||
|
||||
{% if blacklist is not defined %}
|
||||
{% set blacklist =['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'api', 'api-advanced', 'todo', 'code-example'] %}
|
||||
{% endif %}
|
||||
{% if hidden_by is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set hidden_by = {"api" : "api-advanced"} -%}
|
||||
{%- endif %}
|
||||
|
||||
{#^ {% for tagName,tags in structure.tags if tagName not in blacklist -%}#}
|
||||
{#{{ tagName }} ^#}
|
||||
{#{%- endfor %}#}
|
||||
|
||||
{% for tagName,tags in structure.tags if tagName not in blacklist and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
|
||||
{%- if loop.first %}
|
||||
{{title_level}} Tags {{title_level}}
|
||||
{% endif %}
|
||||
^ {{ tagName }} | {% for tag in tags %}{{ tag.version ? tag.version ~ ' ' : '' }}{{ tag.description}}{% endfor %} |
|
||||
{% endfor %}
|
||||
@@ -1,24 +0,0 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='' %}
|
||||
{% endif %}
|
||||
{% for tagName,tags in structure.tags if tagName in ['used-by'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} Used by {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
|
||||
{#{% if loop.first %}#}
|
||||
{#<dt>Uses</dt>#}
|
||||
{#{% endif %}#}
|
||||
{#{% for tag in tags %}#}
|
||||
{#<dd>{{ tag.reference|raw }}</dd>#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endfor %}#}
|
||||
@@ -1,24 +0,0 @@
|
||||
{% if title_level is not defined %}
|
||||
{% set title_level='' %}
|
||||
{% endif %}
|
||||
{% for tagName,tags in structure.tags if tagName in ['uses'] %}
|
||||
{% if loop.first %}
|
||||
{{title_level}} Uses {{title_level}}
|
||||
{% endif %}
|
||||
{% for tag in tags %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ tag.reference ?: tag.link }} : {{ tag.description ?: tag.reference }}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{#{% for tagName,tags in method.tags if tagName in ['uses'] %}#}
|
||||
{#{% if loop.first %}#}
|
||||
{#<dt>Uses</dt>#}
|
||||
{#{% endif %}#}
|
||||
{#{% for tag in tags %}#}
|
||||
{#<dd>{{ tag.reference|raw }}</dd>#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endfor %}#}
|
||||
@@ -1,11 +0,0 @@
|
||||
{% if wrap is not defined -%}
|
||||
{% set wrap = 'notice' %}
|
||||
{%- endif -%}
|
||||
{% if hidden_by is not defined -%}
|
||||
{# Do not display @api if @api-advanced is also present #}
|
||||
{%- set hidden_by = {"api" : "api-advanced"} -%}
|
||||
{%- endif %}
|
||||
|
||||
{%- for tagName,tags in structure.tags if tagName in wrapTags and (hidden_by[tagName] is not defined or structure.tags[hidden_by[tagName]] is not defined) %}
|
||||
<wrap {{wrap}}>{{tagName}}</wrap>
|
||||
{% endfor %}
|
||||
@@ -1,121 +0,0 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block content %}
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
|
||||
{% if node.tags['internal'] is defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This interface is "internal", and thus is not documented!</WRAP>
|
||||
{% elseif node.tags['api'] is not defined and node.tags['api-advanced'] is not defined and node.tags['overwritable-hook'] is not defined and node.tags['extension-hook'] is not defined %}
|
||||
====== {{ node.name }} ======
|
||||
<WRAP alert>This interface is neither "api", "overwritable-hook" or "extension-hook", and thus is not documented!</WRAP>
|
||||
{% else %}
|
||||
|
||||
====== {{ node.name }} ======
|
||||
|
||||
{% if node.deprecated %}<wrap danger>deprecated</wrap>{% endif %}
|
||||
{% if node.abstract %}<wrap warning>abstract</wrap>{% endif %}
|
||||
{% if node.final %}<wrap notice>final</wrap>{% endif %}
|
||||
{% include 'includes/wrap-tags.txt.twig' with {structure:node, wrap: 'safety', wrapTags: ['api', 'api-advanced', 'overwritable-hook', 'extension-hook']} %}
|
||||
|
||||
|
||||
|
||||
{% if node.deprecated %}
|
||||
=== **<del>Deprecated</del>**===
|
||||
//{{ node.tags.deprecated[0].description }}//
|
||||
{% endif %}
|
||||
|
||||
|
||||
== {{ node.summary|replace({"\n":""})|raw }} ==
|
||||
<html>{{ node.description|markdown|raw }}</html>
|
||||
|
||||
|
||||
{% include 'includes/code-examples.txt.twig' with {structure:node, title_level: '====='} %}
|
||||
|
||||
|
||||
{% set class = node.parent %}
|
||||
{% block hierarchy_element %}
|
||||
|
||||
{% if class and class.name is defined and class.name|trim != '' %}
|
||||
==== parent ====
|
||||
{% set child = class %}
|
||||
{% set class = class.parent %}
|
||||
{{ block('hierarchy_element') }}
|
||||
[[{{ child.name }}|{{ child.name }}]]
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% for interface in node.interfaces|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Implements ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ interface.fullyQualifiedStructuralElementName ?: interface }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% for trait in node.usedTraits|sort_asc %}
|
||||
{% if loop.first %}
|
||||
==== Uses traits ====
|
||||
{% endif %}
|
||||
{% if loop.length > 1 %} * {% endif %}{{ trait.fullyQualifiedStructuralElementName ?: trait }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
{% include 'includes/see-also.txt.twig' with {structure:node, title_level: '==='} %}
|
||||
|
||||
{% include 'includes/tags.txt.twig' with {structure:node, title_level: '=====', blacklist: ['link', 'see', 'abstract', 'example', 'method', 'property', 'property-read', 'property-write', 'package', 'subpackage', 'phpdoc-tuning-exclude-inherited', 'api', 'api-advanced', 'overwritable-hook', 'extension-hook', 'copyright', 'license', 'code-example']} %}
|
||||
|
||||
|
||||
{% set methods = node.inheritedMethods.merge(node.methods) %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'api-advanced'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'overwritable-hook'} %}
|
||||
{% include 'includes/tag-synthesys.txt.twig' with {methods:methods, tag:'extension-hook'} %}
|
||||
|
||||
<WRAP clear />
|
||||
|
||||
|
||||
{% for method in methods|sort_asc if method.visibility == 'public' %}
|
||||
{%- if loop.first %}
|
||||
===== Public methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
{% for method in methods|sort_asc if method.visibility == 'protected' %}
|
||||
{%- if loop.first %}
|
||||
===== Protected methods =====
|
||||
{% endif %}
|
||||
{{ block('method') }}
|
||||
{% endfor %}
|
||||
|
||||
|
||||
|
||||
{% set constants = node.inheritedConstants.merge(node.constants) %}
|
||||
{% if constants|length > 0 %}
|
||||
===== Constants =====
|
||||
{% for constant in constants|sort_asc %}
|
||||
{{ block('constant') }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{#{% set properties = node.inheritedProperties.merge(node.properties) %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'public' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Public properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% for property in properties|sort_asc if property.visibility == 'protected' %}#}
|
||||
{#{%- if loop.first %}#}
|
||||
{#===== Protected properties =====#}
|
||||
{#{% endif %}#}
|
||||
{#{{ block('property') }}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
|
||||
{%- endif %} {#{% elseif node.tags['xxx'] is not defined and ... #}
|
||||
|
||||
<wrap button>[[start|🔙 Back]]</wrap>
|
||||
{% endblock %}
|
||||
@@ -1,5 +0,0 @@
|
||||
{% use 'elements/constant.txt.twig' %}
|
||||
{% use 'elements/property.txt.twig' %}
|
||||
{% use 'elements/method.txt.twig' %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
@@ -1,51 +0,0 @@
|
||||
{% extends 'layout.txt.twig' %}
|
||||
|
||||
{% block content %}
|
||||
{% set namespace = project.namespace %}
|
||||
{{ block('sidebarNamespaces') }}
|
||||
|
||||
{#{{ node.parent|raw }}#}
|
||||
{#====== {{ node.parent.fullyQualifiedStructuralElementName }}{{ node.name }} ======#}
|
||||
|
||||
{% if node.children|length > 0 %}
|
||||
=====Namespaces=====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.children} %}
|
||||
----
|
||||
{% endif %}
|
||||
|
||||
{% if node.traits|length > 0 %}
|
||||
===== Traits =====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.traits} %}
|
||||
----
|
||||
{%- endif %}
|
||||
|
||||
{% if node.interfaces|length > 0 %}
|
||||
===== Interfaces =====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.interfaces} %}
|
||||
----
|
||||
{% endif %}
|
||||
|
||||
{% if node.classes|length > 0 %}
|
||||
===== Classes =====
|
||||
{% include 'includes/namespace-structure-toc.html.twig' with {structures: node.classes} %}
|
||||
----
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
{#{% if node.constants|length > 0 %}#}
|
||||
{#===== Constants =====#}
|
||||
{#{% for constant in node.constants|sort_asc %}#}
|
||||
{# {{ block('constant') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endif %}#}
|
||||
|
||||
{#{% if node.functions|length > 0 %}#}
|
||||
{#===== Functions =====#}
|
||||
|
||||
{#{% for method in node.functions|sort_asc %}#}
|
||||
{# {{ block('method') }}#}
|
||||
{#{% endfor %}#}
|
||||
{#{% endif %}#}
|
||||
|
||||
{% endblock %}
|
||||
@@ -1,49 +0,0 @@
|
||||
|
||||
====== Deprecated elements ======
|
||||
|
||||
{#{% for element in project.indexes.elements if element.deprecated %}#}
|
||||
{#{% if element.file.path != previousPath %}#}
|
||||
{#<li><a href="#{{ element.file.path }}"><i class="icon-file"></i> {{ element.file.path }}</a></li>#}
|
||||
{#{% endif %}#}
|
||||
{#{% set previousPath = element.file.path %}#}
|
||||
{#{% endfor %}#}
|
||||
|
||||
{% for element in project.indexes.elements if element.deprecated %}
|
||||
{% if element.file.path != previousPath %}
|
||||
{% if previousPath %}
|
||||
</WRAP>{# group #}
|
||||
{% endif %}
|
||||
{#<a name="{{ element.file.path }}" id="{{ element.file.path }}"></a>#}
|
||||
===== {{ element.file.path }} ({{ element.tags.deprecated.count }} found)=====
|
||||
|
||||
<WRAP group >
|
||||
<WRAP third column >
|
||||
Element
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
Line
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
Description
|
||||
</WRAP>{# third column#}
|
||||
|
||||
{% endif %}
|
||||
{% for tag in element.tags.deprecated %}
|
||||
<WRAP group >
|
||||
<WRAP third column >
|
||||
{{ element.fullyQualifiedStructuralElementName }}
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
{{ element.line }}
|
||||
</WRAP>{# third column#}
|
||||
<WRAP third column >
|
||||
{{ tag.description }}
|
||||
</WRAP>{# third column#}
|
||||
|
||||
{% endfor %}
|
||||
</WRAP>{# group #}
|
||||
{% set previousPath = element.file.path %}
|
||||
{% else %}
|
||||
<WRAP info>No deprecated elements have been found in this project.</WRAP>
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<template>
|
||||
<author>Bruno DA SILVA</author>
|
||||
<email>contact [at] combodo.com</email>
|
||||
<version>1.0.0</version>
|
||||
<copyright>Combodo 2018</copyright>
|
||||
<description><![CDATA[
|
||||
|
||||
Forked from the clean theme of https://github.com/phpDocumentor/phpDocumentor2 provided under the MIT licence.
|
||||
The original work is copyright "Mike van Riel".
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
To improve performance you can add the following to your .htaccess:
|
||||
|
||||
<ifModule mod_deflate.c>
|
||||
<filesMatch "\.(js|css|html)$">
|
||||
SetOutputFilter DEFLATE
|
||||
</filesMatch>
|
||||
</ifModule>
|
||||
]]></description>
|
||||
<transformations>
|
||||
<transformation writer="twig" query="namespace" source="templates/combodo-wiki/namespace.txt.twig" artifact="start.txt"/>
|
||||
<transformation writer="twig" query="indexes.classes" source="templates/combodo-wiki/class.txt.twig" artifact="{{name}}.txt"/>
|
||||
<transformation writer="twig" query="indexes.interfaces" source="templates/combodo-wiki/interface.txt.twig" artifact="{{name}}.txt" />
|
||||
</transformations>
|
||||
</template>
|
||||
@@ -22,6 +22,7 @@ use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSet;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Spinner\SpinnerUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock;
|
||||
use Combodo\iTop\Application\UI\Base\UIBlock;
|
||||
@@ -409,6 +410,9 @@ JS
|
||||
|
||||
$sEnvironment = addslashes(utils::GetCurrentEnvironment());
|
||||
|
||||
$oModalSpinner = SpinnerUIBlockFactory::MakeMedium(null, $sPleaseWaitBackup);
|
||||
$sModalSpinnerHtml = BlockRenderer::RenderBlockTemplates($oModalSpinner);
|
||||
|
||||
$oP->add_script(
|
||||
<<<JS
|
||||
function LaunchBackupNow()
|
||||
@@ -420,7 +424,7 @@ function LaunchBackupNow()
|
||||
{
|
||||
const oModal = CombodoModal.OpenModal({
|
||||
title: '$sBackUpNow',
|
||||
content: '<i class="ajax-spin fas fa-sync-alt fa-spin"></i> $sPleaseWaitBackup'
|
||||
content: `$sModalSpinnerHtml`
|
||||
});
|
||||
|
||||
var oParams = {};
|
||||
|
||||
@@ -22,7 +22,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:KnownError/Attribute:problem_id+' => '',
|
||||
'Class:KnownError/Attribute:problem_ref' => 'Rérérence problème lié',
|
||||
'Class:KnownError/Attribute:problem_ref+' => '',
|
||||
'Class:KnownError/Attribute:symptom' => 'Symptome',
|
||||
'Class:KnownError/Attribute:symptom' => 'Symptôme',
|
||||
'Class:KnownError/Attribute:symptom+' => '',
|
||||
'Class:KnownError/Attribute:root_cause' => 'Cause première',
|
||||
'Class:KnownError/Attribute:root_cause+' => '',
|
||||
|
||||
@@ -122,6 +122,9 @@ $(function()
|
||||
_create: function () {
|
||||
this.element.addClass('ibo-activity-panel');
|
||||
|
||||
// Should be initialized globally, but as we don't actually do it
|
||||
moment.locale(GetUserLanguage());
|
||||
|
||||
this._bindEvents();
|
||||
|
||||
// Lock
|
||||
|
||||
@@ -14,10 +14,7 @@ if (PHP_VERSION_ID < 50600) {
|
||||
echo $err;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
$err,
|
||||
E_USER_ERROR
|
||||
);
|
||||
throw new RuntimeException($err);
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
@@ -11,7 +11,6 @@ return array(
|
||||
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
|
||||
'662a729f963d39afe703c9d9b7ab4a8c' => $vendorDir . '/symfony/polyfill-php83/bootstrap.php',
|
||||
'667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php',
|
||||
'23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php',
|
||||
'89efb1254ef2d1c5d80096acd12c4098' => $vendorDir . '/twig/twig/src/Resources/core.php',
|
||||
'ffecb95d45175fd40f75be8a23b34f90' => $vendorDir . '/twig/twig/src/Resources/debug.php',
|
||||
'c7baa00073ee9c61edf148c51917cfb4' => $vendorDir . '/twig/twig/src/Resources/escaper.php',
|
||||
|
||||
@@ -36,8 +36,7 @@ if ($issues) {
|
||||
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
|
||||
}
|
||||
}
|
||||
trigger_error(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues),
|
||||
E_USER_ERROR
|
||||
throw new \RuntimeException(
|
||||
'Composer detected issues in your platform: ' . implode(' ', $issues)
|
||||
);
|
||||
}
|
||||
|
||||
132
lib/symfony/cache/Traits/Relay/FtTrait.php
vendored
Normal file
132
lib/symfony/cache/Traits/Relay/FtTrait.php
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Traits\Relay;
|
||||
|
||||
if (version_compare(phpversion('relay'), '0.9.0', '>=')) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait FtTrait
|
||||
{
|
||||
public function ftAggregate($index, $query, $options = null): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAggregate(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftAliasAdd($index, $alias): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAliasAdd(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftAliasDel($alias): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAliasDel(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftAliasUpdate($index, $alias): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAliasUpdate(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftAlter($index, $schema, $skipinitialscan = false): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftAlter(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftConfig($operation, $option, $value = null): \Relay\Relay|array|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftConfig(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftCreate($index, $schema, $options = null): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftCreate(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftCursor($operation, $index, $cursor, $options = null): \Relay\Relay|array|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftCursor(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftDictAdd($dict, $term, ...$other_terms): \Relay\Relay|false|int
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftDictAdd(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftDictDel($dict, $term, ...$other_terms): \Relay\Relay|false|int
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftDictDel(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftDictDump($dict): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftDictDump(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftDropIndex($index, $dd = false): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftDropIndex(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftExplain($index, $query, $dialect = 0): \Relay\Relay|false|string
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftExplain(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftExplainCli($index, $query, $dialect = 0): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftExplainCli(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftInfo($index): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftInfo(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftProfile($index, $command, $query, $limited = false): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftProfile(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftSearch($index, $query, $options = null): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftSearch(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftSpellCheck($index, $query, $options = null): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftSpellCheck(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftSynDump($index): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftSynDump(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftSynUpdate($index, $synonym, $term_or_terms, $skipinitialscan = false): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftSynUpdate(...\func_get_args());
|
||||
}
|
||||
|
||||
public function ftTagVals($index, $tag): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->ftTagVals(...\func_get_args());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait FtTrait
|
||||
{
|
||||
}
|
||||
}
|
||||
32
lib/symfony/cache/Traits/Relay/GetWithMetaTrait.php
vendored
Normal file
32
lib/symfony/cache/Traits/Relay/GetWithMetaTrait.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Traits\Relay;
|
||||
|
||||
if (version_compare(phpversion('relay'), '0.10.1', '>=')) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait GetWithMetaTrait
|
||||
{
|
||||
public function getWithMeta($key): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->getWithMeta(...\func_get_args());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait GetWithMetaTrait
|
||||
{
|
||||
}
|
||||
}
|
||||
32
lib/symfony/cache/Traits/Relay/IsTrackedTrait.php
vendored
Normal file
32
lib/symfony/cache/Traits/Relay/IsTrackedTrait.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Traits\Relay;
|
||||
|
||||
if (version_compare(phpversion('relay'), '0.11.1', '>=')) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait IsTrackedTrait
|
||||
{
|
||||
public function isTracked($key): bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->isTracked(...\func_get_args());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait IsTrackedTrait
|
||||
{
|
||||
}
|
||||
}
|
||||
132
lib/symfony/cache/Traits/Relay/Relay11Trait.php
vendored
Normal file
132
lib/symfony/cache/Traits/Relay/Relay11Trait.php
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Traits\Relay;
|
||||
|
||||
if (version_compare(phpversion('relay'), '0.11.0', '>=')) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait Relay11Trait
|
||||
{
|
||||
public function cmsIncrBy($key, $field, $value, ...$fields_and_falues): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsIncrBy(...\func_get_args());
|
||||
}
|
||||
|
||||
public function cmsInfo($key): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsInfo(...\func_get_args());
|
||||
}
|
||||
|
||||
public function cmsInitByDim($key, $width, $depth): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsInitByDim(...\func_get_args());
|
||||
}
|
||||
|
||||
public function cmsInitByProb($key, $error, $probability): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsInitByProb(...\func_get_args());
|
||||
}
|
||||
|
||||
public function cmsMerge($dstkey, $keys, $weights = []): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsMerge(...\func_get_args());
|
||||
}
|
||||
|
||||
public function cmsQuery($key, ...$fields): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->cmsQuery(...\func_get_args());
|
||||
}
|
||||
|
||||
public function commandlog($subcmd, ...$args): \Relay\Relay|array|bool|int
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->commandlog(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hexpire($hash, $ttl, $fields, $mode = null): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpire(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hexpireat($hash, $ttl, $fields, $mode = null): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpireat(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hexpiretime($hash, $fields): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hexpiretime(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hgetdel($key, $fields): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetdel(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hgetex($hash, $fields, $expiry = null): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hgetex(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hpersist($hash, $fields): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpersist(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hpexpire($hash, $ttl, $fields, $mode = null): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpire(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hpexpireat($hash, $ttl, $fields, $mode = null): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpireat(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hpexpiretime($hash, $fields): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpexpiretime(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hpttl($hash, $fields): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hpttl(...\func_get_args());
|
||||
}
|
||||
|
||||
public function hsetex($key, $fields, $expiry = null): \Relay\Relay|false|int
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hsetex(...\func_get_args());
|
||||
}
|
||||
|
||||
public function httl($hash, $fields): \Relay\Relay|array|false
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->httl(...\func_get_args());
|
||||
}
|
||||
|
||||
public function serverName(): false|string
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->serverName(...\func_get_args());
|
||||
}
|
||||
|
||||
public function serverVersion(): false|string
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->serverVersion(...\func_get_args());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait Relay11Trait
|
||||
{
|
||||
}
|
||||
}
|
||||
32
lib/symfony/cache/Traits/Relay/SwapdbTrait.php
vendored
Normal file
32
lib/symfony/cache/Traits/Relay/SwapdbTrait.php
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\Cache\Traits\Relay;
|
||||
|
||||
if (version_compare(phpversion('relay'), '0.9.0', '>=')) {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait SwapdbTrait
|
||||
{
|
||||
public function swapdb($index1, $index2): \Relay\Relay|bool
|
||||
{
|
||||
return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->swapdb(...\func_get_args());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
trait SwapdbTrait
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
Copyright (c) 2021-present Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Polyfill\Php81;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class Php81
|
||||
{
|
||||
public static function array_is_list(array $array): bool
|
||||
{
|
||||
if ([] === $array || $array === array_values($array)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$nextKey = -1;
|
||||
|
||||
foreach ($array as $k => $v) {
|
||||
if ($k !== ++$nextKey) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
Symfony Polyfill / Php81
|
||||
========================
|
||||
|
||||
This component provides features added to PHP 8.1 core:
|
||||
|
||||
- [`array_is_list`](https://php.net/array_is_list)
|
||||
- [`enum_exists`](https://php.net/enum-exists)
|
||||
- [`MYSQLI_REFRESH_REPLICA`](https://php.net/mysqli.constants#constantmysqli-refresh-replica) constant
|
||||
- [`ReturnTypeWillChange`](https://wiki.php.net/rfc/internal_method_return_types)
|
||||
- [`CURLStringFile`](https://php.net/CURLStringFile) (but only if PHP >= 7.4 is used)
|
||||
|
||||
More information can be found in the
|
||||
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
This library is released under the [MIT license](LICENSE).
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
if (\PHP_VERSION_ID >= 70400 && extension_loaded('curl')) {
|
||||
/**
|
||||
* @property string $data
|
||||
*/
|
||||
class CURLStringFile extends CURLFile
|
||||
{
|
||||
private $data;
|
||||
|
||||
public function __construct(string $data, string $postname, string $mime = 'application/octet-stream')
|
||||
{
|
||||
$this->data = $data;
|
||||
parent::__construct('data://application/octet-stream;base64,'.base64_encode($data), $mime, $postname);
|
||||
}
|
||||
|
||||
public function __set(string $name, $value): void
|
||||
{
|
||||
if ('data' !== $name) {
|
||||
$this->$name = $value;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_object($value) ? !method_exists($value, '__toString') : !is_scalar($value)) {
|
||||
throw new TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string');
|
||||
}
|
||||
|
||||
$this->name = 'data://application/octet-stream;base64,'.base64_encode($value);
|
||||
}
|
||||
|
||||
public function __isset(string $name): bool
|
||||
{
|
||||
return isset($this->$name);
|
||||
}
|
||||
|
||||
public function &__get(string $name)
|
||||
{
|
||||
return $this->$name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
if (\PHP_VERSION_ID < 80100) {
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
final class ReturnTypeWillChange
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Symfony\Polyfill\Php81 as p;
|
||||
|
||||
if (\PHP_VERSION_ID >= 80100) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (defined('MYSQLI_REFRESH_SLAVE') && !defined('MYSQLI_REFRESH_REPLICA')) {
|
||||
define('MYSQLI_REFRESH_REPLICA', 64);
|
||||
}
|
||||
|
||||
if (!function_exists('array_is_list')) {
|
||||
function array_is_list(array $array): bool { return p\Php81::array_is_list($array); }
|
||||
}
|
||||
|
||||
if (!function_exists('enum_exists')) {
|
||||
function enum_exists(string $enum, bool $autoload = true): bool { return $autoload && class_exists($enum) && false; }
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"name": "symfony/polyfill-php81",
|
||||
"type": "library",
|
||||
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
|
||||
"keywords": ["polyfill", "shim", "compatibility", "portable"],
|
||||
"homepage": "https://symfony.com",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Nicolas Grekas",
|
||||
"email": "p@tchwork.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": { "Symfony\\Polyfill\\Php81\\": "" },
|
||||
"files": [ "bootstrap.php" ],
|
||||
"classmap": [ "Resources/stubs" ]
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"extra": {
|
||||
"thanks": {
|
||||
"name": "symfony/polyfill",
|
||||
"url": "https://github.com/symfony/polyfill"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,14 +125,14 @@ class GenericRuntime implements RuntimeInterface
|
||||
}
|
||||
|
||||
if (!\is_callable($application)) {
|
||||
throw new \LogicException(sprintf('"%s" doesn\'t know how to handle apps of type "%s".', get_debug_type($this), get_debug_type($application)));
|
||||
throw new \LogicException(\sprintf('"%s" doesn\'t know how to handle apps of type "%s".', get_debug_type($this), get_debug_type($application)));
|
||||
}
|
||||
|
||||
$application = $application(...);
|
||||
}
|
||||
|
||||
if ($_SERVER[$this->options['debug_var_name']] && ($r = new \ReflectionFunction($application)) && $r->getNumberOfRequiredParameters()) {
|
||||
throw new \ArgumentCountError(sprintf('Zero argument should be required by the runner callable, but at least one is in "%s" on line "%d.', $r->getFileName(), $r->getStartLine()));
|
||||
throw new \ArgumentCountError(\sprintf('Zero argument should be required by the runner callable, but at least one is in "%s" on line "%d.', $r->getFileName(), $r->getStartLine()));
|
||||
}
|
||||
|
||||
return new ClosureRunner($application);
|
||||
@@ -171,7 +171,7 @@ class GenericRuntime implements RuntimeInterface
|
||||
if (!$runtime = $this->getRuntime($type)) {
|
||||
$r = $parameter->getDeclaringFunction();
|
||||
|
||||
throw new \InvalidArgumentException(sprintf('Cannot resolve argument "%s $%s" in "%s" on line "%d": "%s" supports only arguments "array $context", "array $argv" and "array $request", or a runtime named "Symfony\Runtime\%1$sRuntime".', $type, $parameter->name, $r->getFileName(), $r->getStartLine(), get_debug_type($this)));
|
||||
throw new \InvalidArgumentException(\sprintf('Cannot resolve argument "%s $%s" in "%s" on line "%d": "%s" supports only arguments "array $context", "array $argv" and "array $request", or a runtime named "Symfony\Runtime\%1$sRuntime".', $type, $parameter->name, $r->getFileName(), $r->getStartLine(), get_debug_type($this)));
|
||||
}
|
||||
|
||||
return $runtime->getArgument($parameter, $type);
|
||||
|
||||
@@ -70,7 +70,7 @@ class ComposerPlugin implements PluginInterface, EventSubscriberInterface
|
||||
}
|
||||
|
||||
if (!is_file($autoloadTemplate)) {
|
||||
throw new \InvalidArgumentException(sprintf('File "%s" defined under "extra.runtime.autoload_template" in your composer.json file not found.', $this->composer->getPackage()->getExtra()['runtime']['autoload_template']));
|
||||
throw new \InvalidArgumentException(\sprintf('File "%s" defined under "extra.runtime.autoload_template" in your composer.json file not found.', $this->composer->getPackage()->getExtra()['runtime']['autoload_template']));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class DebugClosureResolver extends ClosureResolver
|
||||
|
||||
$r = new \ReflectionFunction($closure);
|
||||
|
||||
throw new \TypeError(sprintf('Unexpected value of type "%s" returned, "object" expected from "%s" on line "%d".', get_debug_type($app), $r->getFileName(), $r->getStartLine()));
|
||||
throw new \TypeError(\sprintf('Unexpected value of type "%s" returned, "object" expected from "%s" on line "%d".', get_debug_type($app), $r->getFileName(), $r->getStartLine()));
|
||||
},
|
||||
$arguments,
|
||||
];
|
||||
|
||||
@@ -36,7 +36,7 @@ class ClosureRunner implements RunnerInterface
|
||||
if (null !== $exitStatus && !\is_int($exitStatus)) {
|
||||
$r = new \ReflectionFunction($this->closure);
|
||||
|
||||
throw new \TypeError(sprintf('Unexpected value of type "%s" returned, "string|int|null" expected from "%s" on line "%d".', get_debug_type($exitStatus), $r->getFileName(), $r->getStartLine()));
|
||||
throw new \TypeError(\sprintf('Unexpected value of type "%s" returned, "string|int|null" expected from "%s" on line "%d".', get_debug_type($exitStatus), $r->getFileName(), $r->getStartLine()));
|
||||
}
|
||||
|
||||
return $exitStatus ?? 0;
|
||||
|
||||
@@ -1,3 +1,67 @@
|
||||
6.10.0 (2025-05-27)
|
||||
- Embedded files support (Factur-X 1.07 / ZUGFeRD 2.3) #789
|
||||
|
||||
6.9.5 (2025-05-27)
|
||||
- Automatically add destinations from HTML code #804
|
||||
- Wrong default value when $table_el['old_cell_padding'] is missing #807
|
||||
- Fixed PHP warning when empty hash link for image exists in HTML #809
|
||||
- Fix for application of alpha component to SVG RGBA fills #810
|
||||
|
||||
6.9.4 (2025-05-13)
|
||||
- Update donation link.
|
||||
|
||||
6.9.3 (2025-04-20)
|
||||
- New fix for "Deserialization of untrusted data" (check on valid protocols).
|
||||
- Removed global phar configuration.
|
||||
|
||||
6.9.2 (2025-04-18)
|
||||
- Quick fix for "Deserialization of untrusted data" security vulnerability reported by Positive Technologies.
|
||||
- Disable phar protocol globally.
|
||||
|
||||
6.9.1 (2025-04-03)
|
||||
- Fixed "Path Traversal" security vulnerability reported by Positive Technologies.
|
||||
|
||||
6.9.0 (2025-03-30)
|
||||
- Added PHP 8.4 testing.
|
||||
- Removed tcpdf_import.php and tcpdf_parser.php files (for a parser check the tc-lib-pdf-parser project instead).
|
||||
- Fix composer.json.
|
||||
|
||||
6.8.2 (2025-01-26)
|
||||
- Fix some annotation flags values.
|
||||
- Remove examples from packaging.
|
||||
|
||||
6.8.1 (2025-01-26) - UNTAGGED
|
||||
- Check relative paths on SVG images.
|
||||
|
||||
6.8.0 (2024-12-23)
|
||||
- Requires PHP 7.1+ and curl extension.
|
||||
- Escape error message.
|
||||
- Use strict time-constant function to compare TCPDF-tag hashes.
|
||||
- Add K_CURLOPTS config array to set custom cURL options (NOTE: some defaults have changed).
|
||||
- Add some addTTFfont fixes from tc-lib-pdf-font.
|
||||
|
||||
6.7.8 (2024-12-13)
|
||||
- Improve SVG detection by checking for (mandatory) namespace.
|
||||
- Use late state binding now that minimum PHP version is 5.5.
|
||||
|
||||
6.7.7 (2024-10-26)
|
||||
- Update regular expression to avoid ReDoS (CVE-2024-22641)
|
||||
- [PHP 8.4] Fix: Curl CURLOPT_BINARYTRANSFER deprecated #675
|
||||
- SVG detection fix for inline data images #646
|
||||
- Fix count svg #647
|
||||
- Since the version 6.7.4, the "0" is considered like empty string and not displayed
|
||||
- Fixed handling of transparency in PDF/A mode in addExtGState method
|
||||
- Encrypt /DA string when document is encrypted
|
||||
- Improve quality of generated seed, avoid potential security pitfall
|
||||
- Try to use random_bytes() first if it's available
|
||||
- Do not include the server parameters in the generated seed, as they might contain sensitive data
|
||||
- Fix bug on _getannotsrefs when there are empty signature appearances but not other annot on a page
|
||||
- Fix SVG coordinate parser that caused drawing artifacts
|
||||
- Remove usage of xml_set_object() function
|
||||
|
||||
6.7.6 (2024-10-06)
|
||||
- Forbid access to parent folder in HTML images.
|
||||
|
||||
6.7.5 (2024-04-20)
|
||||
- Update GitHub actions
|
||||
- fix: CSV-2024-22640 (#712)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
2002-2024 Nicola Asuni - Tecnick.com LTD
|
||||
2002-2025 Nicola Asuni - Tecnick.com LTD
|
||||
|
||||
**********************************************************************
|
||||
**********************************************************************
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# TCPDF
|
||||
*PHP PDF Library*
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20TCPDF%20project)
|
||||
*Please consider supporting this project by making a donation via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations¤cy_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20TCPDF%20project)*
|
||||
[](https://www.paypal.com/donate/?hosted_button_id=NZUEC5XS8MFBJ)
|
||||
*Please consider supporting this project by making a donation via [PayPal](https://www.paypal.com/donate/?hosted_button_id=NZUEC5XS8MFBJ)*
|
||||
|
||||
* **category** Library
|
||||
* **author** Nicola Asuni <info@tecnick.com>
|
||||
* **copyright** 2002-2024 Nicola Asuni - Tecnick.com LTD
|
||||
* **copyright** 2002-2025 Nicola Asuni - Tecnick.com LTD
|
||||
* **license** http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
|
||||
* **link** http://www.tcpdf.org
|
||||
* **source** https://github.com/tecnickcom/TCPDF
|
||||
|
||||
@@ -1 +1 @@
|
||||
6.7.5
|
||||
6.10.0
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"barcodes"
|
||||
],
|
||||
"homepage": "http://www.tcpdf.org/",
|
||||
"version": "6.7.5",
|
||||
"version": "6.10.0",
|
||||
"license": "LGPL-3.0-or-later",
|
||||
"authors": [
|
||||
{
|
||||
@@ -22,15 +22,14 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5.0"
|
||||
"php": ">=7.1.0",
|
||||
"ext-curl": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"config",
|
||||
"include",
|
||||
"tcpdf.php",
|
||||
"tcpdf_parser.php",
|
||||
"tcpdf_import.php",
|
||||
"tcpdf_barcodes_1d.php",
|
||||
"tcpdf_barcodes_2d.php",
|
||||
"include/tcpdf_colors.php",
|
||||
@@ -43,10 +42,5 @@
|
||||
"include/barcodes/pdf417.php",
|
||||
"include/barcodes/qrcode.php"
|
||||
]
|
||||
},
|
||||
"archive": {
|
||||
"exclude": [
|
||||
"/examples"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -275,7 +275,7 @@ class TCPDF_COLORS {
|
||||
$color = strtolower($color);
|
||||
// check for javascript color array syntax
|
||||
if (strpos($color, '[') !== false) {
|
||||
if (preg_match('/[\[][\"\'](t|g|rgb|cmyk)[\"\'][\,]?([0-9\.]*+)[\,]?([0-9\.]*+)[\,]?([0-9\.]*+)[\,]?([0-9\.]*+)[\]]/', $color, $m) > 0) {
|
||||
if (preg_match('/[\[][\"\'](t|g|rgba|rgb|cmyk)[\"\'][\,]?([0-9\.]*+)[\,]?([0-9\.]*+)[\,]?([0-9\.]*+)[\,]?([0-9\.]*+)[\]]/', $color, $m) > 0) {
|
||||
$returncolor = array();
|
||||
switch ($m[1]) {
|
||||
case 'cmyk': {
|
||||
@@ -286,7 +286,8 @@ class TCPDF_COLORS {
|
||||
$returncolor['K'] = max(0, min(100, (floatval($m[5]) * 100)));
|
||||
break;
|
||||
}
|
||||
case 'rgb': {
|
||||
case 'rgb':
|
||||
case 'rgba': {
|
||||
// RGB
|
||||
$returncolor['R'] = max(0, min(255, (floatval($m[2]) * 255)));
|
||||
$returncolor['G'] = max(0, min(255, (floatval($m[3]) * 255)));
|
||||
@@ -317,6 +318,25 @@ class TCPDF_COLORS {
|
||||
if (strlen($color) == 0) {
|
||||
return $defcol;
|
||||
}
|
||||
// RGBA ARRAY
|
||||
if (substr($color, 0, 4) == 'rgba') {
|
||||
$codes = substr($color, 5);
|
||||
$codes = str_replace(')', '', $codes);
|
||||
$returncolor = explode(',', $codes);
|
||||
// remove alpha component
|
||||
array_pop($returncolor);
|
||||
foreach ($returncolor as $key => $val) {
|
||||
if (strpos($val, '%') > 0) {
|
||||
// percentage
|
||||
$returncolor[$key] = (255 * intval($val) / 100);
|
||||
} else {
|
||||
$returncolor[$key] = intval($val); /* floatize */
|
||||
}
|
||||
// normalize value
|
||||
$returncolor[$key] = max(0, min(255, $returncolor[$key]));
|
||||
}
|
||||
return $returncolor;
|
||||
}
|
||||
// RGB ARRAY
|
||||
if (substr($color, 0, 3) == 'rgb') {
|
||||
$codes = substr($color, 4);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?php
|
||||
//============================================================+
|
||||
// File name : tcpdf_fonts.php
|
||||
// Version : 1.1.0
|
||||
// Version : 1.1.1
|
||||
// Begin : 2008-01-01
|
||||
// Last Update : 2014-12-10
|
||||
// Last Update : 2024-12-23
|
||||
// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
|
||||
// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
|
||||
// -------------------------------------------------------------------
|
||||
// Copyright (C) 2008-2014 Nicola Asuni - Tecnick.com LTD
|
||||
// Copyright (C) 2008-2025 Nicola Asuni - Tecnick.com LTD
|
||||
//
|
||||
// This file is part of TCPDF software library.
|
||||
//
|
||||
@@ -42,7 +42,7 @@
|
||||
* @class TCPDF_FONTS
|
||||
* Font methods for TCPDF library.
|
||||
* @package com.tecnick.tcpdf
|
||||
* @version 1.1.0
|
||||
* @version 1.1.1
|
||||
* @author Nicola Asuni - info@tecnick.com
|
||||
*/
|
||||
class TCPDF_FONTS {
|
||||
@@ -191,29 +191,30 @@ class TCPDF_FONTS {
|
||||
fclose($fp);
|
||||
// get font info
|
||||
$fmetric['Flags'] = $flags;
|
||||
preg_match ('#/FullName[\s]*\(([^\)]*)#', $font, $matches);
|
||||
preg_match ('#/FullName[\s]*+\(([^\)]*+)#', $font, $matches);
|
||||
$fmetric['name'] = preg_replace('/[^a-zA-Z0-9_\-]/', '', $matches[1]);
|
||||
preg_match('#/FontBBox[\s]*{([^}]*)#', $font, $matches);
|
||||
$fmetric['bbox'] = trim($matches[1]);
|
||||
$bv = explode(' ', $fmetric['bbox']);
|
||||
$fmetric['Ascent'] = intval($bv[3]);
|
||||
$fmetric['Descent'] = intval($bv[1]);
|
||||
preg_match('#/ItalicAngle[\s]*([0-9\+\-]*)#', $font, $matches);
|
||||
preg_match('#/FontBBox[\s]*+{([^}]*+)#', $font, $matches);
|
||||
$rawbvl = explode(' ', trim($matches[1]));
|
||||
$bvl = [(int) $rawbvl[0], (int) $rawbvl[1], (int) $rawbvl[2], (int) $rawbvl[3]];
|
||||
$fmetric['bbox'] = implode(' ', $bvl);
|
||||
$fmetric['Ascent'] = $bvl[3];
|
||||
$fmetric['Descent'] = $bvl[1];
|
||||
preg_match('#/ItalicAngle[\s]*+([0-9\+\-]*+)#', $font, $matches);
|
||||
$fmetric['italicAngle'] = intval($matches[1]);
|
||||
if ($fmetric['italicAngle'] != 0) {
|
||||
$fmetric['Flags'] |= 64;
|
||||
}
|
||||
preg_match('#/UnderlinePosition[\s]*([0-9\+\-]*)#', $font, $matches);
|
||||
preg_match('#/UnderlinePosition[\s]*+([0-9\+\-]*+)#', $font, $matches);
|
||||
$fmetric['underlinePosition'] = intval($matches[1]);
|
||||
preg_match('#/UnderlineThickness[\s]*([0-9\+\-]*)#', $font, $matches);
|
||||
preg_match('#/UnderlineThickness[\s]*+([0-9\+\-]*+)#', $font, $matches);
|
||||
$fmetric['underlineThickness'] = intval($matches[1]);
|
||||
preg_match('#/isFixedPitch[\s]*([^\s]*)#', $font, $matches);
|
||||
preg_match('#/isFixedPitch[\s]*+([^\s]*+)#', $font, $matches);
|
||||
if ($matches[1] == 'true') {
|
||||
$fmetric['Flags'] |= 1;
|
||||
}
|
||||
// get internal map
|
||||
$imap = array();
|
||||
if (preg_match_all('#dup[\s]([0-9]+)[\s]*/([^\s]*)[\s]put#sU', $font, $fmap, PREG_SET_ORDER) > 0) {
|
||||
if (preg_match_all('#dup[\s]([0-9]+)[\s]*+/([^\s]*+)[\s]put#sU', $font, $fmap, PREG_SET_ORDER) > 0) {
|
||||
foreach ($fmap as $v) {
|
||||
$imap[$v[2]] = $v[1];
|
||||
}
|
||||
@@ -229,22 +230,22 @@ class TCPDF_FONTS {
|
||||
$eplain .= chr($chr ^ ($r >> 8));
|
||||
$r = ((($chr + $r) * $c1 + $c2) % 65536);
|
||||
}
|
||||
if (preg_match('#/ForceBold[\s]*([^\s]*)#', $eplain, $matches) > 0) {
|
||||
if (preg_match('#/ForceBold[\s]*+([^\s]*+)#', $eplain, $matches) > 0) {
|
||||
if ($matches[1] == 'true') {
|
||||
$fmetric['Flags'] |= 0x40000;
|
||||
}
|
||||
}
|
||||
if (preg_match('#/StdVW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
|
||||
if (preg_match('#/StdVW[\s]*+\[([^\]]*+)#', $eplain, $matches) > 0) {
|
||||
$fmetric['StemV'] = intval($matches[1]);
|
||||
} else {
|
||||
$fmetric['StemV'] = 70;
|
||||
}
|
||||
if (preg_match('#/StdHW[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
|
||||
if (preg_match('#/StdHW[\s]*+\[([^\]]*+)#', $eplain, $matches) > 0) {
|
||||
$fmetric['StemH'] = intval($matches[1]);
|
||||
} else {
|
||||
$fmetric['StemH'] = 30;
|
||||
}
|
||||
if (preg_match('#/BlueValues[\s]*\[([^\]]*)#', $eplain, $matches) > 0) {
|
||||
if (preg_match('#/BlueValues[\s]*+\[([^\]]*+)#', $eplain, $matches) > 0) {
|
||||
$bv = explode(' ', $matches[1]);
|
||||
if (count($bv) >= 6) {
|
||||
$v1 = intval($bv[2]);
|
||||
@@ -265,7 +266,7 @@ class TCPDF_FONTS {
|
||||
$fmetric['CapHeight'] = 700;
|
||||
}
|
||||
// get the number of random bytes at the beginning of charstrings
|
||||
if (preg_match('#/lenIV[\s]*([0-9]*)#', $eplain, $matches) > 0) {
|
||||
if (preg_match('#/lenIV[\s]*+([\d]*+)#', $eplain, $matches) > 0) {
|
||||
$lenIV = intval($matches[1]);
|
||||
} else {
|
||||
$lenIV = 4;
|
||||
@@ -273,7 +274,7 @@ class TCPDF_FONTS {
|
||||
$fmetric['Leading'] = 0;
|
||||
// get charstring data
|
||||
$eplain = substr($eplain, (strpos($eplain, '/CharStrings') + 1));
|
||||
preg_match_all('#/([A-Za-z0-9\.]*)[\s][0-9]+[\s]RD[\s](.*)[\s]ND#sU', $eplain, $matches, PREG_SET_ORDER);
|
||||
preg_match_all('#/([A-Za-z0-9\.]*+)[\s][0-9]+[\s]RD[\s](.*)[\s]ND#sU', $eplain, $matches, PREG_SET_ORDER);
|
||||
if (!empty($enc) AND isset(TCPDF_FONT_DATA::$encmap[$enc])) {
|
||||
$enc_map = TCPDF_FONT_DATA::$encmap[$enc];
|
||||
} else {
|
||||
@@ -1780,9 +1781,9 @@ class TCPDF_FONTS {
|
||||
*/
|
||||
public static function UTF8ArrayToUniArray($ta, $isunicode=true) {
|
||||
if ($isunicode) {
|
||||
return array_map(get_called_class().'::unichrUnicode', $ta);
|
||||
return array_map(static::class.'::unichrUnicode', $ta);
|
||||
}
|
||||
return array_map(get_called_class().'::unichrASCII', $ta);
|
||||
return array_map(static::class.'::unichrASCII', $ta);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2002,7 +2003,7 @@ class TCPDF_FONTS {
|
||||
if ($isunicode) {
|
||||
// requires PCRE unicode support turned on
|
||||
$chars = TCPDF_STATIC::pregSplit('//','u', $str, -1, PREG_SPLIT_NO_EMPTY);
|
||||
$carr = array_map(get_called_class().'::uniord', $chars);
|
||||
$carr = array_map(static::class.'::uniord', $chars);
|
||||
} else {
|
||||
$chars = str_split($str);
|
||||
$carr = array_map('ord', $chars);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?php
|
||||
//============================================================+
|
||||
// File name : tcpdf_static.php
|
||||
// Version : 1.1.4
|
||||
// Version : 1.1.5
|
||||
// Begin : 2002-08-03
|
||||
// Last Update : 2023-09-06
|
||||
// Last Update : 2024-12-23
|
||||
// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
|
||||
// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
|
||||
// -------------------------------------------------------------------
|
||||
// Copyright (C) 2002-2023 Nicola Asuni - Tecnick.com LTD
|
||||
// Copyright (C) 2002-2025 Nicola Asuni - Tecnick.com LTD
|
||||
//
|
||||
// This file is part of TCPDF software library.
|
||||
//
|
||||
@@ -38,7 +38,7 @@
|
||||
* This is a PHP class that contains static methods for the TCPDF class.<br>
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.1.2
|
||||
* @version 1.1.5
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -46,7 +46,7 @@
|
||||
* Static methods used by the TCPDF class.
|
||||
* @package com.tecnick.tcpdf
|
||||
* @brief PHP class for generating PDF documents without requiring external extensions.
|
||||
* @version 1.1.1
|
||||
* @version 1.1.5
|
||||
* @author Nicola Asuni - info@tecnick.com
|
||||
*/
|
||||
class TCPDF_STATIC {
|
||||
@@ -55,7 +55,7 @@ class TCPDF_STATIC {
|
||||
* Current TCPDF version.
|
||||
* @private static
|
||||
*/
|
||||
private static $tcpdf_version = '6.7.5';
|
||||
private static $tcpdf_version = '6.10.0';
|
||||
|
||||
/**
|
||||
* String alias for total number of pages.
|
||||
@@ -106,6 +106,31 @@ class TCPDF_STATIC {
|
||||
*/
|
||||
public static $pageboxes = array('MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox');
|
||||
|
||||
/**
|
||||
* Array of default cURL options for curl_setopt_array.
|
||||
*
|
||||
* @var array<int, bool|int|string> cURL options.
|
||||
*/
|
||||
protected const CURLOPT_DEFAULT = [
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
CURLOPT_MAXREDIRS => 5,
|
||||
CURLOPT_PROTOCOLS => CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS,
|
||||
CURLOPT_SSL_VERIFYHOST => 2,
|
||||
CURLOPT_SSL_VERIFYPEER => true,
|
||||
CURLOPT_TIMEOUT => 30,
|
||||
CURLOPT_USERAGENT => 'tcpdf',
|
||||
];
|
||||
|
||||
/**
|
||||
* Array of fixed cURL options for curl_setopt_array.
|
||||
*
|
||||
* @var array<int, bool|int|string> cURL options.
|
||||
*/
|
||||
protected const CURLOPT_FIXED = [
|
||||
CURLOPT_FAILONERROR => true,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
];
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
/**
|
||||
@@ -379,7 +404,10 @@ class TCPDF_STATIC {
|
||||
if (function_exists('posix_getpid')) {
|
||||
$rnd .= posix_getpid();
|
||||
}
|
||||
if (function_exists('openssl_random_pseudo_bytes') AND (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) {
|
||||
|
||||
if (function_exists('random_bytes')) {
|
||||
$rnd .= random_bytes(512);
|
||||
} elseif (function_exists('openssl_random_pseudo_bytes') AND (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) {
|
||||
// this is not used on windows systems because it is very slow for a know bug
|
||||
$rnd .= openssl_random_pseudo_bytes(512);
|
||||
} else {
|
||||
@@ -387,7 +415,7 @@ class TCPDF_STATIC {
|
||||
$rnd .= uniqid('', true);
|
||||
}
|
||||
}
|
||||
return $rnd.$seed.__FILE__.serialize($_SERVER).microtime(true);
|
||||
return $rnd.$seed.__FILE__.microtime(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1820,23 +1848,19 @@ class TCPDF_STATIC {
|
||||
*/
|
||||
public static function url_exists($url) {
|
||||
$crs = curl_init();
|
||||
// encode query params in URL to get right response form the server
|
||||
$url = self::encodeUrlQuery($url);
|
||||
curl_setopt($crs, CURLOPT_URL, $url);
|
||||
curl_setopt($crs, CURLOPT_NOBODY, true);
|
||||
curl_setopt($crs, CURLOPT_FAILONERROR, true);
|
||||
if ((ini_get('open_basedir') == '') && (!ini_get('safe_mode'))) {
|
||||
curl_setopt($crs, CURLOPT_FOLLOWLOCATION, true);
|
||||
}
|
||||
curl_setopt($crs, CURLOPT_CONNECTTIMEOUT, 5);
|
||||
curl_setopt($crs, CURLOPT_TIMEOUT, 30);
|
||||
curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file');
|
||||
curl_setopt($crs, CURLOPT_MAXREDIRS, 5);
|
||||
if (defined('CURLOPT_PROTOCOLS')) {
|
||||
curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS);
|
||||
}
|
||||
$curlopts = [];
|
||||
if (
|
||||
(ini_get('open_basedir') == '')
|
||||
&& (ini_get('safe_mode') === ''
|
||||
|| ini_get('safe_mode') === false)
|
||||
) {
|
||||
$curlopts[CURLOPT_FOLLOWLOCATION] = true;
|
||||
}
|
||||
$curlopts = array_replace($curlopts, self::CURLOPT_DEFAULT);
|
||||
$curlopts = array_replace($curlopts, K_CURLOPTS);
|
||||
$curlopts = array_replace($curlopts, self::CURLOPT_FIXED);
|
||||
$curlopts[CURLOPT_URL] = $url;
|
||||
curl_setopt_array($crs, $curlopts);
|
||||
curl_exec($crs);
|
||||
$code = curl_getinfo($crs, CURLINFO_HTTP_CODE);
|
||||
curl_close($crs);
|
||||
@@ -1957,22 +1981,19 @@ class TCPDF_STATIC {
|
||||
) {
|
||||
// try to get remote file data using cURL
|
||||
$crs = curl_init();
|
||||
curl_setopt($crs, CURLOPT_URL, $path);
|
||||
curl_setopt($crs, CURLOPT_BINARYTRANSFER, true);
|
||||
curl_setopt($crs, CURLOPT_FAILONERROR, true);
|
||||
curl_setopt($crs, CURLOPT_RETURNTRANSFER, true);
|
||||
if ((ini_get('open_basedir') == '') && (!ini_get('safe_mode'))) {
|
||||
curl_setopt($crs, CURLOPT_FOLLOWLOCATION, true);
|
||||
}
|
||||
curl_setopt($crs, CURLOPT_CONNECTTIMEOUT, 5);
|
||||
curl_setopt($crs, CURLOPT_TIMEOUT, 30);
|
||||
curl_setopt($crs, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($crs, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($crs, CURLOPT_USERAGENT, 'tc-lib-file');
|
||||
curl_setopt($crs, CURLOPT_MAXREDIRS, 5);
|
||||
if (defined('CURLOPT_PROTOCOLS')) {
|
||||
curl_setopt($crs, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS | CURLPROTO_HTTP | CURLPROTO_FTP | CURLPROTO_FTPS);
|
||||
$curlopts = [];
|
||||
if (
|
||||
(ini_get('open_basedir') == '')
|
||||
&& (ini_get('safe_mode') === ''
|
||||
|| ini_get('safe_mode') === false)
|
||||
) {
|
||||
$curlopts[CURLOPT_FOLLOWLOCATION] = true;
|
||||
}
|
||||
$curlopts = array_replace($curlopts, self::CURLOPT_DEFAULT);
|
||||
$curlopts = array_replace($curlopts, K_CURLOPTS);
|
||||
$curlopts = array_replace($curlopts, self::CURLOPT_FIXED);
|
||||
$curlopts[CURLOPT_URL] = $url;
|
||||
curl_setopt_array($crs, $curlopts);
|
||||
$ret = curl_exec($crs);
|
||||
curl_close($crs);
|
||||
if ($ret !== false) {
|
||||
@@ -2631,7 +2652,6 @@ class TCPDF_STATIC {
|
||||
return $page_mode;
|
||||
}
|
||||
|
||||
|
||||
} // END OF TCPDF_STATIC CLASS
|
||||
|
||||
//============================================================+
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<?php
|
||||
//============================================================+
|
||||
// File name : tcpdf.php
|
||||
// Version : 6.7.5
|
||||
// Version : 6.10.0
|
||||
// Begin : 2002-08-03
|
||||
// Last Update : 2024-03-18
|
||||
// Last Update : 2025-05-27
|
||||
// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
|
||||
// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
|
||||
// -------------------------------------------------------------------
|
||||
// Copyright (C) 2002-2024 Nicola Asuni - Tecnick.com LTD
|
||||
// Copyright (C) 2002-2025 Nicola Asuni - Tecnick.com LTD
|
||||
//
|
||||
// This file is part of TCPDF software library.
|
||||
//
|
||||
@@ -104,7 +104,7 @@
|
||||
* Tools to encode your unicode fonts are on fonts/utils directory.</p>
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 6.6.5
|
||||
* @version 6.10.0
|
||||
*/
|
||||
|
||||
// TCPDF configuration
|
||||
@@ -128,7 +128,7 @@ require_once(dirname(__FILE__).'/include/tcpdf_static.php');
|
||||
* TCPDF project (http://www.tcpdf.org) has been originally derived in 2002 from the Public Domain FPDF class by Olivier Plathey (http://www.fpdf.org), but now is almost entirely rewritten.<br>
|
||||
* @package com.tecnick.tcpdf
|
||||
* @brief PHP class for generating PDF documents without requiring external extensions.
|
||||
* @version 6.7.5
|
||||
* @version 6.10.0
|
||||
* @author Nicola Asuni - info@tecnick.com
|
||||
* @IgnoreAnnotation("protected")
|
||||
* @IgnoreAnnotation("public")
|
||||
@@ -1810,6 +1810,13 @@ class TCPDF {
|
||||
*/
|
||||
protected $custom_xmp_rdf = '';
|
||||
|
||||
/**
|
||||
* Custom XMP RDF pdfaextension data.
|
||||
* @protected
|
||||
* @since 6.9.0 (2025-02-11)
|
||||
*/
|
||||
protected $custom_xmp_rdf_pdfaExtension = '';
|
||||
|
||||
/**
|
||||
* Overprint mode array.
|
||||
* (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008).
|
||||
@@ -3007,6 +3014,7 @@ class TCPDF {
|
||||
public function Error($msg) {
|
||||
// unset all class variables
|
||||
$this->_destroy(true);
|
||||
$msg = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
|
||||
if (defined('K_TCPDF_THROW_EXCEPTION_ERROR') AND !K_TCPDF_THROW_EXCEPTION_ERROR) {
|
||||
die('<strong>TCPDF ERROR: </strong>'.$msg);
|
||||
} else {
|
||||
@@ -4931,6 +4939,32 @@ class TCPDF {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Embed the attached files.
|
||||
* @since 6.9.000 (2025-02-11)
|
||||
* @public
|
||||
*/
|
||||
public function EmbedFile($opt) {
|
||||
if (!$this->pdfa_mode || ($this->pdfa_mode && $this->pdfa_version == 3)) {
|
||||
if ((($opt['Subtype'] == 'FileAttachment')) AND (!TCPDF_STATIC::empty_string($opt['FS']))
|
||||
AND (@TCPDF_STATIC::file_exists($opt['FS']) OR TCPDF_STATIC::isValidURL($opt['FS']))
|
||||
AND (!isset($this->embeddedfiles[basename($opt['FS'])]))) {
|
||||
$this->embeddedfiles[basename($opt['FS'])] = array('f' => ++$this->n, 'n' => ++$this->n, 'file' => $opt['FS']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Embed the attached files.
|
||||
* @since 6.9.000 (2025-02-11)
|
||||
* @public
|
||||
*/
|
||||
public function EmbedFileFromString($filename, $content) {
|
||||
if (!$this->pdfa_mode || ($this->pdfa_mode && $this->pdfa_version == 3)) {
|
||||
$this->embeddedfiles[$filename] = array('f' => ++$this->n, 'n' => ++$this->n, 'content' => $content );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Embedd the attached files.
|
||||
* @since 4.4.000 (2008-12-07)
|
||||
@@ -4944,7 +4978,12 @@ class TCPDF {
|
||||
}
|
||||
reset($this->embeddedfiles);
|
||||
foreach ($this->embeddedfiles as $filename => $filedata) {
|
||||
$data = $this->getCachedFileContents($filedata['file']);
|
||||
$data = false;
|
||||
if (isset($filedata['file']) && !empty($filedata['file'])) {
|
||||
$data = $this->getCachedFileContents($filedata['file']);
|
||||
} elseif ($filedata['content'] && !empty($filedata['content'])) {
|
||||
$data = $filedata['content'];
|
||||
}
|
||||
if ($data !== FALSE) {
|
||||
$rawsize = strlen($data);
|
||||
if ($rawsize > 0) {
|
||||
@@ -6988,7 +7027,7 @@ class TCPDF {
|
||||
unset($imgdata);
|
||||
$imsize = @getimagesize($file);
|
||||
if ($imsize === FALSE) {
|
||||
unlink($file);
|
||||
$this->_unlink($file);
|
||||
$file = $original_file;
|
||||
}
|
||||
}
|
||||
@@ -7221,7 +7260,7 @@ class TCPDF {
|
||||
$tempname = TCPDF_STATIC::getObjFilename('img', $this->file_id);
|
||||
$img->writeImage($tempname);
|
||||
$info = TCPDF_IMAGES::_parsejpeg($tempname);
|
||||
unlink($tempname);
|
||||
$this->_unlink($tempname);
|
||||
$img->destroy();
|
||||
} catch(Exception $e) {
|
||||
$info = false;
|
||||
@@ -7857,15 +7896,16 @@ class TCPDF {
|
||||
if ($handle = @opendir(K_PATH_CACHE)) {
|
||||
while ( false !== ( $file_name = readdir( $handle ) ) ) {
|
||||
if (strpos($file_name, '__tcpdf_'.$this->file_id.'_') === 0) {
|
||||
unlink(K_PATH_CACHE.$file_name);
|
||||
$this->_unlink(K_PATH_CACHE.$file_name);
|
||||
}
|
||||
}
|
||||
closedir($handle);
|
||||
}
|
||||
if (isset($this->imagekeys)) {
|
||||
foreach($this->imagekeys as $file) {
|
||||
if (strpos($file, K_PATH_CACHE) === 0 && TCPDF_STATIC::file_exists($file)) {
|
||||
@unlink($file);
|
||||
if ((strpos($file, K_PATH_CACHE.'__tcpdf_'.$this->file_id.'_') === 0)
|
||||
&& TCPDF_STATIC::file_exists($file)) {
|
||||
$this->_unlink($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8164,7 +8204,7 @@ class TCPDF {
|
||||
* @since 5.0.010 (2010-05-17)
|
||||
*/
|
||||
protected function _getannotsrefs($n) {
|
||||
if (!(isset($this->PageAnnots[$n]) OR ($this->sign AND isset($this->signature_data['cert_type'])))) {
|
||||
if (!(isset($this->PageAnnots[$n]) OR count($this->empty_signature_appearance)>0 OR ($this->sign AND isset($this->signature_data['cert_type'])))) {
|
||||
return '';
|
||||
}
|
||||
$out = ' /Annots [';
|
||||
@@ -8310,15 +8350,15 @@ class TCPDF {
|
||||
break;
|
||||
}
|
||||
case 'locked': {
|
||||
$fval += 1 << 8;
|
||||
$fval += 1 << 7;
|
||||
break;
|
||||
}
|
||||
case 'togglenoview': {
|
||||
$fval += 1 << 9;
|
||||
$fval += 1 << 8;
|
||||
break;
|
||||
}
|
||||
case 'lockedcontents': {
|
||||
$fval += 1 << 10;
|
||||
$fval += 1 << 9;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -8532,7 +8572,7 @@ class TCPDF {
|
||||
}
|
||||
case 'freetext': {
|
||||
if (isset($pl['opt']['da']) AND !empty($pl['opt']['da'])) {
|
||||
$annots .= ' /DA ('.$pl['opt']['da'].')';
|
||||
$annots .= ' /DA '.$this->_datastring($pl['opt']['da']);
|
||||
}
|
||||
if (isset($pl['opt']['q']) AND ($pl['opt']['q'] >= 0) AND ($pl['opt']['q'] <= 2)) {
|
||||
$annots .= ' /Q '.intval($pl['opt']['q']);
|
||||
@@ -8789,7 +8829,7 @@ class TCPDF {
|
||||
$annots .= ' /AA << '.$pl['opt']['aa'].' >>';
|
||||
}
|
||||
if (isset($pl['opt']['da']) AND !empty($pl['opt']['da'])) {
|
||||
$annots .= ' /DA ('.$pl['opt']['da'].')';
|
||||
$annots .= ' /DA '.$this->_datastring($pl['opt']['da']);
|
||||
}
|
||||
if (isset($pl['opt']['q']) AND ($pl['opt']['q'] >= 0) AND ($pl['opt']['q'] <= 2)) {
|
||||
$annots .= ' /Q '.intval($pl['opt']['q']);
|
||||
@@ -9628,6 +9668,17 @@ class TCPDF {
|
||||
$this->custom_xmp_rdf = $xmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set additional XMP data to be added to the default XMP data for PDF/A extensions.
|
||||
* IMPORTANT: This data is added as-is without controls, so you have to validate your data before using this method!
|
||||
* @param string $xmp Custom XMP RDF data.
|
||||
* @since 6.9.0 (2025-02-14)
|
||||
* @public
|
||||
*/
|
||||
public function setExtraXMPPdfaextension($xmp) {
|
||||
$this->custom_xmp_rdf_pdfaExtension = $xmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put XMP data object and return ID.
|
||||
* @return int The object ID.
|
||||
@@ -9762,6 +9813,7 @@ class TCPDF {
|
||||
$xmp .= "\t\t\t\t\t\t\t".'</rdf:Seq>'."\n";
|
||||
$xmp .= "\t\t\t\t\t\t".'</pdfaSchema:property>'."\n";
|
||||
$xmp .= "\t\t\t\t\t".'</rdf:li>'."\n";
|
||||
$xmp .= $this->custom_xmp_rdf_pdfaExtension;
|
||||
$xmp .= "\t\t\t\t".'</rdf:Bag>'."\n";
|
||||
$xmp .= "\t\t\t".'</pdfaExtension:schemas>'."\n";
|
||||
$xmp .= "\t\t".'</rdf:Description>'."\n";
|
||||
@@ -9800,7 +9852,11 @@ class TCPDF {
|
||||
}
|
||||
// start catalog
|
||||
$oid = $this->_newobj();
|
||||
$out = '<< /Type /Catalog';
|
||||
$out = '<< ';
|
||||
if (!empty($this->efnames)) {
|
||||
$out .= ' /AF [ '. implode(' ', $this->efnames) .' ]';
|
||||
}
|
||||
$out .= ' /Type /Catalog';
|
||||
$out .= ' /Version /'.$this->PDFVersion;
|
||||
//$out .= ' /Extensions <<>>';
|
||||
$out .= ' /Pages 1 0 R';
|
||||
@@ -9939,7 +9995,7 @@ class TCPDF {
|
||||
$out .= ' >> >>';
|
||||
}
|
||||
$font = $this->getFontBuffer((($this->pdfa_mode) ? 'pdfa' : '') .'helvetica');
|
||||
$out .= ' /DA (/F'.$font['i'].' 0 Tf 0 g)';
|
||||
$out .= ' /DA ' . $this->_datastring('/F'.$font['i'].' 0 Tf 0 g');
|
||||
$out .= ' /Q '.(($this->rtl)?'2':'0');
|
||||
//$out .= ' /XFA ';
|
||||
$out .= ' >>';
|
||||
@@ -11046,7 +11102,7 @@ class TCPDF {
|
||||
$this->encryptdata['V'] = 4;
|
||||
$this->encryptdata['Length'] = 128;
|
||||
$this->encryptdata['CF']['CFM'] = 'AESV2';
|
||||
$this->encryptdata['CF']['Length'] = 128;
|
||||
$this->encryptdata['CF']['Length'] = 16;
|
||||
if ($this->encryptdata['pubkey']) {
|
||||
$this->encryptdata['SubFilter'] = 'adbe.pkcs7.s5';
|
||||
$this->encryptdata['Recipients'] = array();
|
||||
@@ -11057,7 +11113,7 @@ class TCPDF {
|
||||
$this->encryptdata['V'] = 5;
|
||||
$this->encryptdata['Length'] = 256;
|
||||
$this->encryptdata['CF']['CFM'] = 'AESV3';
|
||||
$this->encryptdata['CF']['Length'] = 256;
|
||||
$this->encryptdata['CF']['Length'] = 32;
|
||||
if ($this->encryptdata['pubkey']) {
|
||||
$this->encryptdata['SubFilter'] = 'adbe.pkcs7.s5';
|
||||
$this->encryptdata['Recipients'] = array();
|
||||
@@ -13936,8 +13992,8 @@ class TCPDF {
|
||||
* @since 3.0.000 (2008-03-27)
|
||||
*/
|
||||
protected function addExtGState($parms) {
|
||||
if ($this->pdfa_mode || $this->pdfa_version >= 2) {
|
||||
// transparencies are not allowed in PDF/A mode
|
||||
if (($this->pdfa_mode && $this->pdfa_version < 2) || ($this->state != 2)) {
|
||||
// transparency is not allowed in PDF/A-1 mode
|
||||
return;
|
||||
}
|
||||
// check if this ExtGState already exist
|
||||
@@ -16440,7 +16496,7 @@ class TCPDF {
|
||||
)
|
||||
);
|
||||
|
||||
if(empty($html)) {
|
||||
if($html === '' || $html === null) {
|
||||
return $dom;
|
||||
}
|
||||
// array of CSS styles ( selector => properties).
|
||||
@@ -17259,7 +17315,7 @@ class TCPDF {
|
||||
$hlen = intval(substr($data, 0, $hpos));
|
||||
$hash = substr($data, $hpos + 1, $hlen);
|
||||
$encoded = substr($data, $hpos + 2 + $hlen);
|
||||
if ($hash != $this->hashTCPDFtag($encoded)) {
|
||||
if (!hash_equals( $this->hashTCPDFtag($encoded), $hash)) {
|
||||
$this->Error('Invalid parameters');
|
||||
}
|
||||
return json_decode(urldecode($encoded), true);
|
||||
@@ -17425,6 +17481,9 @@ class TCPDF {
|
||||
}
|
||||
}
|
||||
if ($key == $maxel) break;
|
||||
if ($dom[$key]['tag'] AND $dom[$key]['opening'] AND !empty($dom[$key]['attribute']['id'])) {
|
||||
$this->setDestination($dom[$key]['attribute']['id']);
|
||||
}
|
||||
if ($dom[$key]['tag'] AND isset($dom[$key]['attribute']['pagebreak'])) {
|
||||
// check for pagebreak
|
||||
if (($dom[$key]['attribute']['pagebreak'] == 'true') OR ($dom[$key]['attribute']['pagebreak'] == 'left') OR ($dom[$key]['attribute']['pagebreak'] == 'right')) {
|
||||
@@ -18867,6 +18926,29 @@ class TCPDF {
|
||||
unset($dom);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the path is relative.
|
||||
* @param string $path path to check
|
||||
* @return boolean true if the path is relative
|
||||
* @protected
|
||||
* @since 6.9.1
|
||||
*/
|
||||
protected function isRelativePath($path) {
|
||||
return (strpos(str_ireplace('%2E', '.', $this->unhtmlentities($path)), '..') !== false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if it contains a non-allowed external protocol.
|
||||
* @param string $path path to check
|
||||
* @return boolean true if the protocol is not allowed.
|
||||
* @protected
|
||||
* @since 6.9.3
|
||||
*/
|
||||
protected function hasExtForbiddenProtocol($path) {
|
||||
return ((strpos($path, '://') !== false)
|
||||
&& (preg_match('|^https?://|', $path) !== 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Process opening tags.
|
||||
* @param array $dom html dom array
|
||||
@@ -19010,29 +19092,29 @@ class TCPDF {
|
||||
$this->setLineWidth($hrHeight);
|
||||
|
||||
$lineStyle = array();
|
||||
if (isset($tag['fgcolor'])) {
|
||||
$lineStyle['color'] = $tag['fgcolor'];
|
||||
}
|
||||
if (isset($tag['fgcolor'])) {
|
||||
$lineStyle['color'] = $tag['fgcolor'];
|
||||
}
|
||||
|
||||
if (isset($tag['fgcolor'])) {
|
||||
$lineStyle['color'] = $tag['fgcolor'];
|
||||
}
|
||||
if (isset($tag['fgcolor'])) {
|
||||
$lineStyle['color'] = $tag['fgcolor'];
|
||||
}
|
||||
|
||||
if (isset($tag['style']['cap'])) {
|
||||
$lineStyle['cap'] = $tag['style']['cap'];
|
||||
}
|
||||
if (isset($tag['style']['cap'])) {
|
||||
$lineStyle['cap'] = $tag['style']['cap'];
|
||||
}
|
||||
|
||||
if (isset($tag['style']['join'])) {
|
||||
$lineStyle['join'] = $tag['style']['join'];
|
||||
}
|
||||
if (isset($tag['style']['join'])) {
|
||||
$lineStyle['join'] = $tag['style']['join'];
|
||||
}
|
||||
|
||||
if (isset($tag['style']['dash'])) {
|
||||
$lineStyle['dash'] = $tag['style']['dash'];
|
||||
}
|
||||
if (isset($tag['style']['dash'])) {
|
||||
$lineStyle['dash'] = $tag['style']['dash'];
|
||||
}
|
||||
|
||||
if (isset($tag['style']['phase'])) {
|
||||
$lineStyle['phase'] = $tag['style']['phase'];
|
||||
}
|
||||
if (isset($tag['style']['phase'])) {
|
||||
$lineStyle['phase'] = $tag['style']['phase'];
|
||||
}
|
||||
|
||||
$lineStyle = array_filter($lineStyle);
|
||||
|
||||
@@ -19055,15 +19137,20 @@ class TCPDF {
|
||||
if ($imgsrc[0] === '@') {
|
||||
// data stream
|
||||
$imgsrc = '@'.base64_decode(substr($imgsrc, 1));
|
||||
$type = '';
|
||||
$type = preg_match('/<svg\s+[^>]*[^>]*>.*<\/svg>/is', $imgsrc) ? 'svg' : '';
|
||||
} else if (preg_match('@^data:image/([^;]*);base64,(.*)@', $imgsrc, $reg)) {
|
||||
$imgsrc = '@'.base64_decode($reg[2]);
|
||||
$type = $reg[1];
|
||||
} elseif ($this->isRelativePath($imgsrc)) {
|
||||
// accessing parent folders is not allowed
|
||||
break;
|
||||
} elseif ( $this->allowLocalFiles && substr($imgsrc, 0, 7) === 'file://') {
|
||||
// get image type from a local file path
|
||||
$imgsrc = substr($imgsrc, 7);
|
||||
$type = TCPDF_IMAGES::getImageFileType($imgsrc);
|
||||
} else {
|
||||
// get image type from a local file path
|
||||
$imgsrc = substr($imgsrc, 7);
|
||||
$type = TCPDF_IMAGES::getImageFileType($imgsrc);
|
||||
} elseif ($this->hasExtForbiddenProtocol($imgsrc)) {
|
||||
break;
|
||||
} else {
|
||||
if (($imgsrc[0] === '/') AND !empty($_SERVER['DOCUMENT_ROOT']) AND ($_SERVER['DOCUMENT_ROOT'] != '/')) {
|
||||
// fix image path
|
||||
$findroot = strpos($imgsrc, $_SERVER['DOCUMENT_ROOT']);
|
||||
@@ -19121,7 +19208,7 @@ class TCPDF {
|
||||
$imglink = '';
|
||||
if (isset($this->HREF['url']) AND !TCPDF_STATIC::empty_string($this->HREF['url'])) {
|
||||
$imglink = $this->HREF['url'];
|
||||
if ($imglink[0] == '#') {
|
||||
if ($imglink[0] == '#' AND isset($imglink[1]) AND is_numeric($imglink[1])) {
|
||||
// convert url to internal link
|
||||
$lnkdata = explode(',', $imglink);
|
||||
if (isset($lnkdata[0])) {
|
||||
@@ -19982,7 +20069,7 @@ class TCPDF {
|
||||
}
|
||||
}
|
||||
if (!$in_table_head) { // we are not inside a thead section
|
||||
$this->cell_padding = isset($table_el['old_cell_padding']) ? $table_el['old_cell_padding'] : null;
|
||||
$this->cell_padding = isset($table_el['old_cell_padding']) ? $table_el['old_cell_padding'] : array('T' => 0, 'R' => 0, 'B' => 0, 'L' => 0);
|
||||
// reset row height
|
||||
$this->resetLastH();
|
||||
if (($this->page == ($this->numpages - 1)) AND ($this->pageopen[$this->numpages])) {
|
||||
@@ -23170,14 +23257,12 @@ class TCPDF {
|
||||
$this->_out(sprintf('%F %F %F %F %F %F cm', $svgscale_x, 0, 0, $svgscale_y, ($e + $svgoffset_x), ($f + $svgoffset_y)));
|
||||
// creates a new XML parser to be used by the other XML functions
|
||||
$parser = xml_parser_create('UTF-8');
|
||||
// the following function allows to use parser inside object
|
||||
xml_set_object($parser, $this);
|
||||
// disable case-folding for this XML parser
|
||||
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
|
||||
// sets the element handler functions for the XML parser
|
||||
xml_set_element_handler($parser, 'startSVGElementHandler', 'endSVGElementHandler');
|
||||
xml_set_element_handler($parser, [$this, 'startSVGElementHandler'], [$this, 'endSVGElementHandler']);
|
||||
// sets the character data handler function for the XML parser
|
||||
xml_set_character_data_handler($parser, 'segSVGContentHandler');
|
||||
xml_set_character_data_handler($parser, [$this, 'segSVGContentHandler']);
|
||||
// start parsing an XML document
|
||||
if (!xml_parse($parser, $svgdata)) {
|
||||
$error_message = sprintf('SVG Error: %s at line %d', xml_error_string(xml_get_error_code($parser)), xml_get_current_line_number($parser));
|
||||
@@ -23327,7 +23412,7 @@ class TCPDF {
|
||||
$text_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['text-color'], $this->spot_colors);
|
||||
$this->setTextColorArray($text_color);
|
||||
// clip
|
||||
if (preg_match('/rect\(([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)[\s]*([a-z0-9\-\.]*)\)/si', $svgstyle['clip'], $regs)) {
|
||||
if (preg_match('/rect\(([a-z0-9\-\.]*+)[\s]*+([a-z0-9\-\.]*+)[\s]*+([a-z0-9\-\.]*+)[\s]*+([a-z0-9\-\.]*+)\)/si', $svgstyle['clip'], $regs)) {
|
||||
$top = (isset($regs[1])?$this->getHTMLUnitToUnits($regs[1], 0, $this->svgunit, false):0);
|
||||
$right = (isset($regs[2])?$this->getHTMLUnitToUnits($regs[2], 0, $this->svgunit, false):0);
|
||||
$bottom = (isset($regs[3])?$this->getHTMLUnitToUnits($regs[3], 0, $this->svgunit, false):0);
|
||||
@@ -23444,13 +23529,15 @@ class TCPDF {
|
||||
$cy -= $h;
|
||||
}
|
||||
$this->_out(sprintf('%F 0 0 %F %F %F cm', ($w * $this->k), ($h * $this->k), ($x * $this->k), ($cy * $this->k)));
|
||||
if (count($gradient['stops']) > 1) {
|
||||
$this->Gradient($gradient['type'], $gradient['coords'], $gradient['stops'], array(), false);
|
||||
if ((is_array($gradient['stops']) || $gradient['stops'] instanceof Countable) && count($gradient['stops']) > 1) {
|
||||
$this->Gradient($gradient['type'], $gradient['coords'], $gradient['stops']);
|
||||
}
|
||||
} elseif ($svgstyle['fill'] != 'none') {
|
||||
$fill_color = TCPDF_COLORS::convertHTMLColorToDec($svgstyle['fill'], $this->spot_colors);
|
||||
if ($svgstyle['fill-opacity'] != 1) {
|
||||
$this->setAlpha($this->alpha['CA'], 'Normal', $svgstyle['fill-opacity'], false);
|
||||
} elseif (preg_match('/rgba\(\d+%?,\s*\d+%?,\s*\d+%?,\s*(\d+(?:\.\d+)?)\)/i', $svgstyle['fill'], $rgba_matches)) {
|
||||
$this->setAlpha($this->alpha['CA'], 'Normal', $rgba_matches[1], false);
|
||||
}
|
||||
$this->setFillColorArray($fill_color);
|
||||
if ($svgstyle['fill-rule'] == 'evenodd') {
|
||||
@@ -23484,7 +23571,7 @@ class TCPDF {
|
||||
if (preg_match('/font-family[\s]*:[\s]*([^\;\"]*)/si', $svgstyle['font'], $regs)) {
|
||||
$font_family = $this->getFontFamilyName($regs[1]);
|
||||
} else {
|
||||
$font_family = $svgstyle['font-family'];
|
||||
$font_family = $this->getFontFamilyName($svgstyle['font-family']);
|
||||
}
|
||||
if (preg_match('/font-size[\s]*:[\s]*([^\s\;\"]*)/si', $svgstyle['font'], $regs)) {
|
||||
$font_size = trim($regs[1]);
|
||||
@@ -23639,7 +23726,8 @@ class TCPDF {
|
||||
$params = array();
|
||||
if (isset($val[2])) {
|
||||
// get curve parameters
|
||||
$rawparams = preg_split('/([\,\s]+)/si', trim($val[2]));
|
||||
preg_match_all('/-?\d*\.?\d+/', trim($val[2]), $matches);
|
||||
$rawparams = $matches[0];
|
||||
$params = array();
|
||||
foreach ($rawparams as $ck => $cp) {
|
||||
$params[$ck] = $this->getHTMLUnitToUnits($cp, 0, $this->svgunit, false);
|
||||
@@ -24464,6 +24552,9 @@ class TCPDF {
|
||||
$img = '@'.base64_decode(substr($img, strlen($m[0])));
|
||||
} else {
|
||||
// fix image path
|
||||
if ($this->isRelativePath($img) || $this->hasExtForbiddenProtocol($img)) {
|
||||
break;
|
||||
}
|
||||
if (!TCPDF_STATIC::empty_string($this->svgdir) AND (($img[0] == '.') OR (basename($img) == $img))) {
|
||||
// replace relative path with full server path
|
||||
$img = $this->svgdir.'/'.$img;
|
||||
@@ -24784,6 +24875,20 @@ class TCPDF {
|
||||
return TCPDF_STATIC::file_exists($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for unlink with disabled protocols.
|
||||
* @param string $file
|
||||
* @return bool
|
||||
*/
|
||||
protected function _unlink($file)
|
||||
{
|
||||
if ((strpos($file, '://') !== false) && ((substr($file, 0, 7) !== 'file://') || (!$this->allowLocalFiles))) {
|
||||
// forbidden protocol
|
||||
return false;
|
||||
}
|
||||
return @unlink($file);
|
||||
}
|
||||
|
||||
} // END OF TCPDF CLASS
|
||||
|
||||
//============================================================+
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
// File name : tcpdf_autoconfig.php
|
||||
// Version : 1.1.1
|
||||
// Begin : 2013-05-16
|
||||
// Last Update : 2014-12-18
|
||||
// Last Update : 2025-04-18
|
||||
// Authors : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
|
||||
// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
|
||||
// -------------------------------------------------------------------
|
||||
// Copyright (C) 2011-2014 Nicola Asuni - Tecnick.com LTD
|
||||
// Copyright (C) 2011-2025 Nicola Asuni - Tecnick.com LTD
|
||||
//
|
||||
// This file is part of TCPDF software library.
|
||||
//
|
||||
@@ -37,9 +37,14 @@
|
||||
* @file
|
||||
* Try to automatically configure some TCPDF constants if not defined.
|
||||
* @package com.tecnick.tcpdf
|
||||
* @version 1.1.1
|
||||
* @version 1.2.1
|
||||
*/
|
||||
|
||||
// Disable phar stream wrapper globally.
|
||||
// if (in_array('phar', stream_get_wrappers(), true)) {
|
||||
// stream_wrapper_unregister('phar');
|
||||
// }
|
||||
|
||||
// DOCUMENT_ROOT fix for IIS Webserver
|
||||
if ((!isset($_SERVER['DOCUMENT_ROOT'])) OR (empty($_SERVER['DOCUMENT_ROOT']))) {
|
||||
if(isset($_SERVER['SCRIPT_FILENAME'])) {
|
||||
@@ -240,6 +245,11 @@ if (!defined('K_TIMEZONE')) {
|
||||
define('K_TIMEZONE', @date_default_timezone_get());
|
||||
}
|
||||
|
||||
// Custom cURL options for curl_setopt_array.
|
||||
if (!defined('K_CURLOPTS')) {
|
||||
define('K_CURLOPTS', array());
|
||||
}
|
||||
|
||||
//============================================================+
|
||||
// END OF FILE
|
||||
//============================================================+
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
<?php
|
||||
//============================================================+
|
||||
// File name : tcpdf_import.php
|
||||
// Version : 1.0.001
|
||||
// Begin : 2011-05-23
|
||||
// Last Update : 2013-09-17
|
||||
// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
|
||||
// License : GNU-LGPL v3 (http://www.gnu.org/copyleft/lesser.html)
|
||||
// -------------------------------------------------------------------
|
||||
// Copyright (C) 2011-2013 Nicola Asuni - Tecnick.com LTD
|
||||
//
|
||||
// This file is part of TCPDF software library.
|
||||
//
|
||||
// TCPDF is free software: you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// TCPDF is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the License
|
||||
// along with TCPDF. If not, see
|
||||
// <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
|
||||
//
|
||||
// See LICENSE.TXT file for more information.
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
// Description : This is a PHP class extension of the TCPDF library to
|
||||
// import existing PDF documents.
|
||||
//
|
||||
//============================================================+
|
||||
|
||||
/**
|
||||
* @file
|
||||
* !!! THIS CLASS IS UNDER DEVELOPMENT !!!
|
||||
* This is a PHP class extension of the TCPDF (http://www.tcpdf.org) library to import existing PDF documents.<br>
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.001
|
||||
*/
|
||||
|
||||
// include the TCPDF class
|
||||
require_once(dirname(__FILE__).'/tcpdf.php');
|
||||
// include PDF parser class
|
||||
require_once(dirname(__FILE__).'/tcpdf_parser.php');
|
||||
|
||||
/**
|
||||
* @class TCPDF_IMPORT
|
||||
* !!! THIS CLASS IS UNDER DEVELOPMENT !!!
|
||||
* PHP class extension of the TCPDF (http://www.tcpdf.org) library to import existing PDF documents.<br>
|
||||
* @package com.tecnick.tcpdf
|
||||
* @brief PHP class extension of the TCPDF library to import existing PDF documents.
|
||||
* @version 1.0.001
|
||||
* @author Nicola Asuni - info@tecnick.com
|
||||
*/
|
||||
class TCPDF_IMPORT extends TCPDF {
|
||||
|
||||
/**
|
||||
* Import an existing PDF document
|
||||
* @param string $filename Filename of the PDF document to import.
|
||||
* @return void
|
||||
* @public
|
||||
* @since 1.0.000 (2011-05-24)
|
||||
*/
|
||||
public function importPDF($filename) {
|
||||
// load document
|
||||
$rawdata = file_get_contents($filename);
|
||||
if ($rawdata === false) {
|
||||
$this->Error('Unable to get the content of the file: '.$filename);
|
||||
}
|
||||
// configuration parameters for parser
|
||||
$cfg = array(
|
||||
'die_for_errors' => false,
|
||||
'ignore_filter_decoding_errors' => true,
|
||||
'ignore_missing_filter_decoders' => true,
|
||||
);
|
||||
try {
|
||||
// parse PDF data
|
||||
$pdf = new TCPDF_PARSER($rawdata, $cfg);
|
||||
} catch (Exception $e) {
|
||||
die($e->getMessage());
|
||||
}
|
||||
// get the parsed data
|
||||
$data = $pdf->getParsedData();
|
||||
// release some memory
|
||||
unset($rawdata);
|
||||
|
||||
// ...
|
||||
|
||||
|
||||
print_r($data); // DEBUG
|
||||
|
||||
|
||||
unset($pdf);
|
||||
}
|
||||
|
||||
} // END OF CLASS
|
||||
|
||||
//============================================================+
|
||||
// END OF FILE
|
||||
//============================================================+
|
||||
@@ -1,815 +0,0 @@
|
||||
<?php
|
||||
//============================================================+
|
||||
// File name : tcpdf_parser.php
|
||||
// Version : 1.0.16
|
||||
// Begin : 2011-05-23
|
||||
// Last Update : 2015-04-28
|
||||
// Author : Nicola Asuni - Tecnick.com LTD - www.tecnick.com - info@tecnick.com
|
||||
// License : http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT GNU-LGPLv3
|
||||
// -------------------------------------------------------------------
|
||||
// Copyright (C) 2011-2015 Nicola Asuni - Tecnick.com LTD
|
||||
//
|
||||
// This file is part of TCPDF software library.
|
||||
//
|
||||
// TCPDF is free software: you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// TCPDF is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
// See the GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the License
|
||||
// along with TCPDF. If not, see
|
||||
// <http://www.tecnick.com/pagefiles/tcpdf/LICENSE.TXT>.
|
||||
//
|
||||
// See LICENSE.TXT file for more information.
|
||||
// -------------------------------------------------------------------
|
||||
//
|
||||
// Description : This is a PHP class for parsing PDF documents.
|
||||
//
|
||||
//============================================================+
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This is a PHP class for parsing PDF documents.<br>
|
||||
* @package com.tecnick.tcpdf
|
||||
* @author Nicola Asuni
|
||||
* @version 1.0.15
|
||||
*/
|
||||
|
||||
// include class for decoding filters
|
||||
require_once(dirname(__FILE__).'/include/tcpdf_filters.php');
|
||||
|
||||
/**
|
||||
* @class TCPDF_PARSER
|
||||
* This is a PHP class for parsing PDF documents.<br>
|
||||
* @package com.tecnick.tcpdf
|
||||
* @brief This is a PHP class for parsing PDF documents..
|
||||
* @version 1.0.15
|
||||
* @author Nicola Asuni - info@tecnick.com
|
||||
*/
|
||||
class TCPDF_PARSER {
|
||||
|
||||
/**
|
||||
* Raw content of the PDF document.
|
||||
* @private
|
||||
*/
|
||||
private $pdfdata = '';
|
||||
|
||||
/**
|
||||
* XREF data.
|
||||
* @protected
|
||||
*/
|
||||
protected $xref = array();
|
||||
|
||||
/**
|
||||
* Array of PDF objects.
|
||||
* @protected
|
||||
*/
|
||||
protected $objects = array();
|
||||
|
||||
/**
|
||||
* Class object for decoding filters.
|
||||
* @private
|
||||
*/
|
||||
private $FilterDecoders;
|
||||
|
||||
/**
|
||||
* Array of configuration parameters.
|
||||
* @private
|
||||
*/
|
||||
private $cfg = array(
|
||||
'die_for_errors' => false,
|
||||
'ignore_filter_decoding_errors' => true,
|
||||
'ignore_missing_filter_decoders' => true,
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Parse a PDF document an return an array of objects.
|
||||
* @param string $data PDF data to parse.
|
||||
* @param array $cfg Array of configuration parameters:
|
||||
* 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception;
|
||||
* 'ignore_filter_decoding_errors' : if true ignore filter decoding errors;
|
||||
* 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors.
|
||||
* @public
|
||||
* @since 1.0.000 (2011-05-24)
|
||||
*/
|
||||
public function __construct($data, $cfg=array()) {
|
||||
if (empty($data)) {
|
||||
$this->Error('Empty PDF data.');
|
||||
}
|
||||
// find the pdf header starting position
|
||||
if (($trimpos = strpos($data, '%PDF-')) === FALSE) {
|
||||
$this->Error('Invalid PDF data: missing %PDF header.');
|
||||
}
|
||||
// get PDF content string
|
||||
$this->pdfdata = substr($data, $trimpos);
|
||||
// get length
|
||||
$pdflen = strlen($this->pdfdata);
|
||||
// set configuration parameters
|
||||
$this->setConfig($cfg);
|
||||
// get xref and trailer data
|
||||
$this->xref = $this->getXrefData();
|
||||
// parse all document objects
|
||||
$this->objects = array();
|
||||
foreach ($this->xref['xref'] as $obj => $offset) {
|
||||
if (!isset($this->objects[$obj]) AND ($offset > 0)) {
|
||||
// decode objects with positive offset
|
||||
$this->objects[$obj] = $this->getIndirectObject($obj, $offset, true);
|
||||
}
|
||||
}
|
||||
// release some memory
|
||||
unset($this->pdfdata);
|
||||
$this->pdfdata = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration parameters.
|
||||
* @param array $cfg Array of configuration parameters:
|
||||
* 'die_for_errors' : if true termitate the program execution in case of error, otherwise thows an exception;
|
||||
* 'ignore_filter_decoding_errors' : if true ignore filter decoding errors;
|
||||
* 'ignore_missing_filter_decoders' : if true ignore missing filter decoding errors.
|
||||
* @public
|
||||
*/
|
||||
protected function setConfig($cfg) {
|
||||
if (isset($cfg['die_for_errors'])) {
|
||||
$this->cfg['die_for_errors'] = !!$cfg['die_for_errors'];
|
||||
}
|
||||
if (isset($cfg['ignore_filter_decoding_errors'])) {
|
||||
$this->cfg['ignore_filter_decoding_errors'] = !!$cfg['ignore_filter_decoding_errors'];
|
||||
}
|
||||
if (isset($cfg['ignore_missing_filter_decoders'])) {
|
||||
$this->cfg['ignore_missing_filter_decoders'] = !!$cfg['ignore_missing_filter_decoders'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of parsed PDF document objects.
|
||||
* @return array Array of parsed PDF document objects.
|
||||
* @public
|
||||
* @since 1.0.000 (2011-06-26)
|
||||
*/
|
||||
public function getParsedData() {
|
||||
return array($this->xref, $this->objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Cross-Reference (xref) table and trailer data from PDF document data.
|
||||
* @param int $offset xref offset (if know).
|
||||
* @param array $xref previous xref array (if any).
|
||||
* @return array containing xref and trailer data.
|
||||
* @protected
|
||||
* @since 1.0.000 (2011-05-24)
|
||||
*/
|
||||
protected function getXrefData($offset=0, $xref=array()) {
|
||||
if ($offset == 0) {
|
||||
// find last startxref
|
||||
if (preg_match_all('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_SET_ORDER, $offset) == 0) {
|
||||
$this->Error('Unable to find startxref');
|
||||
}
|
||||
$matches = array_pop($matches);
|
||||
$startxref = $matches[1];
|
||||
} elseif (strpos($this->pdfdata, 'xref', $offset) == $offset) {
|
||||
// Already pointing at the xref table
|
||||
$startxref = $offset;
|
||||
} elseif (preg_match('/([0-9]+[\s][0-9]+[\s]obj)/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) {
|
||||
// Cross-Reference Stream object
|
||||
$startxref = $offset;
|
||||
} elseif (preg_match('/[\r\n]startxref[\s]*[\r\n]+([0-9]+)[\s]*[\r\n]+%%EOF/i', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset)) {
|
||||
// startxref found
|
||||
$startxref = $matches[1][0];
|
||||
} else {
|
||||
$this->Error('Unable to find startxref');
|
||||
}
|
||||
// check xref position
|
||||
if (strpos($this->pdfdata, 'xref', $startxref) == $startxref) {
|
||||
// Cross-Reference
|
||||
$xref = $this->decodeXref($startxref, $xref);
|
||||
} else {
|
||||
// Cross-Reference Stream
|
||||
$xref = $this->decodeXrefStream($startxref, $xref);
|
||||
}
|
||||
if (empty($xref)) {
|
||||
$this->Error('Unable to find xref');
|
||||
}
|
||||
return $xref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the Cross-Reference section
|
||||
* @param int $startxref Offset at which the xref section starts (position of the 'xref' keyword).
|
||||
* @param array $xref Previous xref array (if any).
|
||||
* @return array containing xref and trailer data.
|
||||
* @protected
|
||||
* @since 1.0.000 (2011-06-20)
|
||||
*/
|
||||
protected function decodeXref($startxref, $xref=array()) {
|
||||
$startxref += 4; // 4 is the length of the word 'xref'
|
||||
// skip initial white space chars: \x00 null (NUL), \x09 horizontal tab (HT), \x0A line feed (LF), \x0C form feed (FF), \x0D carriage return (CR), \x20 space (SP)
|
||||
$offset = $startxref + strspn($this->pdfdata, "\x00\x09\x0a\x0c\x0d\x20", $startxref);
|
||||
// initialize object number
|
||||
$obj_num = 0;
|
||||
// search for cross-reference entries or subsection
|
||||
while (preg_match('/([0-9]+)[\x20]([0-9]+)[\x20]?([nf]?)(\r\n|[\x20]?[\r\n])/', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
|
||||
if ($matches[0][1] != $offset) {
|
||||
// we are on another section
|
||||
break;
|
||||
}
|
||||
$offset += strlen($matches[0][0]);
|
||||
if ($matches[3][0] == 'n') {
|
||||
// create unique object index: [object number]_[generation number]
|
||||
$index = $obj_num.'_'.intval($matches[2][0]);
|
||||
// check if object already exist
|
||||
if (!isset($xref['xref'][$index])) {
|
||||
// store object offset position
|
||||
$xref['xref'][$index] = intval($matches[1][0]);
|
||||
}
|
||||
++$obj_num;
|
||||
} elseif ($matches[3][0] == 'f') {
|
||||
++$obj_num;
|
||||
} else {
|
||||
// object number (index)
|
||||
$obj_num = intval($matches[1][0]);
|
||||
}
|
||||
}
|
||||
// get trailer data
|
||||
if (preg_match('/trailer[\s]*<<(.*)>>/isU', $this->pdfdata, $matches, PREG_OFFSET_CAPTURE, $offset) > 0) {
|
||||
$trailer_data = $matches[1][0];
|
||||
if (!isset($xref['trailer']) OR empty($xref['trailer'])) {
|
||||
// get only the last updated version
|
||||
$xref['trailer'] = array();
|
||||
// parse trailer_data
|
||||
if (preg_match('/Size[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) {
|
||||
$xref['trailer']['size'] = intval($matches[1]);
|
||||
}
|
||||
if (preg_match('/Root[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
|
||||
$xref['trailer']['root'] = intval($matches[1]).'_'.intval($matches[2]);
|
||||
}
|
||||
if (preg_match('/Encrypt[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
|
||||
$xref['trailer']['encrypt'] = intval($matches[1]).'_'.intval($matches[2]);
|
||||
}
|
||||
if (preg_match('/Info[\s]+([0-9]+)[\s]+([0-9]+)[\s]+R/i', $trailer_data, $matches) > 0) {
|
||||
$xref['trailer']['info'] = intval($matches[1]).'_'.intval($matches[2]);
|
||||
}
|
||||
if (preg_match('/ID[\s]*[\[][\s]*[<]([^>]*)[>][\s]*[<]([^>]*)[>]/i', $trailer_data, $matches) > 0) {
|
||||
$xref['trailer']['id'] = array();
|
||||
$xref['trailer']['id'][0] = $matches[1];
|
||||
$xref['trailer']['id'][1] = $matches[2];
|
||||
}
|
||||
}
|
||||
if (preg_match('/Prev[\s]+([0-9]+)/i', $trailer_data, $matches) > 0) {
|
||||
// get previous xref
|
||||
$xref = $this->getXrefData(intval($matches[1]), $xref);
|
||||
}
|
||||
} else {
|
||||
$this->Error('Unable to find trailer');
|
||||
}
|
||||
return $xref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the Cross-Reference Stream section
|
||||
* @param int $startxref Offset at which the xref section starts.
|
||||
* @param array $xref Previous xref array (if any).
|
||||
* @return array containing xref and trailer data.
|
||||
* @protected
|
||||
* @since 1.0.003 (2013-03-16)
|
||||
*/
|
||||
protected function decodeXrefStream($startxref, $xref=array()) {
|
||||
// try to read Cross-Reference Stream
|
||||
$xrefobj = $this->getRawObject($startxref);
|
||||
$xrefcrs = $this->getIndirectObject($xrefobj[1], $startxref, true);
|
||||
if (!isset($xref['trailer']) OR empty($xref['trailer'])) {
|
||||
// get only the last updated version
|
||||
$xref['trailer'] = array();
|
||||
$filltrailer = true;
|
||||
} else {
|
||||
$filltrailer = false;
|
||||
}
|
||||
if (!isset($xref['xref'])) {
|
||||
$xref['xref'] = array();
|
||||
}
|
||||
$valid_crs = false;
|
||||
$columns = 0;
|
||||
$sarr = $xrefcrs[0][1];
|
||||
if (!is_array($sarr)) {
|
||||
$sarr = array();
|
||||
}
|
||||
foreach ($sarr as $k => $v) {
|
||||
if (($v[0] == '/') AND ($v[1] == 'Type') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == '/') AND ($sarr[($k +1)][1] == 'XRef'))) {
|
||||
$valid_crs = true;
|
||||
} elseif (($v[0] == '/') AND ($v[1] == 'Index') AND (isset($sarr[($k +1)]))) {
|
||||
// first object number in the subsection
|
||||
$index_first = intval($sarr[($k +1)][1][0][1]);
|
||||
// number of entries in the subsection
|
||||
$index_entries = intval($sarr[($k +1)][1][1][1]);
|
||||
} elseif (($v[0] == '/') AND ($v[1] == 'Prev') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'numeric'))) {
|
||||
// get previous xref offset
|
||||
$prevxref = intval($sarr[($k +1)][1]);
|
||||
} elseif (($v[0] == '/') AND ($v[1] == 'W') AND (isset($sarr[($k +1)]))) {
|
||||
// number of bytes (in the decoded stream) of the corresponding field
|
||||
$wb = array();
|
||||
$wb[0] = intval($sarr[($k +1)][1][0][1]);
|
||||
$wb[1] = intval($sarr[($k +1)][1][1][1]);
|
||||
$wb[2] = intval($sarr[($k +1)][1][2][1]);
|
||||
} elseif (($v[0] == '/') AND ($v[1] == 'DecodeParms') AND (isset($sarr[($k +1)][1]))) {
|
||||
$decpar = $sarr[($k +1)][1];
|
||||
foreach ($decpar as $kdc => $vdc) {
|
||||
if (($vdc[0] == '/') AND ($vdc[1] == 'Columns') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] == 'numeric'))) {
|
||||
$columns = intval($decpar[($kdc +1)][1]);
|
||||
} elseif (($vdc[0] == '/') AND ($vdc[1] == 'Predictor') AND (isset($decpar[($kdc +1)]) AND ($decpar[($kdc +1)][0] == 'numeric'))) {
|
||||
$predictor = intval($decpar[($kdc +1)][1]);
|
||||
}
|
||||
}
|
||||
} elseif ($filltrailer) {
|
||||
if (($v[0] == '/') AND ($v[1] == 'Size') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'numeric'))) {
|
||||
$xref['trailer']['size'] = $sarr[($k +1)][1];
|
||||
} elseif (($v[0] == '/') AND ($v[1] == 'Root') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) {
|
||||
$xref['trailer']['root'] = $sarr[($k +1)][1];
|
||||
} elseif (($v[0] == '/') AND ($v[1] == 'Info') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) {
|
||||
$xref['trailer']['info'] = $sarr[($k +1)][1];
|
||||
} elseif (($v[0] == '/') AND ($v[1] == 'Encrypt') AND (isset($sarr[($k +1)]) AND ($sarr[($k +1)][0] == 'objref'))) {
|
||||
$xref['trailer']['encrypt'] = $sarr[($k +1)][1];
|
||||
} elseif (($v[0] == '/') AND ($v[1] == 'ID') AND (isset($sarr[($k +1)]))) {
|
||||
$xref['trailer']['id'] = array();
|
||||
$xref['trailer']['id'][0] = $sarr[($k +1)][1][0][1];
|
||||
$xref['trailer']['id'][1] = $sarr[($k +1)][1][1][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
// decode data
|
||||
if ($valid_crs AND isset($xrefcrs[1][3][0])) {
|
||||
// number of bytes in a row
|
||||
$rowlen = ($columns + 1);
|
||||
// convert the stream into an array of integers
|
||||
$sdata = unpack('C*', $xrefcrs[1][3][0]);
|
||||
// split the rows
|
||||
$sdata = array_chunk($sdata, $rowlen);
|
||||
// initialize decoded array
|
||||
$ddata = array();
|
||||
// initialize first row with zeros
|
||||
$prev_row = array_fill (0, $rowlen, 0);
|
||||
// for each row apply PNG unpredictor
|
||||
foreach ($sdata as $k => $row) {
|
||||
// initialize new row
|
||||
$ddata[$k] = array();
|
||||
// get PNG predictor value
|
||||
$predictor = (10 + $row[0]);
|
||||
// for each byte on the row
|
||||
for ($i=1; $i<=$columns; ++$i) {
|
||||
// new index
|
||||
$j = ($i - 1);
|
||||
$row_up = $prev_row[$j];
|
||||
if ($i == 1) {
|
||||
$row_left = 0;
|
||||
$row_upleft = 0;
|
||||
} else {
|
||||
$row_left = $row[($i - 1)];
|
||||
$row_upleft = $prev_row[($j - 1)];
|
||||
}
|
||||
switch ($predictor) {
|
||||
case 10: { // PNG prediction (on encoding, PNG None on all rows)
|
||||
$ddata[$k][$j] = $row[$i];
|
||||
break;
|
||||
}
|
||||
case 11: { // PNG prediction (on encoding, PNG Sub on all rows)
|
||||
$ddata[$k][$j] = (($row[$i] + $row_left) & 0xff);
|
||||
break;
|
||||
}
|
||||
case 12: { // PNG prediction (on encoding, PNG Up on all rows)
|
||||
$ddata[$k][$j] = (($row[$i] + $row_up) & 0xff);
|
||||
break;
|
||||
}
|
||||
case 13: { // PNG prediction (on encoding, PNG Average on all rows)
|
||||
$ddata[$k][$j] = (($row[$i] + (($row_left + $row_up) / 2)) & 0xff);
|
||||
break;
|
||||
}
|
||||
case 14: { // PNG prediction (on encoding, PNG Paeth on all rows)
|
||||
// initial estimate
|
||||
$p = ($row_left + $row_up - $row_upleft);
|
||||
// distances
|
||||
$pa = abs($p - $row_left);
|
||||
$pb = abs($p - $row_up);
|
||||
$pc = abs($p - $row_upleft);
|
||||
$pmin = min($pa, $pb, $pc);
|
||||
// return minimum distance
|
||||
switch ($pmin) {
|
||||
case $pa: {
|
||||
$ddata[$k][$j] = (($row[$i] + $row_left) & 0xff);
|
||||
break;
|
||||
}
|
||||
case $pb: {
|
||||
$ddata[$k][$j] = (($row[$i] + $row_up) & 0xff);
|
||||
break;
|
||||
}
|
||||
case $pc: {
|
||||
$ddata[$k][$j] = (($row[$i] + $row_upleft) & 0xff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: { // PNG prediction (on encoding, PNG optimum)
|
||||
$this->Error('Unknown PNG predictor');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$prev_row = $ddata[$k];
|
||||
} // end for each row
|
||||
// complete decoding
|
||||
$sdata = array();
|
||||
// for every row
|
||||
foreach ($ddata as $k => $row) {
|
||||
// initialize new row
|
||||
$sdata[$k] = array(0, 0, 0);
|
||||
if ($wb[0] == 0) {
|
||||
// default type field
|
||||
$sdata[$k][0] = 1;
|
||||
}
|
||||
$i = 0; // count bytes in the row
|
||||
// for every column
|
||||
for ($c = 0; $c < 3; ++$c) {
|
||||
// for every byte on the column
|
||||
for ($b = 0; $b < $wb[$c]; ++$b) {
|
||||
if (isset($row[$i])) {
|
||||
$sdata[$k][$c] += ($row[$i] << (($wb[$c] - 1 - $b) * 8));
|
||||
}
|
||||
++$i;
|
||||
}
|
||||
}
|
||||
}
|
||||
$ddata = array();
|
||||
// fill xref
|
||||
if (isset($index_first)) {
|
||||
$obj_num = $index_first;
|
||||
} else {
|
||||
$obj_num = 0;
|
||||
}
|
||||
foreach ($sdata as $k => $row) {
|
||||
switch ($row[0]) {
|
||||
case 0: { // (f) linked list of free objects
|
||||
break;
|
||||
}
|
||||
case 1: { // (n) objects that are in use but are not compressed
|
||||
// create unique object index: [object number]_[generation number]
|
||||
$index = $obj_num.'_'.$row[2];
|
||||
// check if object already exist
|
||||
if (!isset($xref['xref'][$index])) {
|
||||
// store object offset position
|
||||
$xref['xref'][$index] = $row[1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: { // compressed objects
|
||||
// $row[1] = object number of the object stream in which this object is stored
|
||||
// $row[2] = index of this object within the object stream
|
||||
$index = $row[1].'_0_'.$row[2];
|
||||
$xref['xref'][$index] = -1;
|
||||
break;
|
||||
}
|
||||
default: { // null objects
|
||||
break;
|
||||
}
|
||||
}
|
||||
++$obj_num;
|
||||
}
|
||||
} // end decoding data
|
||||
if (isset($prevxref)) {
|
||||
// get previous xref
|
||||
$xref = $this->getXrefData($prevxref, $xref);
|
||||
}
|
||||
return $xref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get object type, raw value and offset to next object
|
||||
* @param int $offset Object offset.
|
||||
* @return array containing object type, raw value and offset to next object
|
||||
* @protected
|
||||
* @since 1.0.000 (2011-06-20)
|
||||
*/
|
||||
protected function getRawObject($offset=0) {
|
||||
$objtype = ''; // object type to be returned
|
||||
$objval = ''; // object value to be returned
|
||||
// skip initial white space chars: \x00 null (NUL), \x09 horizontal tab (HT), \x0A line feed (LF), \x0C form feed (FF), \x0D carriage return (CR), \x20 space (SP)
|
||||
$offset += strspn($this->pdfdata, "\x00\x09\x0a\x0c\x0d\x20", $offset);
|
||||
// get first char
|
||||
$char = $this->pdfdata[$offset];
|
||||
// get object type
|
||||
switch ($char) {
|
||||
case '%': { // \x25 PERCENT SIGN
|
||||
// skip comment and search for next token
|
||||
$next = strcspn($this->pdfdata, "\r\n", $offset);
|
||||
if ($next > 0) {
|
||||
$offset += $next;
|
||||
return $this->getRawObject($offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '/': { // \x2F SOLIDUS
|
||||
// name object
|
||||
$objtype = $char;
|
||||
++$offset;
|
||||
if (preg_match('/^([^\x00\x09\x0a\x0c\x0d\x20\s\x28\x29\x3c\x3e\x5b\x5d\x7b\x7d\x2f\x25]+)/', substr($this->pdfdata, $offset, 256), $matches) == 1) {
|
||||
$objval = $matches[1]; // unescaped value
|
||||
$offset += strlen($objval);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '(': // \x28 LEFT PARENTHESIS
|
||||
case ')': { // \x29 RIGHT PARENTHESIS
|
||||
// literal string object
|
||||
$objtype = $char;
|
||||
++$offset;
|
||||
$strpos = $offset;
|
||||
if ($char == '(') {
|
||||
$open_bracket = 1;
|
||||
while ($open_bracket > 0) {
|
||||
if (!isset($this->pdfdata[$strpos])) {
|
||||
break;
|
||||
}
|
||||
$ch = $this->pdfdata[$strpos];
|
||||
switch ($ch) {
|
||||
case '\\': { // REVERSE SOLIDUS (5Ch) (Backslash)
|
||||
// skip next character
|
||||
++$strpos;
|
||||
break;
|
||||
}
|
||||
case '(': { // LEFT PARENHESIS (28h)
|
||||
++$open_bracket;
|
||||
break;
|
||||
}
|
||||
case ')': { // RIGHT PARENTHESIS (29h)
|
||||
--$open_bracket;
|
||||
break;
|
||||
}
|
||||
}
|
||||
++$strpos;
|
||||
}
|
||||
$objval = substr($this->pdfdata, $offset, ($strpos - $offset - 1));
|
||||
$offset = $strpos;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '[': // \x5B LEFT SQUARE BRACKET
|
||||
case ']': { // \x5D RIGHT SQUARE BRACKET
|
||||
// array object
|
||||
$objtype = $char;
|
||||
++$offset;
|
||||
if ($char == '[') {
|
||||
// get array content
|
||||
$objval = array();
|
||||
do {
|
||||
// get element
|
||||
$element = $this->getRawObject($offset);
|
||||
$offset = $element[2];
|
||||
$objval[] = $element;
|
||||
} while ($element[0] != ']');
|
||||
// remove closing delimiter
|
||||
array_pop($objval);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '<': // \x3C LESS-THAN SIGN
|
||||
case '>': { // \x3E GREATER-THAN SIGN
|
||||
if (isset($this->pdfdata[($offset + 1)]) AND ($this->pdfdata[($offset + 1)] == $char)) {
|
||||
// dictionary object
|
||||
$objtype = $char.$char;
|
||||
$offset += 2;
|
||||
if ($char == '<') {
|
||||
// get array content
|
||||
$objval = array();
|
||||
do {
|
||||
// get element
|
||||
$element = $this->getRawObject($offset);
|
||||
$offset = $element[2];
|
||||
$objval[] = $element;
|
||||
} while ($element[0] != '>>');
|
||||
// remove closing delimiter
|
||||
array_pop($objval);
|
||||
}
|
||||
} else {
|
||||
// hexadecimal string object
|
||||
$objtype = $char;
|
||||
++$offset;
|
||||
if (($char == '<') AND (preg_match('/^([0-9A-Fa-f\x09\x0a\x0c\x0d\x20]+)>/iU', substr($this->pdfdata, $offset), $matches) == 1)) {
|
||||
// remove white space characters
|
||||
$objval = strtr($matches[1], "\x09\x0a\x0c\x0d\x20", '');
|
||||
$offset += strlen($matches[0]);
|
||||
} elseif (($endpos = strpos($this->pdfdata, '>', $offset)) !== FALSE) {
|
||||
$offset = $endpos + 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (substr($this->pdfdata, $offset, 6) == 'endobj') {
|
||||
// indirect object
|
||||
$objtype = 'endobj';
|
||||
$offset += 6;
|
||||
} elseif (substr($this->pdfdata, $offset, 4) == 'null') {
|
||||
// null object
|
||||
$objtype = 'null';
|
||||
$offset += 4;
|
||||
$objval = 'null';
|
||||
} elseif (substr($this->pdfdata, $offset, 4) == 'true') {
|
||||
// boolean true object
|
||||
$objtype = 'boolean';
|
||||
$offset += 4;
|
||||
$objval = 'true';
|
||||
} elseif (substr($this->pdfdata, $offset, 5) == 'false') {
|
||||
// boolean false object
|
||||
$objtype = 'boolean';
|
||||
$offset += 5;
|
||||
$objval = 'false';
|
||||
} elseif (substr($this->pdfdata, $offset, 6) == 'stream') {
|
||||
// start stream object
|
||||
$objtype = 'stream';
|
||||
$offset += 6;
|
||||
if (preg_match('/^([\r]?[\n])/isU', substr($this->pdfdata, $offset), $matches) == 1) {
|
||||
$offset += strlen($matches[0]);
|
||||
if (preg_match('/(endstream)[\x09\x0a\x0c\x0d\x20]/isU', substr($this->pdfdata, $offset), $matches, PREG_OFFSET_CAPTURE) == 1) {
|
||||
$objval = substr($this->pdfdata, $offset, $matches[0][1]);
|
||||
$offset += $matches[1][1];
|
||||
}
|
||||
}
|
||||
} elseif (substr($this->pdfdata, $offset, 9) == 'endstream') {
|
||||
// end stream object
|
||||
$objtype = 'endstream';
|
||||
$offset += 9;
|
||||
} elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+R/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
|
||||
// indirect object reference
|
||||
$objtype = 'objref';
|
||||
$offset += strlen($matches[0]);
|
||||
$objval = intval($matches[1]).'_'.intval($matches[2]);
|
||||
} elseif (preg_match('/^([0-9]+)[\s]+([0-9]+)[\s]+obj/iU', substr($this->pdfdata, $offset, 33), $matches) == 1) {
|
||||
// object start
|
||||
$objtype = 'obj';
|
||||
$objval = intval($matches[1]).'_'.intval($matches[2]);
|
||||
$offset += strlen ($matches[0]);
|
||||
} elseif (($numlen = strspn($this->pdfdata, '+-.0123456789', $offset)) > 0) {
|
||||
// numeric object
|
||||
$objtype = 'numeric';
|
||||
$objval = substr($this->pdfdata, $offset, $numlen);
|
||||
$offset += $numlen;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array($objtype, $objval, $offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content of indirect object.
|
||||
* @param string $obj_ref Object number and generation number separated by underscore character.
|
||||
* @param int $offset Object offset.
|
||||
* @param boolean $decoding If true decode streams.
|
||||
* @return array containing object data.
|
||||
* @protected
|
||||
* @since 1.0.000 (2011-05-24)
|
||||
*/
|
||||
protected function getIndirectObject($obj_ref, $offset=0, $decoding=true) {
|
||||
$obj = explode('_', $obj_ref);
|
||||
if (($obj === false) OR (count($obj) != 2)) {
|
||||
$this->Error('Invalid object reference: '.$obj);
|
||||
return;
|
||||
}
|
||||
$objref = $obj[0].' '.$obj[1].' obj';
|
||||
// ignore leading zeros
|
||||
$offset += strspn($this->pdfdata, '0', $offset);
|
||||
if (strpos($this->pdfdata, $objref, $offset) != $offset) {
|
||||
// an indirect reference to an undefined object shall be considered a reference to the null object
|
||||
return array('null', 'null', $offset);
|
||||
}
|
||||
// starting position of object content
|
||||
$offset += strlen($objref);
|
||||
// get array of object content
|
||||
$objdata = array();
|
||||
$i = 0; // object main index
|
||||
do {
|
||||
$oldoffset = $offset;
|
||||
// get element
|
||||
$element = $this->getRawObject($offset);
|
||||
$offset = $element[2];
|
||||
// decode stream using stream's dictionary information
|
||||
if ($decoding AND ($element[0] == 'stream') AND (isset($objdata[($i - 1)][0])) AND ($objdata[($i - 1)][0] == '<<')) {
|
||||
$element[3] = $this->decodeStream($objdata[($i - 1)][1], $element[1]);
|
||||
}
|
||||
$objdata[$i] = $element;
|
||||
++$i;
|
||||
} while (($element[0] != 'endobj') AND ($offset != $oldoffset));
|
||||
// remove closing delimiter
|
||||
array_pop($objdata);
|
||||
// return raw object content
|
||||
return $objdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content of object, resolving indect object reference if necessary.
|
||||
* @param string $obj Object value.
|
||||
* @return array containing object data.
|
||||
* @protected
|
||||
* @since 1.0.000 (2011-06-26)
|
||||
*/
|
||||
protected function getObjectVal($obj) {
|
||||
if ($obj[0] == 'objref') {
|
||||
// reference to indirect object
|
||||
if (isset($this->objects[$obj[1]])) {
|
||||
// this object has been already parsed
|
||||
return $this->objects[$obj[1]];
|
||||
} elseif (isset($this->xref[$obj[1]])) {
|
||||
// parse new object
|
||||
$this->objects[$obj[1]] = $this->getIndirectObject($obj[1], $this->xref[$obj[1]], false);
|
||||
return $this->objects[$obj[1]];
|
||||
}
|
||||
}
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the specified stream.
|
||||
* @param array $sdic Stream's dictionary array.
|
||||
* @param string $stream Stream to decode.
|
||||
* @return array containing decoded stream data and remaining filters.
|
||||
* @protected
|
||||
* @since 1.0.000 (2011-06-22)
|
||||
*/
|
||||
protected function decodeStream($sdic, $stream) {
|
||||
// get stream length and filters
|
||||
$slength = strlen($stream);
|
||||
if ($slength <= 0) {
|
||||
return array('', array());
|
||||
}
|
||||
$filters = array();
|
||||
foreach ($sdic as $k => $v) {
|
||||
if ($v[0] == '/') {
|
||||
if (($v[1] == 'Length') AND (isset($sdic[($k + 1)])) AND ($sdic[($k + 1)][0] == 'numeric')) {
|
||||
// get declared stream length
|
||||
$declength = intval($sdic[($k + 1)][1]);
|
||||
if ($declength < $slength) {
|
||||
$stream = substr($stream, 0, $declength);
|
||||
$slength = $declength;
|
||||
}
|
||||
} elseif (($v[1] == 'Filter') AND (isset($sdic[($k + 1)]))) {
|
||||
// resolve indirect object
|
||||
$objval = $this->getObjectVal($sdic[($k + 1)]);
|
||||
if ($objval[0] == '/') {
|
||||
// single filter
|
||||
$filters[] = $objval[1];
|
||||
} elseif ($objval[0] == '[') {
|
||||
// array of filters
|
||||
foreach ($objval[1] as $flt) {
|
||||
if ($flt[0] == '/') {
|
||||
$filters[] = $flt[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// decode the stream
|
||||
$remaining_filters = array();
|
||||
foreach ($filters as $filter) {
|
||||
if (in_array($filter, TCPDF_FILTERS::getAvailableFilters())) {
|
||||
try {
|
||||
$stream = TCPDF_FILTERS::decodeFilter($filter, $stream);
|
||||
} catch (Exception $e) {
|
||||
$emsg = $e->getMessage();
|
||||
if ((($emsg[0] == '~') AND !$this->cfg['ignore_missing_filter_decoders'])
|
||||
OR (($emsg[0] != '~') AND !$this->cfg['ignore_filter_decoding_errors'])) {
|
||||
$this->Error($e->getMessage());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// add missing filter to array
|
||||
$remaining_filters[] = $filter;
|
||||
}
|
||||
}
|
||||
return array($stream, $remaining_filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an exception or print an error message and die if the K_TCPDF_PARSER_THROW_EXCEPTION_ERROR constant is set to true.
|
||||
* @param string $msg The error message
|
||||
* @public
|
||||
* @since 1.0.000 (2011-05-23)
|
||||
*/
|
||||
public function Error($msg) {
|
||||
if ($this->cfg['die_for_errors']) {
|
||||
die('<strong>TCPDF_PARSER ERROR: </strong>'.$msg);
|
||||
} else {
|
||||
throw new Exception('TCPDF_PARSER ERROR: '.$msg);
|
||||
}
|
||||
}
|
||||
|
||||
} // END OF TCPDF_PARSER CLASS
|
||||
|
||||
//============================================================+
|
||||
// END OF FILE
|
||||
//============================================================+
|
||||
0
lib/tecnickcom/tcpdf/tools/tcpdf_addfont.php
Normal file → Executable file
0
lib/tecnickcom/tcpdf/tools/tcpdf_addfont.php
Normal file → Executable file
@@ -1,4 +1,66 @@
|
||||
# 3.16.0 (2024-XX-XX)
|
||||
# 3.21.1 (2025-05-03)
|
||||
|
||||
* Fix ExtensionSet usage of BinaryOperatorExpressionParser
|
||||
|
||||
# 3.21.0 (2025-05-02)
|
||||
|
||||
* Fix wrong array index
|
||||
* Deprecate `Template::loadTemplate()`
|
||||
* Fix testing and expression when it evaluates to an instance of `Markup`
|
||||
* Add `ReturnPrimitiveTypeInterface` (and sub-interfaces for number, boolean, string, and array)
|
||||
* Add `SupportDefinedTestInterface` for expression nodes supporting the `defined` test
|
||||
* Deprecate using the `|` operator in an expression with `+` or `-` without using parentheses to clarify precedence
|
||||
* Deprecate operator precedence outside of the [0, 512] range
|
||||
* Introduce expression parser classes to describe operators and operands provided by extensions
|
||||
instead of arrays (it comes with many deprecations that are documented in
|
||||
the ``deprecated`` documentation chapter)
|
||||
* Deprecate the `Twig\ExpressionParser`, and `Twig\OperatorPrecedenceChange` classes
|
||||
* Add attributes `AsTwigFilter`, `AsTwigFunction`, and `AsTwigTest` to ease extension development
|
||||
|
||||
# 3.20.0 (2025-02-13)
|
||||
|
||||
* Fix support for ignoring syntax errors in an undefined handler in guard
|
||||
* Add configuration for Commonmark
|
||||
* Fix wrong array index
|
||||
* Bump minimum PHP version to 8.1
|
||||
* Add support for registering callbacks for undefined functions, filters or token parsers in the IntegrationTestCase
|
||||
* Use correct line number for `ForElseNode`
|
||||
* Fix timezone conversion on strings
|
||||
|
||||
# 3.19.0 (2025-01-28)
|
||||
|
||||
* Fix a security issue where escaping was missing when using `??`
|
||||
* Deprecate `Token::getType()`, use `Token::test()` instead
|
||||
* Add `Token::toEnglish()`
|
||||
* Add `ForElseNode`
|
||||
* Deprecate `Twig\ExpressionParser::parseOnlyArguments()` and
|
||||
`Twig\ExpressionParser::parseArguments()` (use
|
||||
`Twig\ExpressionParser::parseNamedArguments()` instead)
|
||||
* Fix `constant()` behavior when used with `??`
|
||||
* Add the `invoke` filter
|
||||
* Make `{}` optional for the `types` tag
|
||||
* Add `LastModifiedExtensionInterface` and implementation in `AbstractExtension` to track modification of runtime classes
|
||||
* Ignore static properties when using the dot operator
|
||||
|
||||
# 3.18.0 (2024-12-29)
|
||||
|
||||
* Fix unary operator precedence change
|
||||
* Ignore `SyntaxError` exceptions from undefined handlers when using the `guard` tag
|
||||
* Add a way to stream template rendering (`TemplateWrapper::stream()` and `TemplateWrapper::streamBlock()`)
|
||||
|
||||
# 3.17.1 (2024-12-12)
|
||||
|
||||
* Fix the null coalescing operator when the test returns null
|
||||
* Fix the Elvis operator when used as '? :' instead of '?:'
|
||||
* Support for invoking closures
|
||||
|
||||
# 3.17.0 (2024-12-10)
|
||||
|
||||
* Fix ArrayAccess with objects as keys
|
||||
* Support underscores in number literals
|
||||
* Deprecate `ConditionalExpression` and `NullCoalesceExpression` (use `ConditionalTernary` and `NullCoalesceBinary` instead)
|
||||
|
||||
# 3.16.0 (2024-11-29)
|
||||
|
||||
* Deprecate `InlinePrint`
|
||||
* Fix having macro variables starting with an underscore
|
||||
@@ -6,7 +68,7 @@
|
||||
* Deprecate returning `null` from `TwigFilter::getSafe()` and `TwigFunction::getSafe()`, return `[]` instead
|
||||
|
||||
# 3.15.0 (2024-11-17)
|
||||
|
||||
|
||||
* [BC BREAK] Add support for accessing class constants with the dot operator;
|
||||
this can be a BC break if you don't use UPPERCASE constant names
|
||||
* Add Spanish inflector support for the `plural` and `singular` filters in the String extension
|
||||
|
||||
@@ -24,11 +24,10 @@
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=8.0.2",
|
||||
"php": ">=8.1.0",
|
||||
"symfony/deprecation-contracts": "^2.5|^3",
|
||||
"symfony/polyfill-mbstring": "^1.3",
|
||||
"symfony/polyfill-ctype": "^1.8",
|
||||
"symfony/polyfill-php81": "^1.29"
|
||||
"symfony/polyfill-ctype": "^1.8"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0",
|
||||
|
||||
@@ -6,12 +6,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Extension/CoreExtension.php
|
||||
|
||||
- # Avoid BC-break
|
||||
message: '#^Constructor of class Twig\\Node\\ForNode has an unused parameter \$ifexpr\.$#'
|
||||
identifier: constructor.unusedParameter
|
||||
count: 1
|
||||
path: src/Node/ForNode.php
|
||||
|
||||
- # 2 parameters will be required
|
||||
message: '#^Method Twig\\Node\\IncludeNode\:\:addGetTemplate\(\) invoked with 2 parameters, 1 required\.$#'
|
||||
identifier: arguments.count
|
||||
@@ -23,3 +17,9 @@ parameters:
|
||||
identifier: parameter.phpDocType
|
||||
count: 5
|
||||
path: src/Node/Node.php
|
||||
|
||||
- # Adding 0 to the string representation of a number is valid and what we want here
|
||||
message: '#^Binary operation "\+" between 0 and string results in an error\.$#'
|
||||
identifier: binaryOp.invalid
|
||||
count: 1
|
||||
path: src/Lexer.php
|
||||
|
||||
@@ -79,6 +79,9 @@ abstract class AbstractTwigCallable implements TwigCallableInterface
|
||||
return $this->dynamicName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return callable|array{class-string, string}|null
|
||||
*/
|
||||
public function getCallable()
|
||||
{
|
||||
return $this->callable;
|
||||
|
||||
56
lib/twig/twig/src/Attribute/AsTwigFilter.php
Normal file
56
lib/twig/twig/src/Attribute/AsTwigFilter.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Attribute;
|
||||
|
||||
use Twig\DeprecatedCallableInfo;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
/**
|
||||
* Registers a method as template filter.
|
||||
*
|
||||
* If the first argument of the method has Twig\Environment type-hint, the filter will receive the current environment.
|
||||
* Additional arguments of the method come from the filter call.
|
||||
*
|
||||
* #[AsTwigFilter(name: 'foo')]
|
||||
* function fooFilter(Environment $env, $string, $arg1 = null, ...) { ... }
|
||||
*
|
||||
* {{ 'string'|foo(arg1) }}
|
||||
*
|
||||
* @see TwigFilter
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
final class AsTwigFilter
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $name The name of the filter in Twig.
|
||||
* @param bool|null $needsCharset Whether the filter needs the charset passed as the first argument.
|
||||
* @param bool|null $needsEnvironment Whether the filter needs the environment passed as the first argument, or after the charset.
|
||||
* @param bool|null $needsContext Whether the filter needs the context array passed as the first argument, or after the charset and the environment.
|
||||
* @param string[]|null $isSafe List of formats in which you want the raw output to be printed unescaped.
|
||||
* @param string|array|null $isSafeCallback Function called at compilation time to determine if the filter is safe.
|
||||
* @param string|null $preEscape Some filters may need to work on input that is already escaped or safe
|
||||
* @param string[]|null $preservesSafety Preserves the safety of the value that the filter is applied to.
|
||||
* @param DeprecatedCallableInfo|null $deprecationInfo Information about the deprecation
|
||||
*/
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public ?bool $needsCharset = null,
|
||||
public ?bool $needsEnvironment = null,
|
||||
public ?bool $needsContext = null,
|
||||
public ?array $isSafe = null,
|
||||
public string|array|null $isSafeCallback = null,
|
||||
public ?string $preEscape = null,
|
||||
public ?array $preservesSafety = null,
|
||||
public ?DeprecatedCallableInfo $deprecationInfo = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
52
lib/twig/twig/src/Attribute/AsTwigFunction.php
Normal file
52
lib/twig/twig/src/Attribute/AsTwigFunction.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Attribute;
|
||||
|
||||
use Twig\DeprecatedCallableInfo;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
/**
|
||||
* Registers a method as template function.
|
||||
*
|
||||
* If the first argument of the method has Twig\Environment type-hint, the function will receive the current environment.
|
||||
* Additional arguments of the method come from the function call.
|
||||
*
|
||||
* #[AsTwigFunction(name: 'foo')]
|
||||
* function fooFunction(Environment $env, string $string, $arg1 = null, ...) { ... }
|
||||
*
|
||||
* {{ foo('string', arg1) }}
|
||||
*
|
||||
* @see TwigFunction
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
final class AsTwigFunction
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $name The name of the function in Twig.
|
||||
* @param bool|null $needsCharset Whether the function needs the charset passed as the first argument.
|
||||
* @param bool|null $needsEnvironment Whether the function needs the environment passed as the first argument, or after the charset.
|
||||
* @param bool|null $needsContext Whether the function needs the context array passed as the first argument, or after the charset and the environment.
|
||||
* @param string[]|null $isSafe List of formats in which you want the raw output to be printed unescaped.
|
||||
* @param string|array|null $isSafeCallback Function called at compilation time to determine if the function is safe.
|
||||
* @param DeprecatedCallableInfo|null $deprecationInfo Information about the deprecation
|
||||
*/
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public ?bool $needsCharset = null,
|
||||
public ?bool $needsEnvironment = null,
|
||||
public ?bool $needsContext = null,
|
||||
public ?array $isSafe = null,
|
||||
public string|array|null $isSafeCallback = null,
|
||||
public ?DeprecatedCallableInfo $deprecationInfo = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
48
lib/twig/twig/src/Attribute/AsTwigTest.php
Normal file
48
lib/twig/twig/src/Attribute/AsTwigTest.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\Attribute;
|
||||
|
||||
use Twig\DeprecatedCallableInfo;
|
||||
use Twig\TwigTest;
|
||||
|
||||
/**
|
||||
* Registers a method as template test.
|
||||
*
|
||||
* The first argument is the value to test and the other arguments are the
|
||||
* arguments passed to the test in the template.
|
||||
*
|
||||
* #[AsTwigTest(name: 'foo')]
|
||||
* public function fooTest($value, $arg1 = null) { ... }
|
||||
*
|
||||
* {% if value is foo(arg1) %}
|
||||
*
|
||||
* @see TwigTest
|
||||
*/
|
||||
#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)]
|
||||
final class AsTwigTest
|
||||
{
|
||||
/**
|
||||
* @param non-empty-string $name The name of the test in Twig.
|
||||
* @param bool|null $needsCharset Whether the test needs the charset passed as the first argument.
|
||||
* @param bool|null $needsEnvironment Whether the test needs the environment passed as the first argument, or after the charset.
|
||||
* @param bool|null $needsContext Whether the test needs the context array passed as the first argument, or after the charset and the environment.
|
||||
* @param DeprecatedCallableInfo|null $deprecationInfo Information about the deprecation
|
||||
*/
|
||||
public function __construct(
|
||||
public string $name,
|
||||
public ?bool $needsCharset = null,
|
||||
public ?bool $needsEnvironment = null,
|
||||
public ?bool $needsContext = null,
|
||||
public ?DeprecatedCallableInfo $deprecationInfo = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ class Compiler
|
||||
$node->compile($this);
|
||||
|
||||
if ($this->didUseEcho) {
|
||||
trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[\Twig\Attribute\YieldReady].', $this->didUseEcho, \get_class($node));
|
||||
trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[\Twig\Attribute\YieldReady].', $this->didUseEcho, $node::class);
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -99,7 +99,7 @@ class Compiler
|
||||
$node->compile($this);
|
||||
|
||||
if ($this->didUseEcho) {
|
||||
trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[\Twig\Attribute\YieldReady].', $this->didUseEcho, \get_class($node));
|
||||
trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[\Twig\Attribute\YieldReady].', $this->didUseEcho, $node::class);
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -170,7 +170,7 @@ class Compiler
|
||||
} elseif (\is_bool($value)) {
|
||||
$this->raw($value ? 'true' : 'false');
|
||||
} elseif (\is_array($value)) {
|
||||
$this->raw('array(');
|
||||
$this->raw('[');
|
||||
$first = true;
|
||||
foreach ($value as $key => $v) {
|
||||
if (!$first) {
|
||||
@@ -181,7 +181,7 @@ class Compiler
|
||||
$this->raw(' => ');
|
||||
$this->repr($v);
|
||||
}
|
||||
$this->raw(')');
|
||||
$this->raw(']');
|
||||
} else {
|
||||
$this->string($value);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use Twig\Error\Error;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Error\RuntimeError;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\ExpressionParser\ExpressionParsers;
|
||||
use Twig\Extension\CoreExtension;
|
||||
use Twig\Extension\EscaperExtension;
|
||||
use Twig\Extension\ExtensionInterface;
|
||||
@@ -27,8 +28,6 @@ use Twig\Extension\YieldNotReadyExtension;
|
||||
use Twig\Loader\ArrayLoader;
|
||||
use Twig\Loader\ChainLoader;
|
||||
use Twig\Loader\LoaderInterface;
|
||||
use Twig\Node\Expression\Binary\AbstractBinary;
|
||||
use Twig\Node\Expression\Unary\AbstractUnary;
|
||||
use Twig\Node\ModuleNode;
|
||||
use Twig\Node\Node;
|
||||
use Twig\NodeVisitor\NodeVisitorInterface;
|
||||
@@ -44,11 +43,11 @@ use Twig\TokenParser\TokenParserInterface;
|
||||
*/
|
||||
class Environment
|
||||
{
|
||||
public const VERSION = '3.16.0';
|
||||
public const VERSION_ID = 31600;
|
||||
public const VERSION = '3.21.1';
|
||||
public const VERSION_ID = 32101;
|
||||
public const MAJOR_VERSION = 3;
|
||||
public const MINOR_VERSION = 16;
|
||||
public const RELEASE_VERSION = 0;
|
||||
public const MINOR_VERSION = 21;
|
||||
public const RELEASE_VERSION = 1;
|
||||
public const EXTRA_VERSION = '';
|
||||
|
||||
private $charset;
|
||||
@@ -155,6 +154,8 @@ class Environment
|
||||
|
||||
/**
|
||||
* Enables debugging mode.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enableDebug()
|
||||
{
|
||||
@@ -164,6 +165,8 @@ class Environment
|
||||
|
||||
/**
|
||||
* Disables debugging mode.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disableDebug()
|
||||
{
|
||||
@@ -183,6 +186,8 @@ class Environment
|
||||
|
||||
/**
|
||||
* Enables the auto_reload option.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enableAutoReload()
|
||||
{
|
||||
@@ -191,6 +196,8 @@ class Environment
|
||||
|
||||
/**
|
||||
* Disables the auto_reload option.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disableAutoReload()
|
||||
{
|
||||
@@ -209,6 +216,8 @@ class Environment
|
||||
|
||||
/**
|
||||
* Enables the strict_variables option.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enableStrictVariables()
|
||||
{
|
||||
@@ -218,6 +227,8 @@ class Environment
|
||||
|
||||
/**
|
||||
* Disables the strict_variables option.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function disableStrictVariables()
|
||||
{
|
||||
@@ -267,6 +278,8 @@ class Environment
|
||||
* @param CacheInterface|string|false $cache A Twig\Cache\CacheInterface implementation,
|
||||
* an absolute path to the compiled templates,
|
||||
* or false to disable cache
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setCache($cache)
|
||||
{
|
||||
@@ -503,6 +516,9 @@ class Environment
|
||||
throw new LoaderError(\sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setLexer(Lexer $lexer)
|
||||
{
|
||||
$this->lexer = $lexer;
|
||||
@@ -520,6 +536,9 @@ class Environment
|
||||
return $this->lexer->tokenize($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setParser(Parser $parser)
|
||||
{
|
||||
$this->parser = $parser;
|
||||
@@ -539,6 +558,9 @@ class Environment
|
||||
return $this->parser->parse($stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setCompiler(Compiler $compiler)
|
||||
{
|
||||
$this->compiler = $compiler;
|
||||
@@ -573,6 +595,9 @@ class Environment
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setLoader(LoaderInterface $loader)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
@@ -583,6 +608,9 @@ class Environment
|
||||
return $this->loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function setCharset(string $charset)
|
||||
{
|
||||
if ('UTF8' === $charset = strtoupper($charset ?: '')) {
|
||||
@@ -603,6 +631,9 @@ class Environment
|
||||
return $this->extensionSet->hasExtension($class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addRuntimeLoader(RuntimeLoaderInterface $loader)
|
||||
{
|
||||
$this->runtimeLoaders[] = $loader;
|
||||
@@ -650,6 +681,9 @@ class Environment
|
||||
throw new RuntimeError(\sprintf('Unable to load the "%s" runtime.', $class));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addExtension(ExtensionInterface $extension)
|
||||
{
|
||||
$this->extensionSet->addExtension($extension);
|
||||
@@ -658,6 +692,8 @@ class Environment
|
||||
|
||||
/**
|
||||
* @param ExtensionInterface[] $extensions An array of extensions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setExtensions(array $extensions)
|
||||
{
|
||||
@@ -673,6 +709,9 @@ class Environment
|
||||
return $this->extensionSet->getExtensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addTokenParser(TokenParserInterface $parser)
|
||||
{
|
||||
$this->extensionSet->addTokenParser($parser);
|
||||
@@ -696,11 +735,17 @@ class Environment
|
||||
return $this->extensionSet->getTokenParser($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable(string): (TokenParserInterface|false) $callable
|
||||
*/
|
||||
public function registerUndefinedTokenParserCallback(callable $callable): void
|
||||
{
|
||||
$this->extensionSet->registerUndefinedTokenParserCallback($callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addNodeVisitor(NodeVisitorInterface $visitor)
|
||||
{
|
||||
$this->extensionSet->addNodeVisitor($visitor);
|
||||
@@ -716,6 +761,9 @@ class Environment
|
||||
return $this->extensionSet->getNodeVisitors();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addFilter(TwigFilter $filter)
|
||||
{
|
||||
$this->extensionSet->addFilter($filter);
|
||||
@@ -729,6 +777,9 @@ class Environment
|
||||
return $this->extensionSet->getFilter($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable(string): (TwigFilter|false) $callable
|
||||
*/
|
||||
public function registerUndefinedFilterCallback(callable $callable): void
|
||||
{
|
||||
$this->extensionSet->registerUndefinedFilterCallback($callable);
|
||||
@@ -750,6 +801,9 @@ class Environment
|
||||
return $this->extensionSet->getFilters();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addTest(TwigTest $test)
|
||||
{
|
||||
$this->extensionSet->addTest($test);
|
||||
@@ -773,6 +827,9 @@ class Environment
|
||||
return $this->extensionSet->getTest($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function addFunction(TwigFunction $function)
|
||||
{
|
||||
$this->extensionSet->addFunction($function);
|
||||
@@ -786,6 +843,9 @@ class Environment
|
||||
return $this->extensionSet->getFunction($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable(string): (TwigFunction|false) $callable
|
||||
*/
|
||||
public function registerUndefinedFunctionCallback(callable $callable): void
|
||||
{
|
||||
$this->extensionSet->registerUndefinedFunctionCallback($callable);
|
||||
@@ -814,6 +874,8 @@ class Environment
|
||||
* but after, you can only update existing globals.
|
||||
*
|
||||
* @param mixed $value The global value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addGlobal(string $name, $value)
|
||||
{
|
||||
@@ -862,22 +924,10 @@ class Environment
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @return array<string, array{precedence: int, class: class-string<AbstractUnary>}>
|
||||
*/
|
||||
public function getUnaryOperators(): array
|
||||
public function getExpressionParsers(): ExpressionParsers
|
||||
{
|
||||
return $this->extensionSet->getUnaryOperators();
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @return array<string, array{precedence: int, class: class-string<AbstractBinary>, associativity: ExpressionParser::OPERATOR_*}>
|
||||
*/
|
||||
public function getBinaryOperators(): array
|
||||
{
|
||||
return $this->extensionSet->getBinaryOperators();
|
||||
return $this->extensionSet->getExpressionParsers();
|
||||
}
|
||||
|
||||
private function updateOptionsHash(): void
|
||||
|
||||
@@ -29,20 +29,17 @@ use Twig\Template;
|
||||
* Whenever possible, you must set these information (original template name
|
||||
* and line number) yourself by passing them to the constructor. If some or all
|
||||
* these information are not available from where you throw the exception, then
|
||||
* this class will guess them automatically (when the line number is set to -1
|
||||
* and/or the name is set to null). As this is a costly operation, this
|
||||
* can be disabled by passing false for both the name and the line number
|
||||
* when creating a new instance of this class.
|
||||
* this class will guess them automatically.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Error extends \Exception
|
||||
{
|
||||
private $lineno;
|
||||
private $name;
|
||||
private $rawMessage;
|
||||
private $sourcePath;
|
||||
private $sourceCode;
|
||||
private ?Source $source;
|
||||
private string $phpFile;
|
||||
private int $phpLine;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -57,16 +54,10 @@ class Error extends \Exception
|
||||
{
|
||||
parent::__construct('', 0, $previous);
|
||||
|
||||
if (null === $source) {
|
||||
$name = null;
|
||||
} else {
|
||||
$name = $source->getName();
|
||||
$this->sourceCode = $source->getCode();
|
||||
$this->sourcePath = $source->getPath();
|
||||
}
|
||||
|
||||
$this->phpFile = $this->getFile();
|
||||
$this->phpLine = $this->getLine();
|
||||
$this->lineno = $lineno;
|
||||
$this->name = $name;
|
||||
$this->source = $source;
|
||||
$this->rawMessage = $message;
|
||||
$this->updateRepr();
|
||||
}
|
||||
@@ -84,30 +75,26 @@ class Error extends \Exception
|
||||
public function setTemplateLine(int $lineno): void
|
||||
{
|
||||
$this->lineno = $lineno;
|
||||
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
public function getSourceContext(): ?Source
|
||||
{
|
||||
return $this->name ? new Source($this->sourceCode, $this->name, $this->sourcePath) : null;
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
public function setSourceContext(?Source $source = null): void
|
||||
{
|
||||
if (null === $source) {
|
||||
$this->sourceCode = $this->name = $this->sourcePath = null;
|
||||
} else {
|
||||
$this->sourceCode = $source->getCode();
|
||||
$this->name = $source->getName();
|
||||
$this->sourcePath = $source->getPath();
|
||||
}
|
||||
|
||||
$this->source = $source;
|
||||
$this->updateRepr();
|
||||
}
|
||||
|
||||
public function guess(): void
|
||||
{
|
||||
if ($this->lineno > -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->guessTemplateInfo();
|
||||
$this->updateRepr();
|
||||
}
|
||||
@@ -120,82 +107,47 @@ class Error extends \Exception
|
||||
|
||||
private function updateRepr(): void
|
||||
{
|
||||
$this->message = $this->rawMessage;
|
||||
|
||||
if ($this->sourcePath && $this->lineno > 0) {
|
||||
$this->file = $this->sourcePath;
|
||||
$this->line = $this->lineno;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$dot = false;
|
||||
if (str_ends_with($this->message, '.')) {
|
||||
$this->message = substr($this->message, 0, -1);
|
||||
$dot = true;
|
||||
}
|
||||
|
||||
$questionMark = false;
|
||||
if (str_ends_with($this->message, '?')) {
|
||||
$this->message = substr($this->message, 0, -1);
|
||||
$questionMark = true;
|
||||
}
|
||||
|
||||
if ($this->name) {
|
||||
if (\is_string($this->name) || $this->name instanceof \Stringable) {
|
||||
$name = \sprintf('"%s"', $this->name);
|
||||
if ($this->source && $this->source->getPath()) {
|
||||
// we only update the file and the line together
|
||||
$this->file = $this->source->getPath();
|
||||
if ($this->lineno > 0) {
|
||||
$this->line = $this->lineno;
|
||||
} else {
|
||||
$name = json_encode($this->name);
|
||||
$this->line = -1;
|
||||
}
|
||||
$this->message .= \sprintf(' in %s', $name);
|
||||
}
|
||||
|
||||
if ($this->lineno && $this->lineno >= 0) {
|
||||
$this->message = $this->rawMessage;
|
||||
$last = substr($this->message, -1);
|
||||
if ($punctuation = '.' === $last || '?' === $last ? $last : '') {
|
||||
$this->message = substr($this->message, 0, -1);
|
||||
}
|
||||
if ($this->source && $this->source->getName()) {
|
||||
$this->message .= \sprintf(' in "%s"', $this->source->getName());
|
||||
}
|
||||
if ($this->lineno > 0) {
|
||||
$this->message .= \sprintf(' at line %d', $this->lineno);
|
||||
}
|
||||
|
||||
if ($dot) {
|
||||
$this->message .= '.';
|
||||
}
|
||||
|
||||
if ($questionMark) {
|
||||
$this->message .= '?';
|
||||
if ($punctuation) {
|
||||
$this->message .= $punctuation;
|
||||
}
|
||||
}
|
||||
|
||||
private function guessTemplateInfo(): void
|
||||
{
|
||||
$template = null;
|
||||
$templateClass = null;
|
||||
// $this->source is never null here (see guess() usage in Template)
|
||||
|
||||
$this->lineno = 0;
|
||||
$template = null;
|
||||
$backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT);
|
||||
foreach ($backtrace as $trace) {
|
||||
if (isset($trace['object']) && $trace['object'] instanceof Template) {
|
||||
$currentClass = \get_class($trace['object']);
|
||||
$isEmbedContainer = null === $templateClass ? false : str_starts_with($templateClass, $currentClass);
|
||||
if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) {
|
||||
$template = $trace['object'];
|
||||
$templateClass = \get_class($trace['object']);
|
||||
}
|
||||
if (isset($trace['object']) && $trace['object'] instanceof Template && $this->source->getName() === $trace['object']->getTemplateName()) {
|
||||
$template = $trace['object'];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// update template name
|
||||
if (null !== $template && null === $this->name) {
|
||||
$this->name = $template->getTemplateName();
|
||||
}
|
||||
|
||||
// update template path if any
|
||||
if (null !== $template && null === $this->sourcePath) {
|
||||
$src = $template->getSourceContext();
|
||||
$this->sourceCode = $src->getCode();
|
||||
$this->sourcePath = $src->getPath();
|
||||
}
|
||||
|
||||
if (null === $template || $this->lineno > -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
$r = new \ReflectionObject($template);
|
||||
$file = $r->getFileName();
|
||||
|
||||
@@ -206,8 +158,7 @@ class Error extends \Exception
|
||||
|
||||
while ($e = array_pop($exceptions)) {
|
||||
$traces = $e->getTrace();
|
||||
array_unshift($traces, ['file' => $e->getFile(), 'line' => $e->getLine()]);
|
||||
|
||||
array_unshift($traces, ['file' => $e instanceof Error ? $e->phpFile : $e->getFile(), 'line' => $e instanceof Error ? $e->phpLine : $e->getLine()]);
|
||||
while ($trace = array_shift($traces)) {
|
||||
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
|
||||
continue;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser;
|
||||
|
||||
abstract class AbstractExpressionParser implements ExpressionParserInterface
|
||||
{
|
||||
public function __toString(): string
|
||||
{
|
||||
return \sprintf('%s(%s)', ExpressionParserType::getType($this)->value, $this->getName());
|
||||
}
|
||||
|
||||
public function getPrecedenceChange(): ?PrecedenceChange
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getAliases(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser;
|
||||
|
||||
interface ExpressionParserDescriptionInterface
|
||||
{
|
||||
public function getDescription(): string;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser;
|
||||
|
||||
interface ExpressionParserInterface
|
||||
{
|
||||
public function __toString(): string;
|
||||
|
||||
public function getName(): string;
|
||||
|
||||
public function getPrecedence(): int;
|
||||
|
||||
public function getPrecedenceChange(): ?PrecedenceChange;
|
||||
|
||||
/**
|
||||
* @return array<string>
|
||||
*/
|
||||
public function getAliases(): array;
|
||||
}
|
||||
33
lib/twig/twig/src/ExpressionParser/ExpressionParserType.php
Normal file
33
lib/twig/twig/src/ExpressionParser/ExpressionParserType.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
enum ExpressionParserType: string
|
||||
{
|
||||
case Prefix = 'prefix';
|
||||
case Infix = 'infix';
|
||||
|
||||
public static function getType(object $object): ExpressionParserType
|
||||
{
|
||||
if ($object instanceof PrefixExpressionParserInterface) {
|
||||
return self::Prefix;
|
||||
}
|
||||
if ($object instanceof InfixExpressionParserInterface) {
|
||||
return self::Infix;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException(\sprintf('Unsupported expression parser type: %s', $object::class));
|
||||
}
|
||||
}
|
||||
127
lib/twig/twig/src/ExpressionParser/ExpressionParsers.php
Normal file
127
lib/twig/twig/src/ExpressionParser/ExpressionParsers.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser;
|
||||
|
||||
/**
|
||||
* @template-implements \IteratorAggregate<ExpressionParserInterface>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class ExpressionParsers implements \IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* @var array<class-string<ExpressionParserInterface>, array<string, ExpressionParserInterface>>
|
||||
*/
|
||||
private array $parsersByName = [];
|
||||
|
||||
/**
|
||||
* @var array<class-string<ExpressionParserInterface>, ExpressionParserInterface>
|
||||
*/
|
||||
private array $parsersByClass = [];
|
||||
|
||||
/**
|
||||
* @var \WeakMap<ExpressionParserInterface, array<ExpressionParserInterface>>|null
|
||||
*/
|
||||
private ?\WeakMap $precedenceChanges = null;
|
||||
|
||||
/**
|
||||
* @param array<ExpressionParserInterface> $parsers
|
||||
*/
|
||||
public function __construct(array $parsers = [])
|
||||
{
|
||||
$this->add($parsers);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<ExpressionParserInterface> $parsers
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function add(array $parsers): static
|
||||
{
|
||||
foreach ($parsers as $parser) {
|
||||
if ($parser->getPrecedence() > 512 || $parser->getPrecedence() < 0) {
|
||||
trigger_deprecation('twig/twig', '3.21', 'Precedence for "%s" must be between 0 and 512, got %d.', $parser->getName(), $parser->getPrecedence());
|
||||
// throw new \InvalidArgumentException(\sprintf('Precedence for "%s" must be between 0 and 512, got %d.', $parser->getName(), $parser->getPrecedence()));
|
||||
}
|
||||
$interface = $parser instanceof PrefixExpressionParserInterface ? PrefixExpressionParserInterface::class : InfixExpressionParserInterface::class;
|
||||
$this->parsersByName[$interface][$parser->getName()] = $parser;
|
||||
$this->parsersByClass[$parser::class] = $parser;
|
||||
foreach ($parser->getAliases() as $alias) {
|
||||
$this->parsersByName[$interface][$alias] = $parser;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of ExpressionParserInterface
|
||||
*
|
||||
* @param class-string<T> $class
|
||||
*
|
||||
* @return T|null
|
||||
*/
|
||||
public function getByClass(string $class): ?ExpressionParserInterface
|
||||
{
|
||||
return $this->parsersByClass[$class] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T of ExpressionParserInterface
|
||||
*
|
||||
* @param class-string<T> $interface
|
||||
*
|
||||
* @return T|null
|
||||
*/
|
||||
public function getByName(string $interface, string $name): ?ExpressionParserInterface
|
||||
{
|
||||
return $this->parsersByName[$interface][$name] ?? null;
|
||||
}
|
||||
|
||||
public function getIterator(): \Traversable
|
||||
{
|
||||
foreach ($this->parsersByName as $parsers) {
|
||||
// we don't yield the keys
|
||||
yield from $parsers;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @return \WeakMap<ExpressionParserInterface, array<ExpressionParserInterface>>
|
||||
*/
|
||||
public function getPrecedenceChanges(): \WeakMap
|
||||
{
|
||||
if (null === $this->precedenceChanges) {
|
||||
$this->precedenceChanges = new \WeakMap();
|
||||
foreach ($this as $ep) {
|
||||
if (!$ep->getPrecedenceChange()) {
|
||||
continue;
|
||||
}
|
||||
$min = min($ep->getPrecedenceChange()->getNewPrecedence(), $ep->getPrecedence());
|
||||
$max = max($ep->getPrecedenceChange()->getNewPrecedence(), $ep->getPrecedence());
|
||||
foreach ($this as $e) {
|
||||
if ($e->getPrecedence() > $min && $e->getPrecedence() < $max) {
|
||||
if (!isset($this->precedenceChanges[$e])) {
|
||||
$this->precedenceChanges[$e] = [];
|
||||
}
|
||||
$this->precedenceChanges[$e][] = $ep;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->precedenceChanges;
|
||||
}
|
||||
}
|
||||
79
lib/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php
Normal file
79
lib/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\Node\Expression\ArrayExpression;
|
||||
use Twig\Node\Expression\Unary\SpreadUnary;
|
||||
use Twig\Node\Expression\Variable\ContextVariable;
|
||||
use Twig\Node\Expression\Variable\LocalVariable;
|
||||
use Twig\Node\Nodes;
|
||||
use Twig\Parser;
|
||||
use Twig\Token;
|
||||
|
||||
trait ArgumentsTrait
|
||||
{
|
||||
private function parseCallableArguments(Parser $parser, int $line, bool $parseOpenParenthesis = true): ArrayExpression
|
||||
{
|
||||
$arguments = new ArrayExpression([], $line);
|
||||
foreach ($this->parseNamedArguments($parser, $parseOpenParenthesis) as $k => $n) {
|
||||
$arguments->addElement($n, new LocalVariable($k, $line));
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
private function parseNamedArguments(Parser $parser, bool $parseOpenParenthesis = true): Nodes
|
||||
{
|
||||
$args = [];
|
||||
$stream = $parser->getStream();
|
||||
if ($parseOpenParenthesis) {
|
||||
$stream->expect(Token::OPERATOR_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
|
||||
}
|
||||
$hasSpread = false;
|
||||
while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) {
|
||||
if ($args) {
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
|
||||
|
||||
// if the comma above was a trailing comma, early exit the argument parse loop
|
||||
if ($stream->test(Token::PUNCTUATION_TYPE, ')')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$value = $parser->parseExpression();
|
||||
if ($value instanceof SpreadUnary) {
|
||||
$hasSpread = true;
|
||||
} elseif ($hasSpread) {
|
||||
throw new SyntaxError('Normal arguments must be placed before argument unpacking.', $stream->getCurrent()->getLine(), $stream->getSourceContext());
|
||||
}
|
||||
|
||||
$name = null;
|
||||
if (($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) || ($token = $stream->nextIf(Token::PUNCTUATION_TYPE, ':'))) {
|
||||
if (!$value instanceof ContextVariable) {
|
||||
throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', $value::class), $token->getLine(), $stream->getSourceContext());
|
||||
}
|
||||
$name = $value->getAttribute('name');
|
||||
$value = $parser->parseExpression();
|
||||
}
|
||||
|
||||
if (null === $name) {
|
||||
$args[] = $value;
|
||||
} else {
|
||||
$args[$name] = $value;
|
||||
}
|
||||
}
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
|
||||
|
||||
return new Nodes($args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\ExpressionParser\AbstractExpressionParser;
|
||||
use Twig\ExpressionParser\ExpressionParserDescriptionInterface;
|
||||
use Twig\ExpressionParser\InfixAssociativity;
|
||||
use Twig\ExpressionParser\InfixExpressionParserInterface;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ArrowFunctionExpression;
|
||||
use Twig\Parser;
|
||||
use Twig\Token;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class ArrowExpressionParser extends AbstractExpressionParser implements InfixExpressionParserInterface, ExpressionParserDescriptionInterface
|
||||
{
|
||||
public function parse(Parser $parser, AbstractExpression $expr, Token $token): AbstractExpression
|
||||
{
|
||||
// As the expression of the arrow function is independent from the current precedence, we want a precedence of 0
|
||||
return new ArrowFunctionExpression($parser->parseExpression(), $expr, $token->getLine());
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return '=>';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Arrow function (x => expr)';
|
||||
}
|
||||
|
||||
public function getPrecedence(): int
|
||||
{
|
||||
return 250;
|
||||
}
|
||||
|
||||
public function getAssociativity(): InfixAssociativity
|
||||
{
|
||||
return InfixAssociativity::Left;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\ExpressionParser\AbstractExpressionParser;
|
||||
use Twig\ExpressionParser\ExpressionParserDescriptionInterface;
|
||||
use Twig\ExpressionParser\InfixAssociativity;
|
||||
use Twig\ExpressionParser\InfixExpressionParserInterface;
|
||||
use Twig\ExpressionParser\PrecedenceChange;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\Binary\AbstractBinary;
|
||||
use Twig\Parser;
|
||||
use Twig\Token;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class BinaryOperatorExpressionParser extends AbstractExpressionParser implements InfixExpressionParserInterface, ExpressionParserDescriptionInterface
|
||||
{
|
||||
public function __construct(
|
||||
/** @var class-string<AbstractBinary> */
|
||||
private string $nodeClass,
|
||||
private string $name,
|
||||
private int $precedence,
|
||||
private InfixAssociativity $associativity = InfixAssociativity::Left,
|
||||
private ?PrecedenceChange $precedenceChange = null,
|
||||
private ?string $description = null,
|
||||
private array $aliases = [],
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AbstractBinary
|
||||
*/
|
||||
public function parse(Parser $parser, AbstractExpression $left, Token $token): AbstractExpression
|
||||
{
|
||||
$right = $parser->parseExpression(InfixAssociativity::Left === $this->getAssociativity() ? $this->getPrecedence() + 1 : $this->getPrecedence());
|
||||
|
||||
return new ($this->nodeClass)($left, $right, $token->getLine());
|
||||
}
|
||||
|
||||
public function getAssociativity(): InfixAssociativity
|
||||
{
|
||||
return $this->associativity;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return $this->description ?? '';
|
||||
}
|
||||
|
||||
public function getPrecedence(): int
|
||||
{
|
||||
return $this->precedence;
|
||||
}
|
||||
|
||||
public function getPrecedenceChange(): ?PrecedenceChange
|
||||
{
|
||||
return $this->precedenceChange;
|
||||
}
|
||||
|
||||
public function getAliases(): array
|
||||
{
|
||||
return $this->aliases;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\ExpressionParser\AbstractExpressionParser;
|
||||
use Twig\ExpressionParser\ExpressionParserDescriptionInterface;
|
||||
use Twig\ExpressionParser\InfixAssociativity;
|
||||
use Twig\ExpressionParser\InfixExpressionParserInterface;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Expression\Ternary\ConditionalTernary;
|
||||
use Twig\Parser;
|
||||
use Twig\Token;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class ConditionalTernaryExpressionParser extends AbstractExpressionParser implements InfixExpressionParserInterface, ExpressionParserDescriptionInterface
|
||||
{
|
||||
public function parse(Parser $parser, AbstractExpression $left, Token $token): AbstractExpression
|
||||
{
|
||||
$then = $parser->parseExpression($this->getPrecedence());
|
||||
if ($parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ':')) {
|
||||
// Ternary operator (expr ? expr2 : expr3)
|
||||
$else = $parser->parseExpression($this->getPrecedence());
|
||||
} else {
|
||||
// Ternary without else (expr ? expr2)
|
||||
$else = new ConstantExpression('', $token->getLine());
|
||||
}
|
||||
|
||||
return new ConditionalTernary($left, $then, $else, $token->getLine());
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return '?';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Conditional operator (a ? b : c)';
|
||||
}
|
||||
|
||||
public function getPrecedence(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getAssociativity(): InfixAssociativity
|
||||
{
|
||||
return InfixAssociativity::Left;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\ExpressionParser\AbstractExpressionParser;
|
||||
use Twig\ExpressionParser\ExpressionParserDescriptionInterface;
|
||||
use Twig\ExpressionParser\InfixAssociativity;
|
||||
use Twig\ExpressionParser\InfixExpressionParserInterface;
|
||||
use Twig\Lexer;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ArrayExpression;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Expression\GetAttrExpression;
|
||||
use Twig\Node\Expression\MacroReferenceExpression;
|
||||
use Twig\Node\Expression\NameExpression;
|
||||
use Twig\Node\Expression\Variable\TemplateVariable;
|
||||
use Twig\Parser;
|
||||
use Twig\Template;
|
||||
use Twig\Token;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class DotExpressionParser extends AbstractExpressionParser implements InfixExpressionParserInterface, ExpressionParserDescriptionInterface
|
||||
{
|
||||
use ArgumentsTrait;
|
||||
|
||||
public function parse(Parser $parser, AbstractExpression $expr, Token $token): AbstractExpression
|
||||
{
|
||||
$stream = $parser->getStream();
|
||||
$token = $stream->getCurrent();
|
||||
$lineno = $token->getLine();
|
||||
$arguments = new ArrayExpression([], $lineno);
|
||||
$type = Template::ANY_CALL;
|
||||
|
||||
if ($stream->nextIf(Token::OPERATOR_TYPE, '(')) {
|
||||
$attribute = $parser->parseExpression();
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ')');
|
||||
} else {
|
||||
$token = $stream->next();
|
||||
if (
|
||||
$token->test(Token::NAME_TYPE)
|
||||
|| $token->test(Token::NUMBER_TYPE)
|
||||
|| ($token->test(Token::OPERATOR_TYPE) && preg_match(Lexer::REGEX_NAME, $token->getValue()))
|
||||
) {
|
||||
$attribute = new ConstantExpression($token->getValue(), $token->getLine());
|
||||
} else {
|
||||
throw new SyntaxError(\sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), $token->toEnglish()), $token->getLine(), $stream->getSourceContext());
|
||||
}
|
||||
}
|
||||
|
||||
if ($stream->test(Token::OPERATOR_TYPE, '(')) {
|
||||
$type = Template::METHOD_CALL;
|
||||
$arguments = $this->parseCallableArguments($parser, $token->getLine());
|
||||
}
|
||||
|
||||
if (
|
||||
$expr instanceof NameExpression
|
||||
&& (
|
||||
null !== $parser->getImportedSymbol('template', $expr->getAttribute('name'))
|
||||
|| '_self' === $expr->getAttribute('name') && $attribute instanceof ConstantExpression
|
||||
)
|
||||
) {
|
||||
return new MacroReferenceExpression(new TemplateVariable($expr->getAttribute('name'), $expr->getTemplateLine()), 'macro_'.$attribute->getAttribute('value'), $arguments, $expr->getTemplateLine());
|
||||
}
|
||||
|
||||
return new GetAttrExpression($expr, $attribute, $arguments, $type, $lineno);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return '.';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Get an attribute on a variable';
|
||||
}
|
||||
|
||||
public function getPrecedence(): int
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
public function getAssociativity(): InfixAssociativity
|
||||
{
|
||||
return InfixAssociativity::Left;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\Attribute\FirstClassTwigCallableReady;
|
||||
use Twig\ExpressionParser\AbstractExpressionParser;
|
||||
use Twig\ExpressionParser\ExpressionParserDescriptionInterface;
|
||||
use Twig\ExpressionParser\InfixAssociativity;
|
||||
use Twig\ExpressionParser\InfixExpressionParserInterface;
|
||||
use Twig\ExpressionParser\PrecedenceChange;
|
||||
use Twig\Node\EmptyNode;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Parser;
|
||||
use Twig\Token;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class FilterExpressionParser extends AbstractExpressionParser implements InfixExpressionParserInterface, ExpressionParserDescriptionInterface
|
||||
{
|
||||
use ArgumentsTrait;
|
||||
|
||||
private $readyNodes = [];
|
||||
|
||||
public function parse(Parser $parser, AbstractExpression $expr, Token $token): AbstractExpression
|
||||
{
|
||||
$stream = $parser->getStream();
|
||||
$token = $stream->expect(Token::NAME_TYPE);
|
||||
$line = $token->getLine();
|
||||
|
||||
if (!$stream->test(Token::OPERATOR_TYPE, '(')) {
|
||||
$arguments = new EmptyNode();
|
||||
} else {
|
||||
$arguments = $this->parseNamedArguments($parser);
|
||||
}
|
||||
|
||||
$filter = $parser->getFilter($token->getValue(), $line);
|
||||
|
||||
$ready = true;
|
||||
if (!isset($this->readyNodes[$class = $filter->getNodeClass()])) {
|
||||
$this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class);
|
||||
}
|
||||
|
||||
if (!$ready = $this->readyNodes[$class]) {
|
||||
trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigFilter" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class);
|
||||
}
|
||||
|
||||
return new $class($expr, $ready ? $filter : new ConstantExpression($filter->getName(), $line), $arguments, $line);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return '|';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Twig filter call';
|
||||
}
|
||||
|
||||
public function getPrecedence(): int
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
public function getPrecedenceChange(): ?PrecedenceChange
|
||||
{
|
||||
return new PrecedenceChange('twig/twig', '3.21', 300);
|
||||
}
|
||||
|
||||
public function getAssociativity(): InfixAssociativity
|
||||
{
|
||||
return InfixAssociativity::Left;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\Attribute\FirstClassTwigCallableReady;
|
||||
use Twig\Error\SyntaxError;
|
||||
use Twig\ExpressionParser\AbstractExpressionParser;
|
||||
use Twig\ExpressionParser\ExpressionParserDescriptionInterface;
|
||||
use Twig\ExpressionParser\InfixAssociativity;
|
||||
use Twig\ExpressionParser\InfixExpressionParserInterface;
|
||||
use Twig\Node\EmptyNode;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\MacroReferenceExpression;
|
||||
use Twig\Node\Expression\NameExpression;
|
||||
use Twig\Parser;
|
||||
use Twig\Token;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class FunctionExpressionParser extends AbstractExpressionParser implements InfixExpressionParserInterface, ExpressionParserDescriptionInterface
|
||||
{
|
||||
use ArgumentsTrait;
|
||||
|
||||
private $readyNodes = [];
|
||||
|
||||
public function parse(Parser $parser, AbstractExpression $expr, Token $token): AbstractExpression
|
||||
{
|
||||
$line = $token->getLine();
|
||||
if (!$expr instanceof NameExpression) {
|
||||
throw new SyntaxError('Function name must be an identifier.', $line, $parser->getStream()->getSourceContext());
|
||||
}
|
||||
|
||||
$name = $expr->getAttribute('name');
|
||||
|
||||
if (null !== $alias = $parser->getImportedSymbol('function', $name)) {
|
||||
return new MacroReferenceExpression($alias['node']->getNode('var'), $alias['name'], $this->parseCallableArguments($parser, $line, false), $line);
|
||||
}
|
||||
|
||||
$args = $this->parseNamedArguments($parser, false);
|
||||
|
||||
$function = $parser->getFunction($name, $line);
|
||||
|
||||
if ($function->getParserCallable()) {
|
||||
$fakeNode = new EmptyNode($line);
|
||||
$fakeNode->setSourceContext($parser->getStream()->getSourceContext());
|
||||
|
||||
return ($function->getParserCallable())($parser, $fakeNode, $args, $line);
|
||||
}
|
||||
|
||||
if (!isset($this->readyNodes[$class = $function->getNodeClass()])) {
|
||||
$this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class);
|
||||
}
|
||||
|
||||
if (!$ready = $this->readyNodes[$class]) {
|
||||
trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigFunction" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class);
|
||||
}
|
||||
|
||||
return new $class($ready ? $function : $function->getName(), $args, $line);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return '(';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Twig function call';
|
||||
}
|
||||
|
||||
public function getPrecedence(): int
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
public function getAssociativity(): InfixAssociativity
|
||||
{
|
||||
return InfixAssociativity::Left;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\Attribute\FirstClassTwigCallableReady;
|
||||
use Twig\ExpressionParser\AbstractExpressionParser;
|
||||
use Twig\ExpressionParser\ExpressionParserDescriptionInterface;
|
||||
use Twig\ExpressionParser\InfixAssociativity;
|
||||
use Twig\ExpressionParser\InfixExpressionParserInterface;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ArrayExpression;
|
||||
use Twig\Node\Expression\MacroReferenceExpression;
|
||||
use Twig\Node\Expression\NameExpression;
|
||||
use Twig\Node\Nodes;
|
||||
use Twig\Parser;
|
||||
use Twig\Token;
|
||||
use Twig\TwigTest;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class IsExpressionParser extends AbstractExpressionParser implements InfixExpressionParserInterface, ExpressionParserDescriptionInterface
|
||||
{
|
||||
use ArgumentsTrait;
|
||||
|
||||
private $readyNodes = [];
|
||||
|
||||
public function parse(Parser $parser, AbstractExpression $expr, Token $token): AbstractExpression
|
||||
{
|
||||
$stream = $parser->getStream();
|
||||
$test = $parser->getTest($token->getLine());
|
||||
|
||||
$arguments = null;
|
||||
if ($stream->test(Token::OPERATOR_TYPE, '(')) {
|
||||
$arguments = $this->parseNamedArguments($parser);
|
||||
} elseif ($test->hasOneMandatoryArgument()) {
|
||||
$arguments = new Nodes([0 => $parser->parseExpression($this->getPrecedence())]);
|
||||
}
|
||||
|
||||
if ('defined' === $test->getName() && $expr instanceof NameExpression && null !== $alias = $parser->getImportedSymbol('function', $expr->getAttribute('name'))) {
|
||||
$expr = new MacroReferenceExpression($alias['node']->getNode('var'), $alias['name'], new ArrayExpression([], $expr->getTemplateLine()), $expr->getTemplateLine());
|
||||
}
|
||||
|
||||
$ready = $test instanceof TwigTest;
|
||||
if (!isset($this->readyNodes[$class = $test->getNodeClass()])) {
|
||||
$this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class);
|
||||
}
|
||||
|
||||
if (!$ready = $this->readyNodes[$class]) {
|
||||
trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigTest" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class);
|
||||
}
|
||||
|
||||
return new $class($expr, $ready ? $test : $test->getName(), $arguments, $stream->getCurrent()->getLine());
|
||||
}
|
||||
|
||||
public function getPrecedence(): int
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'is';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Twig tests';
|
||||
}
|
||||
|
||||
public function getAssociativity(): InfixAssociativity
|
||||
{
|
||||
return InfixAssociativity::Left;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\Unary\NotUnary;
|
||||
use Twig\Parser;
|
||||
use Twig\Token;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class IsNotExpressionParser extends IsExpressionParser
|
||||
{
|
||||
public function parse(Parser $parser, AbstractExpression $expr, Token $token): AbstractExpression
|
||||
{
|
||||
return new NotUnary(parent::parse($parser, $expr, $token), $token->getLine());
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return 'is not';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Twig\ExpressionParser\Infix;
|
||||
|
||||
use Twig\ExpressionParser\AbstractExpressionParser;
|
||||
use Twig\ExpressionParser\ExpressionParserDescriptionInterface;
|
||||
use Twig\ExpressionParser\InfixAssociativity;
|
||||
use Twig\ExpressionParser\InfixExpressionParserInterface;
|
||||
use Twig\Node\Expression\AbstractExpression;
|
||||
use Twig\Node\Expression\ArrayExpression;
|
||||
use Twig\Node\Expression\ConstantExpression;
|
||||
use Twig\Node\Expression\GetAttrExpression;
|
||||
use Twig\Node\Nodes;
|
||||
use Twig\Parser;
|
||||
use Twig\Template;
|
||||
use Twig\Token;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class SquareBracketExpressionParser extends AbstractExpressionParser implements InfixExpressionParserInterface, ExpressionParserDescriptionInterface
|
||||
{
|
||||
public function parse(Parser $parser, AbstractExpression $expr, Token $token): AbstractExpression
|
||||
{
|
||||
$stream = $parser->getStream();
|
||||
$lineno = $token->getLine();
|
||||
$arguments = new ArrayExpression([], $lineno);
|
||||
|
||||
// slice?
|
||||
$slice = false;
|
||||
if ($stream->test(Token::PUNCTUATION_TYPE, ':')) {
|
||||
$slice = true;
|
||||
$attribute = new ConstantExpression(0, $token->getLine());
|
||||
} else {
|
||||
$attribute = $parser->parseExpression();
|
||||
}
|
||||
|
||||
if ($stream->nextIf(Token::PUNCTUATION_TYPE, ':')) {
|
||||
$slice = true;
|
||||
}
|
||||
|
||||
if ($slice) {
|
||||
if ($stream->test(Token::PUNCTUATION_TYPE, ']')) {
|
||||
$length = new ConstantExpression(null, $token->getLine());
|
||||
} else {
|
||||
$length = $parser->parseExpression();
|
||||
}
|
||||
|
||||
$filter = $parser->getFilter('slice', $token->getLine());
|
||||
$arguments = new Nodes([$attribute, $length]);
|
||||
$filter = new ($filter->getNodeClass())($expr, $filter, $arguments, $token->getLine());
|
||||
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ']');
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
$stream->expect(Token::PUNCTUATION_TYPE, ']');
|
||||
|
||||
return new GetAttrExpression($expr, $attribute, $arguments, Template::ARRAY_CALL, $lineno);
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return '[';
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Array access';
|
||||
}
|
||||
|
||||
public function getPrecedence(): int
|
||||
{
|
||||
return 512;
|
||||
}
|
||||
|
||||
public function getAssociativity(): InfixAssociativity
|
||||
{
|
||||
return InfixAssociativity::Left;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user