Compare commits

...

111 Commits

Author SHA1 Message Date
Nicolas Grekas
7793eea884 bug #34091 [Debug] work around failing chdir() on Darwin (mary2501)
This PR was merged into the 4.3 branch.

Discussion
----------

[Debug] work around failing chdir() on Darwin

| Q             | A
| ------------- | ---
| Branch?       |  4.3 for bug fixes <!-- see below -->
| Bug fix?      | yes
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | Fix https://github.com/happybottoms/coverd/issues/15 <!-- prefix each issue number with "Fix #", if any -->
| License       | MIT
| Doc PR        | symfony/symfony-docs#... <!-- required for new features -->
<!--
Replace this notice by a short README for your feature/bugfix. This will help people
understand your PR and can be used as a start for the documentation.

Additionally (see https://symfony.com/roadmap):
 - Always add tests and ensure they pass.
 - Never break backward compatibility (see https://symfony.com/bc).
 - Bug fixes must be submitted against the lowest maintained branch where they apply
   (lowest branches are regularly merged to upper ones so they get the fixes too.)
 - Features and deprecations must be submitted against branch 4.4.
 - Legacy code removals go to the master branch.
-->

Commits
-------

f40373eb7c [Debug] work around failing chdir() on Darwin
2019-11-28 11:55:21 +01:00
Maria Grazia Patteri
e8d70531f3 [Debug] work around failing chdir() on Darwin 2019-11-28 11:53:46 +01:00
Nicolas Grekas
5ea9c3e019 Merge branch '3.4' into 4.3
* 3.4:
  #30432 fix an error message
  fix paths to detect code owners
  [Validator] Ensure numeric subpaths do not cause errors on PHP 7.4
  Remove unused local variables in tests
  Make sure to collect child forms created on *_SET_DATA events
  do not render errors for checkboxes twice
2019-10-28 18:07:32 +01:00
Thomas Calvet
f72e33fdb1 Remove unused local variables in tests 2019-10-24 17:33:53 +02:00
Nicolas Grekas
cc5c1efd0e Merge branch '3.4' into 4.3
* 3.4:
  Re-enable previously failing PHP 7.4 test cases
  Revert "bug #33618 fix tests depending on other components' tests (xabbuh)"
  install from source to include components tests
2019-09-19 17:51:53 +02:00
Nicolas Grekas
b3e7ce815d Re-enable previously failing PHP 7.4 test cases 2019-09-19 17:32:51 +02:00
Fabien Potencier
c1a032ce81 Simplify usage of dirname() 2019-09-10 13:22:25 +02:00
Alexander M. Turek
afcdea44a2 Fix inconsistent return points. 2019-08-20 16:27:59 +02:00
Nicolas Grekas
ed30cb9da5 Merge branch '3.4' into 4.3
* 3.4:
  Fix inconsistent return points.
  [Security/Core] UserInterface::getPassword() can return null
  [Router] Fix TraceableUrlMatcher behaviour with trailing slash
2019-08-20 16:07:54 +02:00
Alexander M. Turek
0b60030091 Fix inconsistent return points. 2019-08-20 15:31:17 +02:00
Nicolas Grekas
2d8ff49ce0 Merge branch '3.4' into 4.3
* 3.4:
  Fix return statements
  [TwigBridge] add missing dep
  Add false type to ChoiceListFactoryInterface::createView $label argument
2019-08-13 08:39:03 +02:00
Nicolas Grekas
2ab93347e8 Fix return statements 2019-08-13 08:33:05 +02:00
Nicolas Grekas
692aa71df2 Merge branch '3.4' into 4.3
* 3.4:
  Improve some URLs
  Fix test compatibility with 4.x components
  [Cache] cs fix
2019-08-08 17:11:33 +02:00
Nicolas Grekas
4645282605 minor #32800 Improve some URLs (Arman-Hosseini)
This PR was squashed before being merged into the 3.4 branch (closes #32800).

Discussion
----------

Improve some URLs

| Q             | A
| ------------- | ---
| Branch?       | 3.4 <!-- see below -->
| Bug fix?      | no
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | N/A   <!-- #-prefixed issue number(s), if any -->
| License       | MIT
| Doc PR        | N/A <!-- required for new features -->

<!--
Replace this notice by a short README for your feature/bugfix. This will help people
understand your PR and can be used as a start for the documentation.

Additionally (see https://symfony.com/roadmap):
 - Bug fixes must be submitted against the lowest maintained branch where they apply
   (lowest branches are regularly merged to upper ones so they get the fixes too).
 - Features and deprecations must be submitted against branch 4.4.
 - Legacy code removals go to the master branch.
-->

Commits
-------

fab17a4487 Improve some URLs
2019-08-08 17:01:55 +02:00
Arman Hosseini
93fd0e9f20 Improve some URLs 2019-08-08 17:01:12 +02:00
Jérémy Derussé
3ec8596803 Disable phpunit typehint patch on 4.3 branch 2019-08-08 11:29:19 +02:00
Nicolas Grekas
19056a4079 Merge branch '3.4' into 4.3
* 3.4:
  Fix inconsistent return points.
  Fix remaining tests
2019-08-07 13:52:19 +02:00
Mario Blažek
12e1811d2b Remove deprecated assertContains 2019-08-07 10:22:11 +02:00
Jérémy Derussé
c5366e87da Fix remaining tests 2019-08-06 15:24:37 +02:00
Nicolas Grekas
406bb25021 Merge branch '3.4' into 4.3
* 3.4:
  bump phpunit-bridge cache-id
  Use assertStringContainsString when needed
  Use assert assertContainsEquals when needed
  Use assertEqualsWithDelta when required
2019-08-06 09:11:09 +02:00
Jérémy Derussé
a78bf4dc3a Use assertStringContainsString when needed 2019-08-06 08:15:37 +02:00
Nicolas Grekas
dda62cdc3a Merge branch '3.4' into 4.3
* 3.4:
  Remove use of ForwardCompatTrait
  Remove deprecated methods assertArraySubset
2019-08-03 23:50:52 +02:00
Jérémy Derussé
4dc880d082 Remove use of ForwardCompatTrait 2019-08-03 23:15:25 +02:00
Nicolas Grekas
288013687b Merge branch '3.4' into 4.3
* 3.4:
  Adopt `@PHPUnit55Migration:risky` rule of php-cs-fixer
2019-08-03 16:00:31 +02:00
Nicolas Grekas
63f26f1891 Adopt @PHPUnit55Migration:risky rule of php-cs-fixer 2019-08-03 15:46:27 +02:00
Nicolas Grekas
91730bdf7d Merge branch '3.4' into 4.3
* 3.4:
  Fix tests
  Fix deprecated phpunit annotation
2019-08-02 14:15:04 +02:00
Jérémy Derussé
bef2cd01a1 Fix deprecated phpunit annotation 2019-08-02 00:48:42 +02:00
Nicolas Grekas
1fd323489f Merge branch '3.4' into 4.3
* 3.4:
  [Cache] fix cs
  Make tests support phpunit 8
2019-08-01 00:32:32 +02:00
Nicolas Grekas
22fea487fa Make tests support phpunit 8 2019-07-31 23:55:24 +02:00
Nicolas Grekas
8ff6ff5f51 Merge branch '3.4' into 4.3
* 3.4:
  Fix travis script
  minor fix for wrong case
  [HttpFoundation] Fix `getMaxFilesize`
  [Cache] fix warning on PHP 7.4
  [Console] fix warning on PHP 7.4
  Don't add value of (default/static) objects to the signature
  fix(yml): fix comment in milti line value
2019-07-31 14:41:55 +02:00
Tobias Weichart
89429ed0eb minor fix for wrong case 2019-07-31 08:13:25 +01:00
Nicolas Grekas
527887c385 Merge branch '4.2' into 4.3
* 4.2:
  [FrameworkBundle] [SecurityBundle] Rename internal WebTestCase to avoid confusion
  ignore not existing translator service
  [FrameworkBundle] [SecurityBundle] Rename internal WebTestCase to avoid confusion
  revert private properties handling
  [HttpFoundation] Fix URLs
  [VarDumper] finish PHP 7.4 support and add tests
  [VarDumper] Use \ReflectionReference for determining if a key is a reference (php >= 7.4)
  Ignore missing translation dependency in FrameworkBundle
  Remove dead tests fixtures
  Remove more dead tests fixtures
  Remove dead tests fixtures
  [Debug][ExceptionHandler] Add tests for custom handlers
2019-07-23 13:21:36 +02:00
Nicolas Grekas
f832ecacfb Merge branch '3.4' into 4.2
* 3.4:
  [FrameworkBundle] [SecurityBundle] Rename internal WebTestCase to avoid confusion
  revert private properties handling
  [HttpFoundation] Fix URLs
  [VarDumper] finish PHP 7.4 support and add tests
  [VarDumper] Use \ReflectionReference for determining if a key is a reference (php >= 7.4)
  Ignore missing translation dependency in FrameworkBundle
  [Debug][ExceptionHandler] Add tests for custom handlers
2019-07-23 11:50:15 +02:00
Nicolas Grekas
bc977cb268 minor #32619 [Debug][ExceptionHandler] Add tests for custom handlers (fancyweb)
This PR was merged into the 3.4 branch.

Discussion
----------

[Debug][ExceptionHandler] Add tests for custom handlers

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

In https://github.com/symfony/symfony/pull/31694 I mixed many things but the whole PR was closed. I wrote some tests for custom handlers + the handle tests don't use mock anymore

I think they are useful even if the `ExceptionHandler` will disappear in the new component because it will still exists in 4.4 for the next 3 years.

Commits
-------

c53e25332a [Debug][ExceptionHandler] Add tests for custom handlers
2019-07-23 10:39:19 +02:00
Nicolas Grekas
340a0fc6ed Merge branch '3.4' into 4.2
* 3.4:
  Remove dead tests fixtures
2019-07-19 14:05:51 +02:00
Nicolas Grekas
dabd21d13b minor #32623 Remove dead tests fixtures (fancyweb)
This PR was merged into the 3.4 branch.

Discussion
----------

Remove dead tests fixtures

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

Once this is merged up to 4.2, I will check 4.2.

Commits
-------

f7e24c2c80 Remove dead tests fixtures
2019-07-19 14:05:10 +02:00
Thomas Calvet
b6f28caaf2 Remove dead tests fixtures 2019-07-19 13:52:08 +02:00
Thomas Calvet
5bf4824968 [Debug][ExceptionHandler] Add tests for custom handlers 2019-07-19 10:43:44 +02:00
Nicolas Grekas
fb91321bee Merge branch '4.2' into 4.3
* 4.2:
  fix tests
  [Validator] Added support for validation of giga values
  Fix Debug component tests
2019-07-19 10:33:28 +02:00
Nicolas Grekas
2fdd843f5e Merge branch '3.4' into 4.2
* 3.4:
  fix tests
  [Validator] Added support for validation of giga values
  Fix Debug component tests
2019-07-19 10:33:10 +02:00
Nicolas Grekas
dff676526c minor #32612 [Debug] Fix 3.4 tests (yceruto)
This PR was merged into the 3.4 branch.

Discussion
----------

[Debug] Fix 3.4 tests

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT

Commits
-------

77fa283091 Fix Debug component tests
2019-07-19 10:32:24 +02:00
Yonel Ceruto
b49ea98332 Fix Debug component tests 2019-07-18 18:35:50 -04:00
Nicolas Grekas
5f3e892c1c Merge branch '4.2' into 4.3
* 4.2: (23 commits)
  fix cs
  Use mocks before replacing the error handler
  [Config] Do not use absolute path when computing the vendor freshness
  Bump minimum version of symfony/phpunit-bridge
  Container*::getServiceIds() should return an array of string
  [Config][ReflectionClassResource] Use ternary instead of null coaelscing operator
  [Validator] Add missing Russian and Ukrainian translations
  [Translation] Use HTTPS and fix a url
  [Config] Fix for signatures of typed properties
  [Validator] Add missing Hungarian translations
  [Validator] Add Lithuanian translation for Range validator
  Add HTTPS to a URL
  sync translation files
  PHPDoc fixes
  Add notInRange translation
  Add danish translation for Range validator
  Add german translation for Range validator
  Update validators.es.xlf
  [Validator] Add missing en and fr translation ids from 4.4
  [Debug][DebugClassLoader] Don't check class if the included file don't exist
  ...
2019-07-18 12:34:59 +02:00
Nicolas Grekas
7a65fe00f9 Merge branch '3.4' into 4.2
* 3.4: (23 commits)
  fix cs
  Use mocks before replacing the error handler
  [Config] Do not use absolute path when computing the vendor freshness
  Bump minimum version of symfony/phpunit-bridge
  Container*::getServiceIds() should return an array of string
  [Config][ReflectionClassResource] Use ternary instead of null coaelscing operator
  [Validator] Add missing Russian and Ukrainian translations
  [Translation] Use HTTPS and fix a url
  [Config] Fix for signatures of typed properties
  [Validator] Add missing Hungarian translations
  [Validator] Add Lithuanian translation for Range validator
  Add HTTPS to a URL
  sync translation files
  PHPDoc fixes
  Add notInRange translation
  Add danish translation for Range validator
  Add german translation for Range validator
  Update validators.es.xlf
  [Validator] Add missing en and fr translation ids from 4.4
  [Debug][DebugClassLoader] Don't check class if the included file don't exist
  ...
2019-07-18 12:29:22 +02:00
Grégoire Paris
a808f15333 Use mocks before replacing the error handler
We want the bridge to mute the deprecations triggered when building mocks.
2019-07-18 08:26:12 +02:00
Thomas Calvet
32d260af46 [Debug][DebugClassLoader] Don't check class if the included file don't exist 2019-07-12 10:40:08 +02:00
Fabien Potencier
8ab610f0b0 Merge branch '4.2' into 4.3
* 4.2:
  fixed CS
  [Debug][DebugClassLoader] Include found files instead of requiring them
2019-07-12 08:54:53 +03:00
Fabien Potencier
8a212666c0 Merge branch '3.4' into 4.2
* 3.4:
  fixed CS
  [Debug][DebugClassLoader] Include found files instead of requiring them
2019-07-12 08:51:03 +03:00
Thomas Calvet
740602e8b0 [Debug][DebugClassLoader] Include found files instead of requiring them 2019-07-11 20:09:53 +02:00
Christian Flothmann
8ca4340b26 Merge branch '4.2' into 4.3
* 4.2:
  fix Debug component dependencies
  [travis] not all components have a master branch
2019-06-28 14:12:54 +02:00
Christian Flothmann
b6d3ae55c0 Merge branch '3.4' into 4.2
* 3.4:
  fix Debug component dependencies
  [travis] not all components have a master branch
2019-06-28 14:00:38 +02:00
Christian Flothmann
d58c0d65d7 fix Debug component dependencies 2019-06-28 11:18:39 +02:00
Nicolas Grekas
d8f4fb3815 Merge branch '4.2' into 4.3
* 4.2:
  [FrameworkBundle] minor: fix typo in SessionTest
  [Debug] workaround BC break in PHP 7.3
2019-06-19 17:27:09 +02:00
Nicolas Grekas
bb91fa5ab9 Merge branch '3.4' into 4.2
* 3.4:
  [FrameworkBundle] minor: fix typo in SessionTest
  [Debug] workaround BC break in PHP 7.3
2019-06-19 17:26:44 +02:00
Nicolas Grekas
1172dc1abe [Debug] workaround BC break in PHP 7.3 2019-06-18 23:26:03 +02:00
Fabien Potencier
a30d8fe728 fixed CS 2019-06-13 13:03:18 +02:00
Fabien Potencier
7d9d22bcd0 Merge branch '4.2' into 4.3
* 4.2:
  fixed CS
  fixed CS
  [HttpKernel] Remove TestEventDispatcher.
2019-06-13 13:01:17 +02:00
Fabien Potencier
d0bff29e62 fixed CS 2019-06-13 12:57:15 +02:00
Fabien Potencier
7e1a4ec082 fixed CS 2019-06-13 12:34:15 +02:00
Nicolas Grekas
4e025104f1 Merge branch '4.2' into 4.3
* 4.2:
  Use willReturn() instead of will(returnValue()).
2019-05-30 18:10:05 +02:00
Nicolas Grekas
ceed75ff0d Merge branch '3.4' into 4.2
* 3.4:
  Use willReturn() instead of will(returnValue()).
2019-05-30 18:06:08 +02:00
Alexander M. Turek
e79bbe15d8 Use willReturn() instead of will(returnValue()). 2019-05-30 17:47:52 +02:00
Nicolas Grekas
97cde06d79 Merge branch '4.2' into 4.3
* 4.2:
  minor: add some test in the ldap component
  [Bridge\ProxyManager] isProxyCandidate() does not take into account interfaces
  [Routing][AnnotationClassLoader] fix utf-8 encoding in default route name
  fixed a phpdoc
  [Debug] Wrap call to require_once in a try/catch
  prevent deprecation when filesize matches error code
  [PropertyInfo] Add missing documentation link in Readme
  Use the current working dir as default first arg in 'link' binary
  Respect parent class contract in ContainerAwareDoctrineEventManager
  [Validator] Add the missing translations for the Danish ("da") locale
  [PropertyAccess] Add missing property to PropertyAccessor
  [Cache] fix saving unrelated keys in recursive callback calls
  [Serializer] Fix denormalization of object with variadic constructor typed argument
  Allow set 'None' on samesite cookie flag
  Making cache rebuild correctly with MessageSubscriberInterface return values
  Fix finding parent definition
2019-05-20 18:16:12 +02:00
Nicolas Grekas
22b4d033e6 Merge branch '3.4' into 4.2
* 3.4:
  minor: add some test in the ldap component
  [Bridge\ProxyManager] isProxyCandidate() does not take into account interfaces
  [Routing][AnnotationClassLoader] fix utf-8 encoding in default route name
  fixed a phpdoc
  [Debug] Wrap call to require_once in a try/catch
  [PropertyInfo] Add missing documentation link in Readme
  Use the current working dir as default first arg in 'link' binary
  Respect parent class contract in ContainerAwareDoctrineEventManager
  [Validator] Add the missing translations for the Danish ("da") locale
  [Serializer] Fix denormalization of object with variadic constructor typed argument
  Allow set 'None' on samesite cookie flag
2019-05-20 18:15:26 +02:00
Grégoire Pineau
671fc55bd1 [Debug] Wrap call to require_once in a try/catch
If the included file contains an error, it hides the real error. This
makes debugging harder.

How to reproduce:

```
composer create-project symfony/skeleton symfony-3.4 3.4
cd symfony-3.4
composer req monolog
```

Add to `monolog.yaml`:
```yaml
        elasticsearch:
            type: "elasticsearch"
            elasticsearch:
                host: 'elasticsearch'
                port: '9200'
            index: 'ep_php_logs_dev'
            level: 'debug'
            tags: 'monolog.logger'
            channels: ['!event']
```

This will fail because the the \Elastica\Client class does not exist.
But this error will be hidden by the `ClassNotFoundFatalErrorHandler`
because it will try to load the `Symfony\Component\Kernel\Client` and
this class extends `Symfony\Component\BrowserKit\Client`. The last one
is a soft dependency...

---

Before
```
Fatal error: Uncaught Error: Class 'Symfony\Component\BrowserKit\Client' not found in /tmp/symfony-3.4/vendor/symfony/http-kernel/Client.php:31
```

After:
```
Fatal error: Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "Client" from namespace "Elastica".
Did you forget a "use" statement for another namespace? in /tmp/symfony-es/var/cache/dev/ContainerWXN4mS9/srcApp_KernelDevDebugContainer.php:303
```
2019-05-18 15:32:47 +02:00
Nicolas Grekas
bcb342fd9c Merge branch '4.2'
* 4.2:
  Catch empty deprecation.log silently (fixes #31050)
  minor: the meaning of the data breach was not correct
  Optimize SVGs
  property normalizer should also pass format and context to isAllowedAttribute
2019-04-11 14:10:52 +02:00
Nicolas Grekas
2d279b6bb1 Merge branch '3.4' into 4.2
* 3.4:
  minor: the meaning of the data breach was not correct
  Optimize SVGs
  property normalizer should also pass format and context to isAllowedAttribute
2019-04-11 13:27:41 +02:00
Martijn Cuppens
681afbb264 Optimize SVGs 2019-04-11 11:48:14 +02:00
Christian Flothmann
dba19a100b Merge branch '4.2'
* 4.2:
  fix tests
  fix PHPUnit 4.8 compatibility
  [Debug] Fixed error handling when an error is already handled when another error is already handled (5)
  sync validator translations
2019-04-07 21:49:19 +02:00
Christian Flothmann
f90c108a59 Merge branch '3.4' into 4.2
* 3.4:
  fix PHPUnit 4.8 compatibility
  [Debug] Fixed error handling when an error is already handled when another error is already handled (5)
  sync validator translations
2019-04-07 20:00:57 +02:00
Grégoire Pineau
63b4ddb7c6 [Debug] Fixed error handling when an error is already handled when another error is already handled (5) 2019-04-07 14:43:40 +02:00
Nicolas Grekas
85c2c0c26f Merge branch '4.2'
* 4.2:
  fix translating file validation error message
  [Validator] Add missing Hungarian translations
  Improving deprecation message of the Twig templates directory src/Resources/views
  [3.4] [Validator] Add missing french validation translations.
  [Validator] Only traverse arrays that are cascaded into
  Handle case where no translations were found
  [Validator] Translate unique collection message to Hungarian
  fix tests
  Run test in separate process
  Use a class name that does not actually exist
  [Profiler] Fix dark theme elements color
  fix horizontal spacing of inlined Bootstrap forms
  [Translator] Warm up the translations cache in dev
  turn failed file uploads into form errors
2019-04-07 11:58:10 +02:00
Nicolas Grekas
c4d2a5ad16 Merge branch '3.4' into 4.2
* 3.4:
  fix translating file validation error message
  [Validator] Add missing Hungarian translations
  [3.4] [Validator] Add missing french validation translations.
  [Validator] Only traverse arrays that are cascaded into
  Handle case where no translations were found
  [Validator] Translate unique collection message to Hungarian
  fix tests
  Run test in separate process
  Use a class name that does not actually exist
  fix horizontal spacing of inlined Bootstrap forms
  [Translator] Warm up the translations cache in dev
  turn failed file uploads into form errors
2019-04-07 11:56:43 +02:00
Grégoire Paris
032e6624c3 Use a class name that does not actually exist
Using "Foo", a class name that corresponds to no less than 22 fixture
classes, results in the first found "Foo" being loaded when one is
found by the ClassNotFoundFatalErrorHandler error handler, I am not sure
exactly why, but it is not really a big issue because this is a fatal
error handler and execution is not supposed to continue after that.
Except that is very much the case when running the whole test suite
sequentially with ./phpunit . Then we arrive to the DI component test
suite, and a failure happens because \\foo was not supposed to be defined:

> Failed asserting that exception message 'The definition for "\foo" has
> no class attribute, and appears to reference a class or interface in the
> global namespace. Leaving out the "class" attribute is only allowed for
> namespaced classes. Please specify the class attribute explicitly to get
> rid of this error.' contains 'The definition for "\foo" has no class.'.
2019-04-06 21:25:09 +02:00
Fabien Potencier
91691fa245 feature #28879 [Debug] Mimic __toString php behavior in FlattenException (Deltachaos)
This PR was merged into the 4.3-dev branch.

Discussion
----------

[Debug] Mimic __toString php behavior in FlattenException

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | symfony/symfony-docs#

The `Symfony\Component\Debug\Exception\FlattenException` object is returned by `Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector::getException` method, but the docblock of this method indicates that it should return `\Exception` object.

As the `FlattenException` class should behave as much as possible like a php `\Exception` object, it should implement the same methods as `\Exception`.

This PR is adding `__toString` and `getTraceAsString` methods. Those methods are (in my opinion) the most useful methods of a `\Exception` object. A potential use case (where i am stumbled across this inconsistency) is to get the last exception of a request in a `WebTestCase` using the profiler and printing the trace.

Commits
-------

514a1b506c [Debug] Mimic __toString php behavior in FlattenException
2019-03-31 11:12:58 +02:00
Nicolas Grekas
2a9e82faff Merge branch '4.2'
* 4.2:
  [TwigBridge] remove deprecation triggered when using Twig 2.7
2019-03-10 18:10:06 +01:00
Nicolas Grekas
43ce8ab34c Merge branch '3.4' into 4.2
* 3.4:
  [TwigBridge] remove deprecation triggered when using Twig 2.7
2019-03-10 18:09:50 +01:00
Nicolas Grekas
adbdd5d663 [TwigBridge] remove deprecation triggered when using Twig 2.7 2019-03-10 18:07:42 +01:00
Nicolas Grekas
6d4484cd4b Merge branch '4.2'
* 4.2: (27 commits)
  cs fix
  cs fix
  [PHPUnit-Bridge] override some environment variables
  [TwigBridge] Remove use spaceless tag
  Upgrade zookeeper ext
  [translation] Update defaut format from yml to yaml
  Change default log level for output streams
  update docblock to match the actual behavior
  Don't resolve the Deprecation error handler mode until a deprecation is triggered
  compatibility with phpunit8
  Make 'headers' key optional for encoded messages
  [Debug][DebugClassLoader] Detect annotations before blank docblock lines on final and internal methods
  Fix undefined variable fromConstructor when passing context to getTypes
  Added translations for chineese language.
  Allow 3rd argument to be null
  Remove whitespace (tab on blank line)
  [Monolog] Really reset logger when calling logger::reset()
  [Form] Fixes debug:form appears many times as type extensions configured with new getExtendedTypes method
  Update src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
  Update src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
  ...
2019-03-10 11:14:34 +01:00
Nicolas Grekas
94eda15aa1 Merge branch '3.4' into 4.2
* 3.4:
  cs fix
  cs fix
  [PHPUnit-Bridge] override some environment variables
  [TwigBridge] Remove use spaceless tag
  [translation] Update defaut format from yml to yaml
  Change default log level for output streams
  update docblock to match the actual behavior
  compatibility with phpunit8
  [Debug][DebugClassLoader] Detect annotations before blank docblock lines on final and internal methods
  Added translations for chineese language.
2019-03-10 11:08:12 +01:00
Thomas Calvet
a5961253fa [Debug][DebugClassLoader] Detect annotations before blank docblock lines on final and internal methods 2019-03-06 15:53:23 +01:00
Fabien Potencier
2372d7084d Merge branch '4.2'
* 4.2:
  detect annotations before blank docblock lines
  Serializer: Use the context in supports calls
2019-03-04 12:23:10 +01:00
Fabien Potencier
26bccc04be Merge branch '3.4' into 4.2
* 3.4:
  detect annotations before blank docblock lines
2019-03-04 12:23:00 +01:00
Christian Flothmann
878d05a2eb detect annotations before blank docblock lines 2019-03-04 11:54:25 +01:00
Fabien Potencier
5f14d80d8b Merge branch '4.2'
* 4.2:
  fixed CS
  Autoconfig: don't automatically tag decorators
  removed suggestion
  [PropertyAccess] Fixed PropertyPathBuilder remove that fails to reset internal indexes
  bumped Symfony version to 4.2.5
  updated VERSION for 4.2.4
  updated CHANGELOG for 4.2.4
  bumped Symfony version to 3.4.24
  updated VERSION for 3.4.23
  update CONTRIBUTORS for 3.4.23
  updated CHANGELOG for 3.4.23
  [Routing][ServiceRouterLoader] Remove an outdated comment
2019-03-04 10:16:46 +01:00
Fabien Potencier
83e5508e9d Merge branch '3.4' into 4.2
* 3.4:
  fixed CS
  removed suggestion
  [PropertyAccess] Fixed PropertyPathBuilder remove that fails to reset internal indexes
  bumped Symfony version to 3.4.24
  updated VERSION for 3.4.23
  update CONTRIBUTORS for 3.4.23
  updated CHANGELOG for 3.4.23
  [Routing][ServiceRouterLoader] Remove an outdated comment
2019-03-04 10:16:25 +01:00
Fabien Potencier
d5f9980171 fixed CS 2019-03-04 10:11:50 +01:00
Nicolas Grekas
2533ffde4d Drop more usages of Serializable 2019-03-04 09:45:35 +01:00
Fabien Potencier
806e831d70 Merge branch '4.2'
* 4.2:
  Removed non-existing parameters for LogoutUrlGenerator calls
  [WebProfilerBundle] toolbar: invisible route name in Firefox
  Drop spurious execution bit
  [HttpKernel] Correctly merging cache directives in HttpCache/ResponseCacheStrategy
  [Validator] Add the missing translations for the Latvian ("lv") locale
  Fixed the DebugClassLoader compatibility with eval()'d code on Darwin
  [Validator] Update Serbian translation file
2019-03-03 19:12:18 +01:00
Nicolas Grekas
a850962740 Merge branch '4.2'
* 4.2: (26 commits)
  Apply php-cs-fixer rule for array_key_exists()
  [Cache] fix warming up cache.system and apcu
  [Security] Change FormAuthenticator if condition
  handles multi-byte characters in autocomplete
  speed up tests running them without debug flag
  [Translations] added missing Croatian validators
  Fix getItems() performance issue with RedisCluster (php-redis)
  [VarDumper] Keep a ref to objects to ensure their handle cannot be reused while cloning
  IntegerType: reject submitted non-integer numbers
  be keen to newcomers
  [HttpKernel] Fix possible infinite loop of exceptions
  fixed CS
  [Validator] Added missing translations for Afrikaans
  do not validate non-submitted form fields in PATCH requests
  Update usage example in ArrayInput doc block.
  [Console] Prevent ArgvInput::getFirstArgument() from returning an option value
  [Validator] Fixed duplicate UUID
  fixed CS
  [EventDispatcher] Fix unknown priority
  Avoid mutating the Finder when building the iterator
  ...
2019-02-23 16:22:31 +01:00
Maximilian Ruta
c6af9101fb [Debug] Mimic __toString php behavior in FlattenException 2019-02-21 14:05:12 +01:00
Przemysław Bogusz
4792c7baab Additional addons for the ghost 2019-02-21 00:39:50 +01:00
Nicolas Grekas
091fd557df Merge branch '4.2'
* 4.2:
  [Console] Fix command testing with missing inputs
  [Validator] Sync no/nb translation files
  [Translation] Added a script to display the status of translations
  [Validator] Added missing translations for Norwegian (\"no\") locale #30179
  [Security\Guard] bump lowest version of security-core
  [TwigBridge] Fix test
  Remove unnecessary ProgressBar stdout writes (fixes flickering)
  [Validator] improve translations for albanian ("sq") locale
  [VarDumper] fix serializing Stub instances
  [Validator] Added missing use statement for UnexpectedTypeException
  Don't resolve the Deprecation error handler mode until a deprecation is triggered
  bug #30245 fix lost namespace in eval (fizzka)
  fix lost namespace in eval
  [Twig] removed usage of non-namespaced classes
  added missing dot
  Update validators.lt.xlf
  #30172 Add the missing validation translations for the Luxembourgish …
  [Debug][ErrorHandler] Preserve next error handler
2019-02-19 19:29:52 +01:00
Przemysław Bogusz
f47ba47df3 Add element to ghost in Exception 2019-02-14 10:10:17 +01:00
Javier Eguiluz
8f517eb954 [Debug] Display more details in the simple error page of Debug 2019-02-07 10:41:41 +01:00
Fabien Potencier
c7ac313d92 minor #29988 [Debug][DebugClassLoader] Match callable() type for parameters not defined in sub classes (fancyweb)
This PR was merged into the 4.3-dev branch.

Discussion
----------

[Debug][DebugClassLoader] Match callable() type for parameters not defined in sub classes

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #29969
| License       | MIT
| Doc PR        | -

Added test fixture for multi param, no param type and multi spaces as well.

BTW, I didn't understand why there was a positive lookbehind on the current regex. Looks useless to me and tests passes without it.

Commits
-------

89c89c9776 [Debug][DebugClassLoader] Match callable() type for parameters not defined in sub classes
2019-01-27 11:31:13 +01:00
Thomas Calvet
97a066c39a [Debug][DebugClassLoader] Match callable() type for parameters not defined in sub classes 2019-01-26 12:58:26 +01:00
Nicolas Grekas
4b3f518420 Merge branch '4.2'
* 4.2:
  [HttpFoundation] Check file exists before unlink
  [Console] Fixed #29835: ConfirmationQuestion with default true for answer '0'
  [Cache] PDO-based cache pool table autocreation does not work
  [Translation] Concatenated translation messages
  [Form] ensure compatibility with older PHPUnit mocks
  [Serializer] Docblock about throwing exceptions on serializer
  [Cache] fix used variable name
  [Debug][ErrorHandler] Preserve our error handler when a logger set another one
  [Form] Changed UrlType input type to text when default_protocol is not null
  [Bugfix] MemcachedSessionHandler::close() must close connection
  Always pass $key to NullAdapter->createCacheItem
2019-01-25 15:35:46 +01:00
Nicolas Grekas
643df31c6a Merge branch '4.2'
* 4.2:
  Bump phpunit bridge cache id
  [appveyor] fix create-project phpunit
  Fix HttpKernel Debug requirement
  Fix heredoc
  use final annotation to allow mocking the class
  synchronise the form builder docblock
  Grammar fix in exception message
  fix tests
  forward the parse error to the calling code
  Avoid dots in generated class names.
  [Debug][DebugClassLoader] Match more cases for final, deprecated and internal classes / methods extends
  ensure compatibility with older PHPUnit mocks
  [Security] Do not mix usage of password_*() functions and sodium_*() ones
2019-01-24 22:40:22 +01:00
Fabien Potencier
7cdd4f6f12 fixed CS 2019-01-16 23:37:52 +01:00
Fabien Potencier
f49c101672 fixed CS 2019-01-16 22:53:45 +01:00
Fabien Potencier
9f1401aebf Merge branch '4.2' into short-array-master
* 4.2:
  fixed CS
  fixed CS
  fixed tests
  fixed CS
  fixed CS
  fixed CS
  fixed short array CS in comments
  fixed CS in ExpressionLanguage fixtures
  fixed CS in generated files
  fixed CS on generated container files
  fixed CS on Form PHP templates
  fixed CS on YAML fixtures
  fixed fixtures
  switched array() to []
2019-01-16 22:53:39 +01:00
Fabien Potencier
789a7a9031 Merge branch '4.2'
* 4.2:
  bump required Twig version
  fix compatibility with Twig >= 2.6.1
  [Form] SA fix
  fix compatibility with PHPUnit 4.8
  remove return type hint for PHP 5 compatibility
  SCA: minor code tweaks
  Component CssSelector tests
  [DebugClassLoader] Readd findFile() method
  [Console] Fix composer.json suggest/provide
  Revert "bug #29597 [DI] fix reporting bindings on overriden services as unused (nicolas-grekas)"
  Fixed exception wording
  Fix SwiftMailerHandler to support Monolog's latest reset functionality
2019-01-14 16:34:34 +01:00
Fabien Potencier
b04503aa3b feature #28902 [Debug] Detect virtual methods using @method (ro0NL)
This PR was squashed before being merged into the 4.3-dev branch (closes #28902).

Discussion
----------

[Debug] Detect virtual methods using @method

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | no
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | https://github.com/symfony/symfony/pull/28897#issuecomment-430542792
| License       | MIT
| Doc PR        | https://github.com/symfony/symfony-docs/issues/10504

My first Debug PR, so im still on it. But early feedback welcome.

In #28901 we'll introduce a new virtual interface method using `@method` annotation. IIUC the idea is to trigger whenever such a method is overridden.

Commits
-------

38877c32ac [Debug] Detect virtual methods using @method
2019-01-05 09:11:12 +01:00
Roland Franssen
42fa73a995 [Debug] Detect virtual methods using @method 2019-01-05 09:11:02 +01:00
Christian Flothmann
c0ed02a95c Merge branch '4.2'
* 4.2:
  update years in license files
  Fix: Adjust DocBlock
  \"ParserTest->getParserTestData()\" -> only some more tests
  access the container getting it from the kernel
  Replace slave and master by replica and primary
  Fix erasing cookies issue
  [Lock] Pedantic improvements for lock
  [EventDispatcher] Fixed phpdoc on interface
  update year in license files
  [VarExporter] fix exporting array indexes
  [SecurityBundle] Fix traceable voters
  [Console] Fix help text for single command applications
  Fix random test failure on lock
  improve error message when using test client without the BrowserKit component
  Fixed minor typos in an error message
  [Event Dispatcher] fixed 29703: TraceableEventDispatcher reset now sets callStack to null with test to dispatch after reset.
  Fixed minor typos
  Fix: Method can also return null
  [Stopwatch] Fixed phpdoc for category name
2019-01-03 10:16:58 +01:00
Nicolas Grekas
7f2f295f38 Merge branch '4.2'
* 4.2: (27 commits)
  [VarExporter] dont call userland code with uninitialized objects
  Fix typos in doc blocks
  [Debug] ignore underscore vs backslash namespaces in DebugClassLoader
  [TwigBridge][Form] Prevent multiple rendering of form collection prototypes
  [FrameworkBundle] fix describing routes with no controllers
  [DI] move RegisterServiceSubscribersPass before DecoratorServicePass
  Update ValidationListener.php
  [Yaml] ensures that the mb_internal_encoding is reset to its initial value
  [Messenger] Restore message handlers laziness
  [WebLink] Fixed documentation link
  [Security] getTargetPath of TargetPathTrait must return string or null
  [Hackday][Serializer] Deserialization ignores argument type hint from phpdoc for array in constructor argument
  Optimize perf by replacing call_user_func with dynamic vars
  [Cache] Fix dsn parsing
  [Routing] fix dumping same-path routes with placeholders
  [WebProfilerBundle][TwigBundle] CSS fixes
  Add a docblock for FormFactoryInterface
  [Security] defer log message in guard authenticator
  [Validator] Added IBAN format for Vatican City State
  merge conflicts
  ...
2018-12-13 13:43:21 +01:00
Nicolas Grekas
170e2f8f61 feature #28954 [Debug] Mark ErrorHandler and ExceptionHandler classes as final (fancyweb)
This PR was merged into the 4.3-dev branch.

Discussion
----------

[Debug] Mark ErrorHandler and ExceptionHandler classes as final

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | not yet
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

The goal of marking this method final is to be able to change the argument signature to `\Throwable` in Symfony 5.0

We will then be able to convert the incoming `\Throwable` to `\ErrorException` thanks to the `FatalThrowableError` class.

The use case is when you use the `ExceptionHandler::register()` method of the `Debug` component with a custom `set_error_handler()` that don't handle this conversion. This is for example the case of the `Drupal` one.

Commits
-------

2a4e2e614b [Debug] Mark the ErrorHandler and ExceptionHandler classes as final
2018-12-01 11:04:56 +01:00
Nicolas Grekas
e597d2960c Merge branch '4.2'
* 4.2:
  [DI] fix combinatorial explosion when analyzing the service graph
  [Debug] workaround opcache bug mutating "$this" !?!
2018-11-28 19:24:33 +01:00
Fabien Potencier
fbd644bb30 updated version to 4.3 2018-11-26 17:19:01 +01:00
Thomas Calvet
436274c5b8 [Debug] Mark the ErrorHandler and ExceptionHandler classes as final 2018-10-23 11:56:45 +02:00
26 changed files with 524 additions and 165 deletions

View File

@@ -1,6 +1,14 @@
CHANGELOG
=========
4.3.0
-----
* made the `ErrorHandler` and `ExceptionHandler` classes final
* added `Exception\FlattenException::getAsString` and
`Exception\FlattenException::getTraceAsString` to increase compatibility to php
exception objects
4.0.0
-----

View File

@@ -39,6 +39,7 @@ class DebugClassLoader
private static $internalMethods = [];
private static $annotatedParameters = [];
private static $darwinCache = ['/' => ['/', []]];
private static $method = [];
public function __construct(callable $classLoader)
{
@@ -152,11 +153,11 @@ class DebugClassLoader
if (!$file = $this->classLoader[0]->findFile($class) ?: false) {
// no-op
} elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) {
require $file;
include $file;
return;
} else {
require $file;
} elseif (false === include $file) {
return;
}
} else {
($this->classLoader)($class);
@@ -171,7 +172,7 @@ class DebugClassLoader
private function checkClass($class, $file = null)
{
$exists = null === $file || \class_exists($class, false) || \interface_exists($class, false) || \trait_exists($class, false);
$exists = null === $file || class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false);
if (null !== $file && $class && '\\' === $class[0]) {
$class = substr($class, 1);
@@ -189,7 +190,7 @@ class DebugClassLoader
}
$name = $refl->getName();
if ($name !== $class && 0 === \strcasecmp($name, $class)) {
if ($name !== $class && 0 === strcasecmp($name, $class)) {
throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: "%s" vs "%s".', $class, $name));
}
@@ -222,23 +223,41 @@ class DebugClassLoader
$deprecations = [];
// Don't trigger deprecations for classes in the same vendor
if (2 > $len = 1 + (\strpos($class, '\\') ?: \strpos($class, '_'))) {
if (2 > $len = 1 + (strpos($class, '\\') ?: strpos($class, '_'))) {
$len = 0;
$ns = '';
} else {
$ns = \str_replace('_', '\\', \substr($class, 0, $len));
$ns = str_replace('_', '\\', substr($class, 0, $len));
}
// Detect annotations on the class
if (false !== $doc = $refl->getDocComment()) {
foreach (['final', 'deprecated', 'internal'] as $annotation) {
if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$)#s', $doc, $notice)) {
if (false !== strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
self::${$annotation}[$class] = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : '';
}
}
if ($refl->isInterface() && false !== strpos($doc, 'method') && preg_match_all('#\n \* @method\s+(static\s+)?+(?:[\w\|&\[\]\\\]+\s+)?(\w+(?:\s*\([^\)]*\))?)+(.+?([[:punct:]]\s*)?)?(?=\r?\n \*(?: @|/$|\r?\n))#', $doc, $notice, PREG_SET_ORDER)) {
foreach ($notice as $method) {
$static = '' !== $method[1];
$name = $method[2];
$description = $method[3] ?? null;
if (false === strpos($name, '(')) {
$name .= '()';
}
if (null !== $description) {
$description = trim($description);
if (!isset($method[4])) {
$description .= '.';
}
}
self::$method[$class][] = [$class, $name, $static, $description];
}
}
}
$parent = \get_parent_class($class);
$parent = get_parent_class($class);
$parentAndOwnInterfaces = $this->getOwnInterfaces($class, $parent);
if ($parent) {
$parentAndOwnInterfaces[$parent] = $parent;
@@ -253,22 +272,44 @@ class DebugClassLoader
}
// Detect if the parent is annotated
foreach ($parentAndOwnInterfaces + \class_uses($class, false) as $use) {
foreach ($parentAndOwnInterfaces + class_uses($class, false) as $use) {
if (!isset(self::$checkedClasses[$use])) {
$this->checkClass($use);
}
if (isset(self::$deprecated[$use]) && \strncmp($ns, \str_replace('_', '\\', $use), $len)) {
if (isset(self::$deprecated[$use]) && strncmp($ns, str_replace('_', '\\', $use), $len) && !isset(self::$deprecated[$class])) {
$type = class_exists($class, false) ? 'class' : (interface_exists($class, false) ? 'interface' : 'trait');
$verb = class_exists($use, false) || interface_exists($class, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses');
$deprecations[] = sprintf('The "%s" %s %s "%s" that is deprecated%s.', $class, $type, $verb, $use, self::$deprecated[$use]);
}
if (isset(self::$internal[$use]) && \strncmp($ns, \str_replace('_', '\\', $use), $len)) {
if (isset(self::$internal[$use]) && strncmp($ns, str_replace('_', '\\', $use), $len)) {
$deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $class);
}
if (isset(self::$method[$use])) {
if ($refl->isAbstract()) {
if (isset(self::$method[$class])) {
self::$method[$class] = array_merge(self::$method[$class], self::$method[$use]);
} else {
self::$method[$class] = self::$method[$use];
}
} elseif (!$refl->isInterface()) {
$hasCall = $refl->hasMethod('__call');
$hasStaticCall = $refl->hasMethod('__callStatic');
foreach (self::$method[$use] as $method) {
list($interface, $name, $static, $description) = $method;
if ($static ? $hasStaticCall : $hasCall) {
continue;
}
$realName = substr($name, 0, strpos($name, '('));
if (!$refl->hasMethod($realName) || !($methodRefl = $refl->getMethod($realName))->isPublic() || ($static && !$methodRefl->isStatic()) || (!$static && $methodRefl->isStatic())) {
$deprecations[] = sprintf('Class "%s" should implement method "%s::%s"%s', $class, ($static ? 'static ' : '').$interface, $name, null == $description ? '.' : ': '.$description);
}
}
}
}
}
if (\trait_exists($class)) {
if (trait_exists($class)) {
return $deprecations;
}
@@ -296,7 +337,7 @@ class DebugClassLoader
if (isset(self::$internalMethods[$class][$method->name])) {
list($declaringClass, $message) = self::$internalMethods[$class][$method->name];
if (\strncmp($ns, $declaringClass, $len)) {
if (strncmp($ns, $declaringClass, $len)) {
$deprecations[] = sprintf('The "%s::%s()" method is considered internal%s. It may change without further notice. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class);
}
}
@@ -311,7 +352,7 @@ class DebugClassLoader
}
foreach (self::$annotatedParameters[$class][$method->name] as $parameterName => $deprecation) {
if (!isset($definedParameters[$parameterName]) && !($doc && preg_match("/\\n\\s+\\* @param (.*?)(?<= )\\\${$parameterName}\\b/", $doc))) {
if (!isset($definedParameters[$parameterName]) && !($doc && preg_match("/\\n\\s+\\* @param +((?(?!callable *\().*?|callable *\(.*\).*?))(?<= )\\\${$parameterName}\\b/", $doc))) {
$deprecations[] = sprintf($deprecation, $class);
}
}
@@ -324,17 +365,17 @@ class DebugClassLoader
$finalOrInternal = false;
foreach (['final', 'internal'] as $annotation) {
if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$)#s', $doc, $notice)) {
if (false !== strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) {
$message = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : '';
self::${$annotation.'Methods'}[$class][$method->name] = [$class, $message];
$finalOrInternal = true;
}
}
if ($finalOrInternal || $method->isConstructor() || false === \strpos($doc, '@param') || StatelessInvocation::class === $class) {
if ($finalOrInternal || $method->isConstructor() || false === strpos($doc, '@param') || StatelessInvocation::class === $class) {
continue;
}
if (!preg_match_all('#\n\s+\* @param (.*?)(?<= )\$([a-zA-Z0-9_\x7f-\xff]++)#', $doc, $matches, PREG_SET_ORDER)) {
if (!preg_match_all('#\n\s+\* @param +((?(?!callable *\().*?|callable *\(.*\).*?))(?<= )\$([a-zA-Z0-9_\x7f-\xff]++)#', $doc, $matches, PREG_SET_ORDER)) {
continue;
}
if (!isset(self::$annotatedParameters[$class][$method->name])) {
@@ -354,6 +395,12 @@ class DebugClassLoader
return $deprecations;
}
/**
* @param string $file
* @param string $class
*
* @return array|null
*/
public function checkCase(\ReflectionClass $refl, $file, $class)
{
$real = explode('\\', $class.strrchr($file, '.'));
@@ -370,7 +417,7 @@ class DebugClassLoader
array_splice($tail, 0, $i + 1);
if (!$tail) {
return;
return null;
}
$tail = \DIRECTORY_SEPARATOR.implode(\DIRECTORY_SEPARATOR, $tail);
@@ -386,6 +433,8 @@ class DebugClassLoader
) {
return [substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1)];
}
return null;
}
/**
@@ -406,7 +455,11 @@ class DebugClassLoader
$real = self::$darwinCache[$kDir][0];
} else {
$dir = getcwd();
chdir($real);
if (!@chdir($real)) {
return $real.$file;
}
$real = getcwd().'/';
chdir($dir);
@@ -433,7 +486,7 @@ class DebugClassLoader
}
if (isset($dirFiles[$file])) {
return $real .= $dirFiles[$file];
return $real.$dirFiles[$file];
}
$kFile = strtolower($file);
@@ -452,7 +505,7 @@ class DebugClassLoader
self::$darwinCache[$kDir][1] = $dirFiles;
}
return $real .= $dirFiles[$kFile];
return $real.$dirFiles[$kFile];
}
/**

View File

@@ -45,6 +45,8 @@ use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler;
*
* @author Nicolas Grekas <p@tchwork.com>
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*
* @final since Symfony 4.3
*/
class ErrorHandler
{
@@ -380,6 +382,10 @@ class ErrorHandler
*/
public function handleError($type, $message, $file, $line)
{
if (\PHP_VERSION_ID >= 70300 && E_WARNING === $type && '"' === $message[0] && false !== strpos($message, '" targeting switch is equivalent to "break')) {
$type = E_DEPRECATED;
}
// Level is the current error reporting level to manage silent error.
$level = error_reporting();
$silenced = 0 === ($level & $type);
@@ -436,7 +442,7 @@ class ErrorHandler
self::$silencedErrorCache[$id][$message] = $errorAsException;
}
if (null === $lightTrace) {
return;
return true;
}
} else {
$errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line);
@@ -452,7 +458,7 @@ class ErrorHandler
}
if ($throw) {
if (E_USER_ERROR & $type) {
if (\PHP_VERSION_ID < 70400 && E_USER_ERROR & $type) {
for ($i = 1; isset($backtrace[$i]); ++$i) {
if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function'])
&& '__toString' === $backtrace[$i]['function']
@@ -569,7 +575,9 @@ class ErrorHandler
$this->exceptionHandler = null;
try {
if (null !== $exceptionHandler) {
return $exceptionHandler($exception);
$exceptionHandler($exception);
return;
}
$handlerException = $handlerException ?: $exception;
} catch (\Throwable $handlerException) {

View File

@@ -27,6 +27,7 @@ class FlattenException
private $code;
private $previous;
private $trace;
private $traceAsString;
private $class;
private $statusCode;
private $headers;
@@ -172,7 +173,7 @@ class FlattenException
{
if (false !== strpos($message, "class@anonymous\0")) {
$message = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) {
return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
return class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0];
}, $message);
}
@@ -239,6 +240,8 @@ class FlattenException
public function setTraceFromThrowable(\Throwable $throwable)
{
$this->traceAsString = $throwable->getTraceAsString();
return $this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine());
}
@@ -324,4 +327,33 @@ class FlattenException
return $array['__PHP_Incomplete_Class_Name'];
}
public function getTraceAsString()
{
return $this->traceAsString;
}
public function getAsString()
{
$message = '';
$next = false;
foreach (array_reverse(array_merge([$this], $this->getAllPrevious())) as $exception) {
if ($next) {
$message .= 'Next ';
} else {
$next = true;
}
$message .= $exception->getClass();
if ('' != $exception->getMessage()) {
$message .= ': '.$exception->getMessage();
}
$message .= ' in '.$exception->getFile().':'.$exception->getLine().
"\nStack trace:\n".$exception->getTraceAsString()."\n\n";
}
return rtrim($message);
}
}

View File

@@ -54,7 +54,7 @@ class SilencedErrorContext implements \JsonSerializable
return $this->trace;
}
public function JsonSerialize()
public function jsonSerialize()
{
return [
'severity' => $this->severity,

File diff suppressed because one or more lines are too long

View File

@@ -33,11 +33,11 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
$notFoundSuffix = '\' not found';
$notFoundSuffixLen = \strlen($notFoundSuffix);
if ($notFoundSuffixLen > $messageLen) {
return;
return null;
}
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
return;
return null;
}
foreach (['class', 'interface', 'trait'] as $typeName) {
@@ -71,6 +71,8 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
return new ClassNotFoundException($message, $exception);
}
return null;
}
/**
@@ -171,7 +173,11 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
}
}
require_once $file;
try {
require_once $file;
} catch (\Throwable $e) {
return null;
}
foreach ($candidates as $candidate) {
if ($this->classExists($candidate)) {

View File

@@ -30,17 +30,17 @@ class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface
$notFoundSuffix = '()';
$notFoundSuffixLen = \strlen($notFoundSuffix);
if ($notFoundSuffixLen > $messageLen) {
return;
return null;
}
if (0 !== substr_compare($error['message'], $notFoundSuffix, -$notFoundSuffixLen)) {
return;
return null;
}
$prefix = 'Call to undefined function ';
$prefixLen = \strlen($prefix);
if (0 !== strpos($error['message'], $prefix)) {
return;
return null;
}
$fullyQualifiedFunctionName = substr($error['message'], $prefixLen, -$notFoundSuffixLen);

View File

@@ -28,7 +28,7 @@ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface
{
preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $error['message'], $matches);
if (!$matches) {
return;
return null;
}
$className = $matches[1];

View File

@@ -23,7 +23,7 @@ class DebugClassLoaderTest extends TestCase
private $loader;
protected function setUp()
protected function setUp(): void
{
$this->errorReporting = error_reporting(E_ALL);
$this->loader = new ClassLoader();
@@ -31,7 +31,7 @@ class DebugClassLoaderTest extends TestCase
DebugClassLoader::enable();
}
protected function tearDown()
protected function tearDown(): void
{
DebugClassLoader::disable();
spl_autoload_unregister([$this->loader, 'loadClass']);
@@ -58,12 +58,10 @@ class DebugClassLoaderTest extends TestCase
$this->fail('DebugClassLoader did not register');
}
/**
* @expectedException \Exception
* @expectedExceptionMessage boo
*/
public function testThrowingClass()
{
$this->expectException('Exception');
$this->expectExceptionMessage('boo');
try {
class_exists(__NAMESPACE__.'\Fixtures\Throwing');
$this->fail('Exception expected');
@@ -75,20 +73,17 @@ class DebugClassLoaderTest extends TestCase
class_exists(__NAMESPACE__.'\Fixtures\Throwing');
}
/**
* @expectedException \RuntimeException
*/
public function testNameCaseMismatch()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Case mismatch between loaded and declared class names');
class_exists(__NAMESPACE__.'\TestingCaseMismatch', true);
}
/**
* @expectedException \RuntimeException
* @expectedExceptionMessage Case mismatch between class and real file names
*/
public function testFileCaseMismatch()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Case mismatch between class and real file names');
if (!file_exists(__DIR__.'/Fixtures/CaseMismatch.php')) {
$this->markTestSkipped('Can only be run on case insensitive filesystems');
}
@@ -96,11 +91,10 @@ class DebugClassLoaderTest extends TestCase
class_exists(__NAMESPACE__.'\Fixtures\CaseMismatch', true);
}
/**
* @expectedException \RuntimeException
*/
public function testPsr4CaseMismatch()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Case mismatch between loaded and declared class names');
class_exists(__NAMESPACE__.'\Fixtures\Psr4CaseMismatch', true);
}
@@ -294,6 +288,11 @@ class DebugClassLoaderTest extends TestCase
$this->assertSame([
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::quzMethod()" method will require a new "Quz $quz" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::whereAmI()" method will require a new "bool $matrix" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "$noType" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable(\Throwable|null $reason, mixed $value) $callback" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "string $param" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable ($a, $b) $anotherOne" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "Type$WithDollarIsStillAType $ccc" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.',
'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::isSymfony()" method will require a new "true $yes" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.',
], $deprecations);
}
@@ -312,6 +311,46 @@ class DebugClassLoaderTest extends TestCase
$this->assertSame([], $deprecations);
}
public function testVirtualUse()
{
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsVirtual', true);
error_reporting($e);
restore_error_handler();
$this->assertSame([
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::sameLineInterfaceMethodNoBraces()".',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::newLineInterfaceMethod()": Some description!',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::newLineInterfaceMethodNoBraces()": Description.',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::invalidInterfaceMethod()".',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::invalidInterfaceMethodNoBraces()".',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::complexInterfaceMethod($arg, ...$args)".',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::complexInterfaceMethodTyped($arg, int ...$args)": Description ...',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "static Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::staticMethodNoBraces()".',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "static Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::staticMethodTyped(int $arg)": Description.',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "static Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::staticMethodTypedNoBraces()".',
'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtual" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualSubInterface::subInterfaceMethod()".',
], $deprecations);
}
public function testVirtualUseWithMagicCall()
{
$deprecations = [];
set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; });
$e = error_reporting(E_USER_DEPRECATED);
class_exists('Test\\'.__NAMESPACE__.'\\ExtendsVirtualMagicCall', true);
error_reporting($e);
restore_error_handler();
$this->assertSame([], $deprecations);
}
public function testEvaluatedCode()
{
$this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\DefinitionInEvaluatedCode', true));
@@ -372,6 +411,34 @@ class ClassLoader
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternalsParent extends \\'.__NAMESPACE__.'\Fixtures\InternalClass implements \\'.__NAMESPACE__.'\Fixtures\InternalInterface { }');
} elseif ('Test\\'.__NAMESPACE__.'\UseTraitWithInternalMethod' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; class UseTraitWithInternalMethod { use \\'.__NAMESPACE__.'\Fixtures\TraitWithInternalMethod; }');
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtual' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtual extends ExtendsVirtualParent implements \\'.__NAMESPACE__.'\Fixtures\VirtualSubInterface {
public function ownClassMethod() { }
public function classMethod() { }
public function sameLineInterfaceMethodNoBraces() { }
}');
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualParent' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtualParent extends ExtendsVirtualAbstract {
public function ownParentMethod() { }
public function traitMethod() { }
public function sameLineInterfaceMethod() { }
public function staticMethodNoBraces() { } // should be static
}');
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualAbstract' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; abstract class ExtendsVirtualAbstract extends ExtendsVirtualAbstractBase {
public static function staticMethod() { }
public function ownAbstractMethod() { }
public function interfaceMethod() { }
}');
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualAbstractBase' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; abstract class ExtendsVirtualAbstractBase extends \\'.__NAMESPACE__.'\Fixtures\VirtualClass implements \\'.__NAMESPACE__.'\Fixtures\VirtualInterface {
public function ownAbstractBaseMethod() { }
}');
} elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualMagicCall' === $class) {
eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtualMagicCall extends \\'.__NAMESPACE__.'\Fixtures\VirtualClassMagicCall implements \\'.__NAMESPACE__.'\Fixtures\VirtualInterface {
}');
}
return null;
}
}

View File

@@ -70,8 +70,8 @@ class ErrorHandlerTest extends TestCase
public function testErrorGetLast()
{
$handler = ErrorHandler::register();
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler = ErrorHandler::register();
$handler->setDefaultLogger($logger);
$handler->screamAt(E_ALL);
@@ -143,9 +143,8 @@ class ErrorHandlerTest extends TestCase
public function testDefaultLogger()
{
try {
$handler = ErrorHandler::register();
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler = ErrorHandler::register();
$handler->setDefaultLogger($logger, E_NOTICE);
$handler->setDefaultLogger($logger, [E_USER_NOTICE => LogLevel::CRITICAL]);
@@ -234,7 +233,7 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->once())
->method('log')
->will($this->returnCallback($warnArgCheck))
->willReturnCallback($warnArgCheck)
;
$handler = ErrorHandler::register();
@@ -262,7 +261,7 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->once())
->method('log')
->will($this->returnCallback($logArgCheck))
->willReturnCallback($logArgCheck)
;
$handler = ErrorHandler::register();
@@ -284,6 +283,10 @@ class ErrorHandlerTest extends TestCase
public function testHandleUserError()
{
if (\PHP_VERSION_ID >= 70400) {
$this->markTestSkipped('PHP 7.4 allows __toString to throw exceptions');
}
try {
$handler = ErrorHandler::register();
$handler->throwAt(0, true);
@@ -318,7 +321,7 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->once())
->method('log')
->will($this->returnCallback($logArgCheck))
->willReturnCallback($logArgCheck)
;
$handler = new ErrorHandler();
@@ -331,12 +334,11 @@ class ErrorHandlerTest extends TestCase
public function testHandleException()
{
try {
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler = ErrorHandler::register();
$exception = new \Exception('foo');
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logArgCheck = function ($level, $message, $context) {
$this->assertSame('Uncaught Exception: foo', $message);
$this->assertArrayHasKey('exception', $context);
@@ -346,7 +348,7 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->exactly(2))
->method('log')
->will($this->returnCallback($logArgCheck))
->willReturnCallback($logArgCheck)
;
$handler->setDefaultLogger($logger, E_ERROR);
@@ -442,6 +444,7 @@ class ErrorHandlerTest extends TestCase
public function testHandleFatalError()
{
try {
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$handler = ErrorHandler::register();
$error = [
@@ -451,8 +454,6 @@ class ErrorHandlerTest extends TestCase
'line' => 123,
];
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logArgCheck = function ($level, $message, $context) {
$this->assertEquals('Fatal Parse Error: foo', $message);
$this->assertArrayHasKey('exception', $context);
@@ -462,7 +463,7 @@ class ErrorHandlerTest extends TestCase
$logger
->expects($this->once())
->method('log')
->will($this->returnCallback($logArgCheck))
->willReturnCallback($logArgCheck)
;
$handler->setDefaultLogger($logger, E_PARSE);
@@ -481,7 +482,7 @@ class ErrorHandlerTest extends TestCase
public function testHandleErrorException()
{
$exception = new \Error("Class 'Foo' not found");
$exception = new \Error("Class 'IReallyReallyDoNotExistAnywhereInTheRepositoryISwear' not found");
$handler = new ErrorHandler();
$handler->setExceptionHandler(function () use (&$args) {
@@ -491,14 +492,12 @@ class ErrorHandlerTest extends TestCase
$handler->handleException($exception);
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $args[0]);
$this->assertStringStartsWith("Attempted to load class \"Foo\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
$this->assertStringStartsWith("Attempted to load class \"IReallyReallyDoNotExistAnywhereInTheRepositoryISwear\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage());
}
/**
* @expectedException \Exception
*/
public function testCustomExceptionHandler()
{
$this->expectException('Exception');
$handler = new ErrorHandler();
$handler->setExceptionHandler(function ($e) use ($handler) {
$handler->handleException($e);

View File

@@ -294,7 +294,7 @@ class FlattenExceptionTest extends TestCase
// assertEquals() does not like NAN values.
$this->assertEquals($array[$i][0], 'float');
$this->assertTrue(is_nan($array[$i++][1]));
$this->assertNan($array[$i][1]);
}
public function testRecursionInArguments()
@@ -305,7 +305,7 @@ class FlattenExceptionTest extends TestCase
$flattened = FlattenException::create($exception);
$trace = $flattened->getTrace();
$this->assertContains('*DEEP NESTED ARRAY*', serialize($trace));
$this->assertStringContainsString('*DEEP NESTED ARRAY*', serialize($trace));
}
public function testTooBigArray()
@@ -329,8 +329,8 @@ class FlattenExceptionTest extends TestCase
$serializeTrace = serialize($trace);
$this->assertContains('*SKIPPED over 10000 entries*', $serializeTrace);
$this->assertNotContains('*value1*', $serializeTrace);
$this->assertStringContainsString('*SKIPPED over 10000 entries*', $serializeTrace);
$this->assertStringNotContainsString('*value1*', $serializeTrace);
}
public function testAnonymousClass()
@@ -346,6 +346,41 @@ class FlattenExceptionTest extends TestCase
$this->assertSame('Class "RuntimeException@anonymous" blah.', $flattened->getMessage());
}
public function testToStringEmptyMessage()
{
$exception = new \RuntimeException();
$flattened = FlattenException::create($exception);
$this->assertSame($exception->getTraceAsString(), $flattened->getTraceAsString());
$this->assertSame($exception->__toString(), $flattened->getAsString());
}
public function testToString()
{
$test = function ($a, $b, $c, $d) {
return new \RuntimeException('This is a test message');
};
$exception = $test('foo123', 1, null, 1.5);
$flattened = FlattenException::create($exception);
$this->assertSame($exception->getTraceAsString(), $flattened->getTraceAsString());
$this->assertSame($exception->__toString(), $flattened->getAsString());
}
public function testToStringParent()
{
$exception = new \LogicException('This is message 1');
$exception = new \RuntimeException('This is messsage 2', 500, $exception);
$flattened = FlattenException::create($exception);
$this->assertSame($exception->getTraceAsString(), $flattened->getTraceAsString());
$this->assertSame($exception->__toString(), $flattened->getAsString());
}
private function createException($foo)
{
return new \Exception();

View File

@@ -21,12 +21,12 @@ require_once __DIR__.'/HeaderMock.php';
class ExceptionHandlerTest extends TestCase
{
protected function setUp()
protected function setUp(): void
{
testHeader();
}
protected function tearDown()
protected function tearDown(): void
{
testHeader();
}
@@ -39,8 +39,8 @@ class ExceptionHandlerTest extends TestCase
$handler->sendPhpResponse(new \RuntimeException('Foo'));
$response = ob_get_clean();
$this->assertContains('Whoops, looks like something went wrong.', $response);
$this->assertNotContains('<div class="trace trace-as-html">', $response);
$this->assertStringContainsString('Whoops, looks like something went wrong.', $response);
$this->assertStringNotContainsString('<div class="trace trace-as-html">', $response);
$handler = new ExceptionHandler(true);
@@ -48,8 +48,17 @@ class ExceptionHandlerTest extends TestCase
$handler->sendPhpResponse(new \RuntimeException('Foo'));
$response = ob_get_clean();
$this->assertContains('Whoops, looks like something went wrong.', $response);
$this->assertContains('<div class="trace trace-as-html">', $response);
$this->assertStringContainsString('<h1 class="break-long-words exception-message">Foo</h1>', $response);
$this->assertStringContainsString('<div class="trace trace-as-html">', $response);
// taken from https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)
$htmlWithXss = '<body onload=alert(\'test1\')> <b onmouseover=alert(\'Wufff!\')>click me!</b> <img src="j&#X41vascript:alert(\'test2\')"> <meta http-equiv="refresh"
content="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg">';
ob_start();
$handler->sendPhpResponse(new \RuntimeException($htmlWithXss));
$response = ob_get_clean();
$this->assertStringContainsString(sprintf('<h1 class="break-long-words exception-message">%s</h1>', htmlspecialchars($htmlWithXss, ENT_COMPAT | ENT_SUBSTITUTE, 'UTF-8')), $response);
}
public function testStatusCode()
@@ -60,7 +69,7 @@ class ExceptionHandlerTest extends TestCase
$handler->sendPhpResponse(new NotFoundHttpException('Foo'));
$response = ob_get_clean();
$this->assertContains('Sorry, the page you are looking for could not be found.', $response);
$this->assertStringContainsString('Sorry, the page you are looking for could not be found.', $response);
$expectedHeaders = [
['HTTP/1.0 404', true, null],
@@ -76,7 +85,7 @@ class ExceptionHandlerTest extends TestCase
ob_start();
$handler->sendPhpResponse(new MethodNotAllowedHttpException(['POST']));
$response = ob_get_clean();
ob_get_clean();
$expectedHeaders = [
['HTTP/1.0 405', true, null],
@@ -99,35 +108,65 @@ class ExceptionHandlerTest extends TestCase
public function testHandle()
{
$exception = new \Exception('foo');
$handler = new ExceptionHandler(true);
ob_start();
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(['sendPhpResponse'])->getMock();
$handler
->expects($this->exactly(2))
->method('sendPhpResponse');
$handler->handle(new \Exception('foo'));
$handler->handle($exception);
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'foo');
}
$handler->setHandler(function ($e) use ($exception) {
$this->assertSame($exception, $e);
public function testHandleWithACustomHandlerThatOutputsSomething()
{
$handler = new ExceptionHandler(true);
ob_start();
$handler->setHandler(function () {
echo 'ccc';
});
$handler->handle($exception);
$handler->handle(new \Exception());
ob_end_flush(); // Necessary because of this PHP bug : https://bugs.php.net/76563
$this->assertSame('ccc', ob_get_clean());
}
public function testHandleWithACustomHandlerThatOutputsNothing()
{
$handler = new ExceptionHandler(true);
$handler->setHandler(function () {});
$handler->handle(new \Exception('ccc'));
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc');
}
public function testHandleWithACustomHandlerThatFails()
{
$handler = new ExceptionHandler(true);
$handler->setHandler(function () {
throw new \RuntimeException();
});
$handler->handle(new \Exception('ccc'));
$this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc');
}
public function testHandleOutOfMemoryException()
{
$exception = new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__);
$handler = $this->getMockBuilder('Symfony\Component\Debug\ExceptionHandler')->setMethods(['sendPhpResponse'])->getMock();
$handler
->expects($this->once())
->method('sendPhpResponse');
$handler->setHandler(function ($e) {
$handler = new ExceptionHandler(true);
ob_start();
$handler->setHandler(function () {
$this->fail('OutOfMemoryException should bypass the handler');
});
$handler->handle($exception);
$handler->handle(new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__));
$this->assertThatTheExceptionWasOutput(ob_get_clean(), OutOfMemoryException::class, 'OutOfMemoryException', 'foo');
}
private function assertThatTheExceptionWasOutput($content, $expectedClass, $expectedTitle, $expectedMessage)
{
$this->assertStringContainsString(sprintf('<span class="exception_title"><abbr title="%s">%s</abbr></span>', $expectedClass, $expectedTitle), $content);
$this->assertStringContainsString(sprintf('<p class="break-long-words trace-message">%s</p>', $expectedMessage), $content);
}
}

View File

@@ -19,7 +19,7 @@ use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler;
class ClassNotFoundFatalErrorHandlerTest extends TestCase
{
public static function setUpBeforeClass()
public static function setUpBeforeClass(): void
{
foreach (spl_autoload_functions() as $function) {
if (!\is_array($function)) {
@@ -32,7 +32,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
}
if ($function[0] instanceof ComposerClassLoader) {
$function[0]->add('Symfony_Component_Debug_Tests_Fixtures', \dirname(\dirname(\dirname(\dirname(\dirname(__DIR__))))));
$function[0]->add('Symfony_Component_Debug_Tests_Fixtures', \dirname(__DIR__, 5));
break;
}
}
@@ -61,7 +61,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
}
$this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $exception);
$this->assertSame($translatedMessage, $exception->getMessage());
$this->assertRegExp($translatedMessage, $exception->getMessage());
$this->assertSame($error['type'], $exception->getSeverity());
$this->assertSame($error['file'], $exception->getFile());
$this->assertSame($error['line'], $exception->getLine());
@@ -71,6 +71,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
{
$autoloader = new ComposerClassLoader();
$autoloader->add('Symfony\Component\Debug\Exception\\', realpath(__DIR__.'/../../Exception'));
$autoloader->add('Symfony_Component_Debug_Tests_Fixtures', realpath(__DIR__.'/../../Tests/Fixtures'));
$debugClassLoader = new DebugClassLoader([$autoloader, 'loadClass']);
@@ -82,7 +83,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
'file' => 'foo.php',
'message' => 'Class \'WhizBangFactory\' not found',
],
"Attempted to load class \"WhizBangFactory\" from the global namespace.\nDid you forget a \"use\" statement?",
"/^Attempted to load class \"WhizBangFactory\" from the global namespace.\nDid you forget a \"use\" statement\?$/",
],
[
[
@@ -91,7 +92,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\WhizBangFactory\' not found',
],
"Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?",
"/^Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/",
],
[
[
@@ -100,7 +101,8 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
'file' => 'foo.php',
'message' => 'Class \'UndefinedFunctionException\' not found',
],
"Attempted to load class \"UndefinedFunctionException\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
"/^Attempted to load class \"UndefinedFunctionException\" from the global namespace.\nDid you forget a \"use\" statement for .*\"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?$/",
[$debugClassLoader, 'loadClass'],
],
[
[
@@ -109,35 +111,7 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
'file' => 'foo.php',
'message' => 'Class \'PEARClass\' not found',
],
"Attempted to load class \"PEARClass\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony_Component_Debug_Tests_Fixtures_PEARClass\"?",
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
],
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
],
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
[$autoloader, 'loadClass'],
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
],
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\Bar\".\nDid you forget a \"use\" statement for \"Symfony\Component\Debug\Exception\UndefinedFunctionException\"?",
"/^Attempted to load class \"PEARClass\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony_Component_Debug_Tests_Fixtures_PEARClass\"\?$/",
[$debugClassLoader, 'loadClass'],
],
[
@@ -147,7 +121,37 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
],
"Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\Bar\".\nDid you forget a \"use\" statement for another namespace?",
"/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for .*\"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?$/",
[$debugClassLoader, 'loadClass'],
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
],
"/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for \"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?$/",
[$autoloader, 'loadClass'],
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
],
"/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for \"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?/",
[$debugClassLoader, 'loadClass'],
],
[
[
'type' => 1,
'line' => 12,
'file' => 'foo.php',
'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found',
],
"/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/",
function ($className) { /* do nothing here */ },
],
];

View File

@@ -30,6 +30,7 @@ class FinalClass3
/**
* @final
*
* @author John Doe
*/
class FinalClass4
@@ -63,7 +64,6 @@ class FinalClass6
* @author John Doe
*
* @final another
*
* multiline comment...
*
* @return string
@@ -76,6 +76,7 @@ class FinalClass7
/**
* @author John Doe
* @final
*
* @return string
*/
class FinalClass8

View File

@@ -13,6 +13,8 @@ class FinalMethod
/**
* @final
*
* @return int
*/
public function finalMethod2()
{

View File

@@ -11,4 +11,17 @@ interface InterfaceWithAnnotatedParameters
* @param bool $matrix
*/
public function whereAmI();
/**
* @param $noType
* @param callable(\Throwable|null $reason, mixed $value) $callback and a comment
* about this great param
* @param string $param (comment with $dollar)
* @param $defined
* @param callable ($a, $b) $anotherOne
* @param callable (mixed $a, $b) $definedCallable
* @param Type$WithDollarIsStillAType $ccc
* @param \JustAType
*/
public function iAmHere();
}

View File

@@ -21,4 +21,12 @@ class SubClassWithAnnotatedParameters extends ClassWithAnnotatedParameters imple
public function whereAmI()
{
}
/**
* @param $defined
* @param Type\Does\Not\Matter $definedCallable
*/
public function iAmHere()
{
}
}

View File

@@ -0,0 +1,11 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
/**
* @method string classMethod()
*/
class VirtualClass
{
use VirtualTrait;
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
/**
* @method string magicMethod()
* @method static string staticMagicMethod()
*/
class VirtualClassMagicCall
{
public static function __callStatic($name, $arguments)
{
}
public function __call($name, $arguments)
{
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
/**
* @method string interfaceMethod()
* @method sameLineInterfaceMethod($arg)
* @method sameLineInterfaceMethodNoBraces
*
* Ignored
* @method
* @method
*
* Not ignored
* @method newLineInterfaceMethod() Some description!
* @method \stdClass newLineInterfaceMethodNoBraces Description
*
* Invalid
* @method unknownType invalidInterfaceMethod()
* @method unknownType|string invalidInterfaceMethodNoBraces
*
* Complex
* @method complexInterfaceMethod($arg, ...$args)
* @method string[]|int complexInterfaceMethodTyped($arg, int ...$args) Description ...
*
* Static
* @method static Foo&Bar staticMethod()
* @method static staticMethodNoBraces
* @method static \stdClass staticMethodTyped(int $arg) Description
* @method static \stdClass[] staticMethodTypedNoBraces
*/
interface VirtualInterface
{
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
/**
* @method string subInterfaceMethod()
*/
interface VirtualSubInterface extends VirtualInterface
{
}

View File

@@ -0,0 +1,10 @@
<?php
namespace Symfony\Component\Debug\Tests\Fixtures;
/**
* @method string traitMethod()
*/
trait VirtualTrait
{
}

View File

@@ -1,24 +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\Component\Debug\Tests;
use Symfony\Component\Debug\ExceptionHandler;
class MockExceptionHandler extends ExceptionHandler
{
public $e;
public function handle(\Exception $e)
{
$this->e = $e;
}
}

View File

@@ -24,7 +24,7 @@ var_dump([
$eHandler[0]->setExceptionHandler('print_r');
if (true) {
class Broken implements \Serializable
class Broken implements \JsonSerializable
{
}
}
@@ -37,6 +37,6 @@ array(1) {
}
object(Symfony\Component\Debug\Exception\FatalErrorException)#%d (%d) {
["message":protected]=>
string(199) "Error: Class Symfony\Component\Debug\Broken contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (Serializable::serialize, Serializable::unserialize)"
string(179) "Error: Class Symfony\Component\Debug\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)"
%a
}

View File

@@ -34,7 +34,7 @@
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "4.2-dev"
"dev-master": "4.3-dev"
}
}
}