Merge branch '3.2'

* 3.2: (40 commits)
  fixed CS
  fixed CS
  fixed CS fixer config
  fixed typo
  Revert "fixed typo"
  fixed typo
  fixed CS
  Avoid setting request attributes from signature arguments in AnnotationClassLoader
  [DependencyInjection] Add some missing typehints in YamlFileLoader
  [DependencyInjection] minor: Fix a DocBlock
  [HttpKernel] Give higher priority to adding request formats
  [Cache] Fix tags expiration
  [PhpUnit] Blacklist DeprecationErrorHandler in stack traces
  [PropertyInfo] Don't try to access a property thru a static method
  [PropertyInfo] Exclude static methods form properties guessing
  [Workflow] Added new validator to make sure each place has unique translation names
  [Cache] [PdoAdapter] Fix MySQL 1170 error (blob as primary key)
  [FrameworkBundle] Fix third level headers for MarkdownDescriptor
  [Ldap] Using Ldap stored username instead of form submitted one
  [Ldap] load users with the good username case
  ...
This commit is contained in:
Fabien Potencier 2017-01-21 09:10:26 -08:00
commit c633f912d8
66 changed files with 761 additions and 258 deletions

View File

@ -8,33 +8,34 @@ return PhpCsFixer\Config::create()
'no_unreachable_default_argument_value' => false,
'braces' => array('allow_single_line_closure' => true),
'heredoc_to_nowdoc' => false,
'phpdoc_annotation_without_dot' => false,
))
->setRiskyAllowed(true)
->setFinder(
PhpCsFixer\Finder::create()
->in(__DIR__)
->in(__DIR__.'/src')
->exclude(array(
// directories containing files with content that is autogenerated by `var_export`, which breaks CS in output code
'src/Symfony/Component/DependencyInjection/Tests/Fixtures',
'src/Symfony/Component/Routing/Tests/Fixtures/dumper',
'Symfony/Component/DependencyInjection/Tests/Fixtures',
'Symfony/Component/Routing/Tests/Fixtures/dumper',
// fixture templates
'src/Symfony/Component/Templating/Tests/Fixtures/templates',
'src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom',
'Symfony/Component/Templating/Tests/Fixtures/templates',
'Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom',
// generated fixtures
'src/Symfony/Component/VarDumper/Tests/Fixtures',
'Symfony/Component/VarDumper/Tests/Fixtures',
// resource templates
'src/Symfony/Bundle/FrameworkBundle/Resources/views/Form',
'Symfony/Bundle/FrameworkBundle/Resources/views/Form',
))
// file content autogenerated by `var_export`
->notPath('src/Symfony/Component/Translation/Tests/fixtures/resources.php')
->notPath('Symfony/Component/Translation/Tests/fixtures/resources.php')
// autogenerated xmls
->notPath('src/Symfony/Component/Console/Tests/Fixtures/application_1.xml')
->notPath('src/Symfony/Component/Console/Tests/Fixtures/application_2.xml')
->notPath('Symfony/Component/Console/Tests/Fixtures/application_1.xml')
->notPath('Symfony/Component/Console/Tests/Fixtures/application_2.xml')
// yml
->notPath('src/Symfony/Component/Yaml/Tests/Fixtures/sfTests.yml')
->notPath('Symfony/Component/Yaml/Tests/Fixtures/sfTests.yml')
// test template
->notPath('src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom/_name_entry_label.html.php')
->notPath('Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom/_name_entry_label.html.php')
// explicit heredoc test
->notPath('src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/views/translation.html.php')
->notPath('Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/views/translation.html.php')
)
;

View File

@ -27,18 +27,18 @@ Symfony is the result of the work of many people who made the code better
- Karma Dordrak (drak)
- Lukas Kahwe Smith (lsmith)
- Martin Hasoň (hason)
- Jeremy Mikola (jmikola)
- Grégoire Pineau (lyrixx)
- Jeremy Mikola (jmikola)
- Jean-François Simon (jfsimon)
- Benjamin Eberlei (beberlei)
- Igor Wiedler (igorw)
- Eriksen Costa (eriksencosta)
- Jules Pietri (heah)
- Maxime Steinhausser (ogizanagi)
- Jules Pietri (heah)
- Robin Chalas (chalas_r)
- Sarah Khalil (saro0h)
- Jonathan Wage (jwage)
- Diego Saint Esteben (dosten)
- Robin Chalas (chalas_r)
- Alexandre Salomé (alexandresalome)
- William Durand (couac)
- ornicar
@ -49,11 +49,12 @@ Symfony is the result of the work of many people who made the code better
- Saša Stamenković (umpirsky)
- Henrik Bjørnskov (henrikbjorn)
- Miha Vrhovnik
- Diego Saint Esteben (dii3g0)
- Ener-Getick (energetick)
- Diego Saint Esteben (dii3g0)
- Konstantin Kudryashov (everzet)
- Bilal Amarni (bamarni)
- Iltar van der Berg (kjarli)
- Roland Franssen (ro0)
- Bilal Amarni (bamarni)
- Florin Patan (florinpatan)
- Peter Rehm (rpet)
- Kevin Bond (kbond)
@ -69,19 +70,18 @@ Symfony is the result of the work of many people who made the code better
- Henrik Westphal (snc)
- Dariusz Górecki (canni)
- Douglas Greenshields (shieldo)
- Titouan Galopin (tgalopin)
- Konstantin Myakshin (koc)
- Lee McDermott
- Brandon Turner
- Luis Cordova (cordoval)
- Graham Campbell (graham)
- Titouan Galopin (tgalopin)
- Daniel Holmes (dholmes)
- Pierre du Plessis (pierredup)
- Toni Uebernickel (havvg)
- Bart van den Burg (burgov)
- Jordan Alliot (jalliot)
- John Wards (johnwards)
- Roland Franssen (ro0)
- Fran Moreno (franmomu)
- Jáchym Toušek (enumag)
- Antoine Hérault (herzult)
@ -98,6 +98,7 @@ Symfony is the result of the work of many people who made the code better
- lenar
- Włodzimierz Gajda (gajdaw)
- Baptiste Clavié (talus)
- Maxime STEINHAUSSER
- Alexander Schwenn (xelaris)
- Florian Voutzinos (florianv)
- Colin Frei
@ -114,13 +115,13 @@ Symfony is the result of the work of many people who made the code better
- Eric GELOEN (gelo)
- David Buchmann (dbu)
- Tugdual Saunier (tucksaun)
- Maxime STEINHAUSSER
- Théo FIDRY (theofidry)
- Robert Schönthal (digitalkaoz)
- Florian Lonqueu-Brochard (florianlb)
- Stefano Sala (stefano.sala)
- Evgeniy (ewgraf)
- Juti Noppornpitak (shiroyuki)
- Tobias Nyholm (tobias)
- Tigran Azatyan (tigranazatyan)
- Sebastian Hörl (blogsh)
- Daniel Gomes (danielcsgomes)
@ -130,12 +131,11 @@ Symfony is the result of the work of many people who made the code better
- Pablo Godel (pgodel)
- Jérémie Augustin (jaugustin)
- Andréia Bohner (andreia)
- Yonel Ceruto González (yonelceruto)
- Rafael Dohms (rdohms)
- Arnaud Kleinpeter (nanocom)
- jwdeitch
- Tobias Nyholm (tobias)
- Joel Wurtz (brouznouf)
- Yonel Ceruto González (yonelceruto)
- Philipp Wahala (hifi)
- Vyacheslav Pavlov
- Javier Spagnoletti (phansys)
@ -179,6 +179,7 @@ Symfony is the result of the work of many people who made the code better
- fivestar
- Dominique Bongiraud
- Jeremy Livingston (jeremylivingston)
- Michael Lee (zerustech)
- Matthieu Auger (matthieuauger)
- Leszek Prabucki (l3l0)
- François Zaninotto (fzaninotto)
@ -187,6 +188,7 @@ Symfony is the result of the work of many people who made the code better
- John Kary (johnkary)
- Justin Hileman (bobthecow)
- Blanchon Vincent (blanchonvincent)
- Chris Wilkinson (thewilkybarkid)
- Michele Orselli (orso)
- Tom Van Looy (tvlooy)
- Sven Paulus (subsven)
@ -195,6 +197,7 @@ Symfony is the result of the work of many people who made the code better
- Dawid Nowak
- Eugene Wissner
- Julien Brochet (mewt)
- Tristan Darricau (nicofuma)
- Sergey Linnik (linniksa)
- Michaël Perrin (michael.perrin)
- Marcel Beerta (mazen)
@ -202,7 +205,6 @@ Symfony is the result of the work of many people who made the code better
- Jannik Zschiesche (apfelbox)
- Marco Pivetta (ocramius)
- julien pauli (jpauli)
- Michael Lee (zerustech)
- Lorenz Schori
- Sébastien Lavoie (lavoiesl)
- Francois Zaninotto
@ -216,20 +218,20 @@ Symfony is the result of the work of many people who made the code better
- Roman Marintšenko (inori)
- Christian Schmidt
- Xavier Montaña Carreras (xmontana)
- Chris Wilkinson (thewilkybarkid)
- Mickaël Andrieu (mickaelandrieu)
- Xavier Perez
- Arjen Brouwer (arjenjb)
- Katsuhiro OGAWA
- Patrick McDougle (patrick-mcdougle)
- James Halsall (jaitsu)
- Alif Rachmawadi
- Kristen Gilden (kgilden)
- SpacePossum
- Pierre-Yves LEBECQ (pylebecq)
- Alex Pott
- Jakub Kucharovic (jkucharovic)
- Eugene Leonovich (rybakit)
- Filippo Tessarotto
- Tristan Darricau (nicofuma)
- Joseph Rouff (rouffj)
- Félix Labrecque (woodspire)
- GordonsLondon
@ -259,7 +261,6 @@ Symfony is the result of the work of many people who made the code better
- Peter Kruithof (pkruithof)
- Michael Holm (hollo)
- Marc Weistroff (futurecat)
- SpacePossum
- Hidde Wieringa (hiddewie)
- Chris Smith (cs278)
- Florian Klein (docteurklein)
@ -278,12 +279,14 @@ Symfony is the result of the work of many people who made the code better
- Ismael Ambrosi (iambrosi)
- Uwe Jäger (uwej711)
- Aurelijus Valeiša (aurelijus)
- Victor Bocharsky (bocharsky_bw)
- Jan Decavele (jandc)
- Gustavo Piltcher
- Stepan Tanasiychuk (stfalcon)
- Tiago Ribeiro (fixe)
- Hidde Boomsma (hboomsma)
- John Bafford (jbafford)
- Pavel Batanov (scaytrase)
- Bob den Otter (bopp)
- Adrian Rudnik (kreischweide)
- Francesc Rosàs (frosas)
@ -304,6 +307,7 @@ Symfony is the result of the work of many people who made the code better
- Matthew Lewinski (lewinski)
- Magnus Nordlander (magnusnordlander)
- alquerci
- Adam Prager (padam87)
- Francesco Levorato
- Vitaliy Zakharov (zakharovvi)
- Tobias Sjösten (tobiassjosten)
@ -324,6 +328,7 @@ Symfony is the result of the work of many people who made the code better
- Clément Gautier (clementgautier)
- Eduardo Gulias (egulias)
- giulio de donato (liuggio)
- ShinDarth
- Stéphane PY (steph_py)
- Philipp Kräutli (pkraeutli)
- Kirill chEbba Chebunin (chebba)
@ -336,9 +341,9 @@ Symfony is the result of the work of many people who made the code better
- Hassan Amouhzi
- Tamas Szijarto
- Pavel Volokitin (pvolok)
- François Pluchino (francoispluchino)
- Nicolas Dewez (nicolas_dewez)
- Endre Fejes
- Victor Bocharsky (bocharsky_bw)
- Tobias Naumann (tna)
- Daniel Beyer
- Shein Alexey
@ -355,7 +360,6 @@ Symfony is the result of the work of many people who made the code better
- Xavier HAUSHERR
- Albert Jessurum (ajessu)
- Laszlo Korte
- Pavel Batanov (scaytrase)
- Miha Vrhovnik
- Alessandro Desantis
- hubert lecorche (hlecorche)
@ -412,6 +416,7 @@ Symfony is the result of the work of many people who made the code better
- boombatower
- Fabrice Bernhard (fabriceb)
- Jérôme Macias (jeromemacias)
- Andrey Astakhov (aast)
- Fabian Lange (codingfabian)
- Frank Neff (fneff)
- Roman Lapin (memphys)
@ -422,6 +427,7 @@ Symfony is the result of the work of many people who made the code better
- Pablo Díez (pablodip)
- Kevin McBride
- Sergio Santoro
- Robin van der Vleuten (robinvdvleuten)
- Philipp Rieber (bicpi)
- Manuel de Ruiter (manuel)
- Eduardo Oliveira (entering)
@ -478,7 +484,6 @@ Symfony is the result of the work of many people who made the code better
- Alexander Deruwe (aderuwe)
- Alain Hippolyte (aloneh)
- Dave Hulbert (dave1010)
- François Pluchino (francoispluchino)
- Ivan Rey (ivanrey)
- Marcin Chyłek (songoq)
- Ned Schwartz
@ -512,6 +517,7 @@ Symfony is the result of the work of many people who made the code better
- Konstantin S. M. Möllers (ksmmoellers)
- Sinan Eldem
- Alexandre Dupuy (satchette)
- Rob Frawley 2nd
- Nahuel Cuesta (ncuesta)
- Chris Boden (cboden)
- Asmir Mustafic (goetas)
@ -522,6 +528,7 @@ Symfony is the result of the work of many people who made the code better
- Åsmund Garfors
- Maxime Douailin
- Jean Pasdeloup (pasdeloup)
- Benjamin Cremer (bcremer)
- Javier López (loalf)
- Andreas Braun
- Reinier Kip
@ -551,7 +558,6 @@ Symfony is the result of the work of many people who made the code better
- umpirski
- Chris Heng (gigablah)
- Ulumuddin Yunus (joenoez)
- Adam Prager (padam87)
- Luc Vieillescazes (iamluc)
- Johann Saunier (prophet777)
- Samuel ROZE (sroze)
@ -586,6 +592,7 @@ Symfony is the result of the work of many people who made the code better
- develop
- ReenExe
- Mark Sonnabaum
- Thomas Royer (cydonia7)
- Richard Quadling
- jochenvdv
- Arturas Smorgun (asarturas)
@ -593,6 +600,7 @@ Symfony is the result of the work of many people who made the code better
- Michael Piecko
- yclian
- twifty
- Indra Gunawan (guind)
- Peter Ward
- Julien DIDIER (juliendidier)
- Dominik Ritter (dritter)
@ -600,10 +608,10 @@ Symfony is the result of the work of many people who made the code better
- Martin Hujer (martinhujer)
- Pascal Helfenstein
- Baldur Rensch (brensch)
- Thomas Calvet
- Vladyslav Petrovych
- Alex Xandra Albert Sim
- Carson Full
- Andrey Astakhov (aast)
- Trent Steel (trsteel88)
- Yuen-Chi Lian
- Besnik Br
@ -630,11 +638,13 @@ Symfony is the result of the work of many people who made the code better
- Christian Soronellas (theunic)
- Romain Gautier (mykiwi)
- Yosmany Garcia (yosmanyga)
- Wouter J
- Wouter de Wild
- Miroslav Sustek
- Degory Valentine
- Benoit Lévêque (benoit_leveque)
- Jeroen Fiege (fieg)
- Arthur de Moulins (4rthem)
- Krzysiek Łabuś
- Xavier Lacot (xavier)
- possum
@ -642,6 +652,7 @@ Symfony is the result of the work of many people who made the code better
- Olivier Maisonneuve (olineuve)
- Masterklavi
- Francis Turmel (fturmel)
- Nikita Nefedov (nikita2206)
- cgonzalez
- Ben
- Jayson Xu (superjavason)
@ -683,8 +694,10 @@ Symfony is the result of the work of many people who made the code better
- Ivan Menshykov
- David Romaní
- Patrick Allaert
- Fabien Bourigault (fbourigault)
- Gustavo Falco (gfalco)
- Matt Robinson (inanimatt)
- Ruud Kamphuis (ruudk)
- Aleksey Podskrebyshev
- Calin Mihai Pristavu
- David Marín Carreño (davefx)
@ -734,7 +747,6 @@ Symfony is the result of the work of many people who made the code better
- Mikhail Yurasov (mym)
- LOUARDI Abdeltif (ouardisoft)
- Robert Gruendler (pulse00)
- Robin van der Vleuten (robinvdvleuten)
- Simon Terrien (sterrien)
- Benoît Merlet (trompette)
- Koen Kuipers
@ -763,6 +775,7 @@ Symfony is the result of the work of many people who made the code better
- Colin O'Dell (colinodell)
- xaav
- Mahmoud Mostafa (mahmoud)
- Alessandro Lai
- Pieter
- Michael Tibben
- Sander Marechal
@ -811,8 +824,10 @@ Symfony is the result of the work of many people who made the code better
- Nicolas Macherey
- Lin Clark
- Jeremy David (jeremy.david)
- Denis Brumann (dbrumann)
- Troy McCabe
- Ville Mattila
- ilyes kooli
- Boris Vujicic (boris.vujicic)
- Max Beutel
- Antanas Arvasevicius
@ -832,6 +847,7 @@ Symfony is the result of the work of many people who made the code better
- Christian
- Sergii Smertin (nfx)
- hugofonseca (fonsecas72)
- Martynas Narbutas
- Bailey Parker
- Eddie Jaoude
- Haritz Iturbe (hizai)
@ -846,7 +862,6 @@ Symfony is the result of the work of many people who made the code better
- Alex Demchenko (pilot)
- Tadas Gliaubicas (tadcka)
- Benoit Garret
- Thomas Royer (cydonia7)
- DerManoMann
- Olaf Klischat
- orlovv
@ -867,7 +882,6 @@ Symfony is the result of the work of many people who made the code better
- rpg600
- Péter Buri (burci)
- Davide Borsatto (davide.borsatto)
- Indra Gunawan (guind)
- kaiwa
- Charles Sanquer (csanquer)
- Albert Ganiev (helios-ag)
@ -909,6 +923,7 @@ Symfony is the result of the work of many people who made the code better
- Krzysztof Przybyszewski
- Paul Matthews
- Juan Traverso
- Tarjei Huse (tarjei)
- Philipp Strube
- Christian Sciberras
- Clement Herreman (clemherreman)
@ -919,7 +934,6 @@ Symfony is the result of the work of many people who made the code better
- Alberto Aldegheri
- heccjj
- Alexandre Melard
- Thomas Calvet
- Sergey Yuferev
- Tobias Stöckler
- Mario Young
@ -973,6 +987,7 @@ Symfony is the result of the work of many people who made the code better
- Samuel Vogel (samuelvogel)
- Berat Doğan
- Juanmi Rodriguez Cerón
- Andy Raines
- Anthony Ferrara
- Klaas Cuvelier (kcuvelier)
- Steve Frécinaux
@ -998,6 +1013,7 @@ Symfony is the result of the work of many people who made the code better
- Alberto Pirovano (geezmo)
- Pete Mitchell (peterjmit)
- Tom Corrigan (tomcorrigan)
- Luis Galeas
- Martin Pärtel
- Noah Heck (myesain)
- Patrick Daley (padrig)
@ -1014,7 +1030,6 @@ Symfony is the result of the work of many people who made the code better
- Romain Geissler
- Adrien Moiruad
- Tomaz Ahlin
- Benjamin Cremer (bcremer)
- Marcus Stöhr (dafish)
- Emmanuel Vella (emmanuel.vella)
- Carsten Nielsen (phreaknerd)
@ -1036,6 +1051,7 @@ Symfony is the result of the work of many people who made the code better
- Damien Tournoud
- Jon Gotlin (jongotlin)
- Michael Dowling (mtdowling)
- Karlos Presumido (oneko)
- BilgeXA
- r1pp3rj4ck
- Robert Queck
@ -1073,7 +1089,6 @@ Symfony is the result of the work of many people who made the code better
- kor3k kor3k (kor3k)
- Stelian Mocanita (stelian)
- Flavian (2much)
- Arthur de Moulins (4rthem)
- mike
- Keith Maika
- Mephistofeles
@ -1164,6 +1179,7 @@ Symfony is the result of the work of many people who made the code better
- Julius Beckmann
- Romain Dorgueil
- Grayson Koonce (breerly)
- Fabien LUCAS (flucas2)
- Karim Cassam Chenaï (ka)
- Nicolas Bastien (nicolas_bastien)
- Denis (yethee)
@ -1212,7 +1228,6 @@ Symfony is the result of the work of many people who made the code better
- Bram Van der Sype (brammm)
- Guile (guile)
- Julien Moulin (lizjulien)
- Nikita Nefedov (nikita2206)
- Mauro Foti (skler)
- Yannick Warnier (ywarnier)
- Kevin Decherf
@ -1235,7 +1250,9 @@ Symfony is the result of the work of many people who made the code better
- Tischoi
- J Bruni
- Alexey Prilipko
- vlakoff
- bertillon
- Bertalan Attila
- Yannick Bensacq (cibou)
- Luca Genuzio (genuzio)
- Hans Nilsson (hansnilsson)
@ -1254,7 +1271,6 @@ Symfony is the result of the work of many people who made the code better
- Joel Marcey
- David Christmann
- root
- Wouter J
- James Hudson
- Tom Maguire
- David Zuelke
@ -1309,9 +1325,9 @@ Symfony is the result of the work of many people who made the code better
- ddebree
- Tomas Liubinas
- Alex
- Patrick Dawkins
- Klaas Naaijkens
- Daniel González Cerviño
- ShinDarth
- Rafał
- Adria Lopez (adlpz)
- Rosio (ben-rosio)
@ -1338,9 +1354,9 @@ Symfony is the result of the work of many people who made the code better
- Michael Pohlers (mick_the_big)
- Cayetano Soriano Gallego (neoshadybeat)
- Ondrej Machulda (ondram)
- Patrick McDougle (patrick-mcdougle)
- Pablo Monterde Perez (plebs)
- Jimmy Leger (redpanda)
- Marcin Szepczynski (szepczynski)
- Cyrille Jouineau (tuxosaurus)
- Yorkie Chadwick (yorkie76)
- Yanick Witschi
@ -1363,6 +1379,7 @@ Symfony is the result of the work of many people who made the code better
- Arnaud Buathier (arnapou)
- chesteroni (chesteroni)
- Mauricio Lopez (diaspar)
- HADJEDJ Vincent (hadjedjvincent)
- Daniele Cesarini (ijanki)
- Ismail Asci (ismailasci)
- Simon CONSTANS (kosssi)
@ -1505,7 +1522,6 @@ Symfony is the result of the work of many people who made the code better
- Damián Nohales (eagleoneraptor)
- Elliot Anderson (elliot)
- Fabien D. (fabd)
- Fabien Bourigault (fbourigault)
- Carsten Eilers (fnc)
- Sorin Gitlan (forapathy)
- Yohan Giarelli (frequence-web)
@ -1549,7 +1565,6 @@ Symfony is the result of the work of many people who made the code better
- Daniel Perez Pinazo (pitiflautico)
- Brayden Williams (redstar504)
- Rich Sage (richsage)
- Ruud Kamphuis (ruudk)
- Bart Ruysseveldt (ruyss)
- Sascha Dens (saschadens)
- scourgen hung (scourgen)

View File

@ -0,0 +1,53 @@
<?php
namespace Symfony\Bridge\Doctrine\Tests\Fixtures;
use Doctrine\ORM\Mapping as ORM;
/**
* an entity that has two objects (class without toString methods) as primary key.
*
* @ORM\Entity
*/
class CompositeObjectNoToStringIdEntity
{
/**
* @var SingleIntIdNoToStringEntity
*
* @ORM\Id
* @ORM\ManyToOne(targetEntity="SingleIntIdNoToStringEntity", cascade={"persist"})
* @ORM\JoinColumn(name="object_one_id")
*/
protected $objectOne;
/**
* @var SingleIntIdNoToStringEntity
*
* @ORM\Id
* @ORM\ManyToOne(targetEntity="SingleIntIdNoToStringEntity", cascade={"persist"})
* @ORM\JoinColumn(name="object_two_id")
*/
protected $objectTwo;
public function __construct(SingleIntIdNoToStringEntity $objectOne, SingleIntIdNoToStringEntity $objectTwo)
{
$this->objectOne = $objectOne;
$this->objectTwo = $objectTwo;
}
/**
* @return SingleIntIdNoToStringEntity
*/
public function getObjectOne()
{
return $this->objectOne;
}
/**
* @return SingleIntIdNoToStringEntity
*/
public function getObjectTwo()
{
return $this->objectTwo;
}
}

View File

@ -19,6 +19,7 @@ use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper;
use Symfony\Bridge\Doctrine\Test\TestRepositoryFactory;
use Symfony\Bridge\Doctrine\Tests\Fixtures\Employee;
use Symfony\Bridge\Doctrine\Tests\Fixtures\Person;
use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeObjectNoToStringIdEntity;
use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity;
use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity;
use Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity;
@ -146,6 +147,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity2'),
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\Person'),
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\Employee'),
$em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeObjectNoToStringIdEntity'),
));
}
@ -179,7 +181,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->buildViolation('myMessage')
->atPath('property.path.name')
->setParameter('{{ value }}', '"Foo"')
->setInvalidValue('Foo')
->setInvalidValue($entity2)
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
}
@ -204,7 +206,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->buildViolation('myMessage')
->atPath('property.path.bar')
->setParameter('{{ value }}', '"Foo"')
->setInvalidValue('Foo')
->setInvalidValue($entity2)
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
}
@ -423,7 +425,7 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->buildViolation('myMessage')
->atPath('property.path.single')
->setParameter('{{ value }}', $entity1)
->setParameter('{{ value }}', 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity") identified by (id => 1)')
->setInvalidValue($entity1)
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
@ -456,12 +458,12 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$this->validator->validate($associated2, $constraint);
$expectedValue = 'Object of class "Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity2" identified by "2"';
$expectedValue = 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity") identified by (id => 1)';
$this->buildViolation('myMessage')
->atPath('property.path.single')
->setParameter('{{ value }}', '"'.$expectedValue.'"')
->setInvalidValue($expectedValue)
->setParameter('{{ value }}', $expectedValue)
->setInvalidValue($entity1)
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
}
@ -617,4 +619,38 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest
$entity = new Person(1, 'Foo');
$this->validator->validate($entity, $constraint);
}
public function testValidateUniquenessWithCompositeObjectNoToStringIdEntity()
{
$constraint = new UniqueEntity(array(
'message' => 'myMessage',
'fields' => array('objectOne', 'objectTwo'),
'em' => self::EM_NAME,
));
$objectOne = new SingleIntIdNoToStringEntity(1, 'foo');
$objectTwo = new SingleIntIdNoToStringEntity(2, 'bar');
$this->em->persist($objectOne);
$this->em->persist($objectTwo);
$this->em->flush();
$entity = new CompositeObjectNoToStringIdEntity($objectOne, $objectTwo);
$this->em->persist($entity);
$this->em->flush();
$newEntity = new CompositeObjectNoToStringIdEntity($objectOne, $objectTwo);
$this->validator->validate($newEntity, $constraint);
$expectedValue = 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity") identified by (id => 1)';
$this->buildViolation('myMessage')
->atPath('property.path.objectOne')
->setParameter('{{ value }}', $expectedValue)
->setInvalidValue($objectOne)
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->assertRaised();
}
}

View File

@ -12,6 +12,8 @@
namespace Symfony\Bridge\Doctrine\Validator\Constraints;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
@ -141,15 +143,41 @@ class UniqueEntityValidator extends ConstraintValidator
$errorPath = null !== $constraint->errorPath ? $constraint->errorPath : $fields[0];
$invalidValue = isset($criteria[$errorPath]) ? $criteria[$errorPath] : $criteria[$fields[0]];
if (is_object($invalidValue) && !method_exists($invalidValue, '__toString')) {
$invalidValue = sprintf('Object of class "%s" identified by "%s"', get_class($entity), implode(', ', $class->getIdentifierValues($entity)));
}
$this->context->buildViolation($constraint->message)
->atPath($errorPath)
->setParameter('{{ value }}', $this->formatValue($invalidValue, static::OBJECT_TO_STRING | static::PRETTY_DATE))
->setParameter('{{ value }}', $this->formatWithIdentifiers($em, $class, $invalidValue))
->setInvalidValue($invalidValue)
->setCode(UniqueEntity::NOT_UNIQUE_ERROR)
->addViolation();
}
private function formatWithIdentifiers(ObjectManager $em, ClassMetadata $class, $value)
{
if (!is_object($value) || $value instanceof \DateTimeInterface) {
return $this->formatValue($value, self::PRETTY_DATE);
}
// non unique value is a composite PK
if ($class->getName() !== $idClass = get_class($value)) {
$identifiers = $em->getClassMetadata($idClass)->getIdentifierValues($value);
} else {
$identifiers = $class->getIdentifierValues($value);
}
if (!$identifiers) {
return sprintf('object("%s")', $idClass);
}
array_walk($identifiers, function (&$id, $field) {
if (!is_object($id) || $id instanceof \DateTimeInterface) {
$idAsString = $this->formatValue($id, self::PRETTY_DATE);
} else {
$idAsString = sprintf('object("%s")', get_class($id));
}
$id = sprintf('%s => %s', $field, $idAsString);
});
return sprintf('object("%s") identified by (%s)', $idClass, implode(', ', $identifiers));
}
}

View File

@ -141,7 +141,7 @@ class DeprecationErrorHandler
return "\x1B[{$color}m{$str}\x1B[0m";
};
} else {
$colorize = function ($str) {return $str;};
$colorize = function ($str) { return $str; };
}
register_shutdown_function(function () use ($getMode, &$deprecations, $deprecationHandler, $colorize) {
$mode = $getMode();
@ -152,7 +152,7 @@ class DeprecationErrorHandler
restore_error_handler();
if (DeprecationErrorHandler::MODE_WEAK === $mode) {
$colorize = function ($str) {return $str;};
$colorize = function ($str) { return $str; };
}
if ($currErrorHandler !== $deprecationHandler) {
echo "\n", $colorize('THE ERROR HANDLER HAS CHANGED!', true), "\n";

View File

@ -35,6 +35,7 @@ class SymfonyTestsListener extends \PHPUnit_Framework_BaseTestListener
*/
public function __construct(array $mockedNamespaces = array())
{
\PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\DeprecationErrorHandler'] = 1;
\PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\SymfonyTestsListener'] = 1;
$warn = false;

View File

@ -43,6 +43,9 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__
@unlink("$PHPUNIT_VERSION.zip");
passthru("wget https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip");
}
if (!class_exists('ZipArchive')) {
throw new \Exception('simple-phpunit requires the "zip" PHP extension to be installed and enabled in order to uncompress the downloaded PHPUnit packages.');
}
$zip = new ZipArchive();
$zip->open("$PHPUNIT_VERSION.zip");
$zip->extractTo(getcwd());

View File

@ -21,7 +21,8 @@
"php": ">=5.3.3"
},
"suggest": {
"symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader"
"symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader",
"ext-zip": "Zip support is required when using bin/simple-phpunit"
},
"autoload": {
"files": [ "bootstrap.php" ],

View File

@ -122,9 +122,6 @@ class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \Pr
unset($this->valueHolder5157dd96e88c0->$name);
}
/**
*
*/
public function __clone()
{
$this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__clone', array());
@ -132,9 +129,6 @@ class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \Pr
$this->valueHolder5157dd96e88c0 = clone $this->valueHolder5157dd96e88c0;
}
/**
*
*/
public function __sleep()
{
$this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__sleep', array());
@ -142,9 +136,6 @@ class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \Pr
return array('valueHolder5157dd96e88c0');
}
/**
*
*/
public function __wakeup()
{
}

View File

@ -122,9 +122,6 @@ class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \Pr
unset($this->valueHolder5157dd96e88c0->$name);
}
/**
*
*/
public function __clone()
{
$this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__clone', array());
@ -132,9 +129,6 @@ class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \Pr
$this->valueHolder5157dd96e88c0 = clone $this->valueHolder5157dd96e88c0;
}
/**
*
*/
public function __sleep()
{
$this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__sleep', array());
@ -142,9 +136,6 @@ class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \Pr
return array('valueHolder5157dd96e88c0');
}
/**
*
*/
public function __wakeup()
{
}
@ -168,7 +159,7 @@ class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \Pr
/**
* {@inheritdoc}
*/
public function initializeProxy() : bool
public function initializeProxy(): bool
{
return $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, 'initializeProxy', array());
}
@ -176,7 +167,7 @@ class stdClass_c1d194250ee2e2b7d2eab8b8212368a8 extends \stdClass implements \Pr
/**
* {@inheritdoc}
*/
public function isProxyInitialized() : bool
public function isProxyInitialized(): bool
{
return null !== $this->valueHolder5157dd96e88c0;
}

View File

@ -140,7 +140,7 @@ EOF
}
if ($type === 'functions' || $type === 'filters') {
$cb = $entity->getCallable();
if (is_null($cb)) {
if (null === $cb) {
return;
}
if (is_array($cb)) {

View File

@ -33,7 +33,7 @@ class DumpExtensionTest extends \PHPUnit_Framework_TestCase
$dumped = null;
$exception = null;
$prevDumper = VarDumper::setHandler(function ($var) use (&$dumped) {$dumped = $var;});
$prevDumper = VarDumper::setHandler(function ($var) use (&$dumped) { $dumped = $var; });
try {
$this->assertEquals($expectedOutput, $twig->render('template'));

View File

@ -235,7 +235,7 @@ class MarkdownDescriptor extends Descriptor
}
}
$this->write(isset($options['id']) ? sprintf("%s\n%s\n\n%s\n", $options['id'], str_repeat('~', strlen($options['id'])), $output) : $output);
$this->write(isset($options['id']) ? sprintf("### %s\n\n%s\n", $options['id'], $output) : $output);
}
/**
@ -250,7 +250,7 @@ class MarkdownDescriptor extends Descriptor
return $this->write($output);
}
$this->write(sprintf("%s\n%s\n\n%s\n", $options['id'], str_repeat('~', strlen($options['id'])), $output));
$this->write(sprintf("### %s\n\n%s\n", $options['id'], $output));
if (!$builder) {
return;

View File

@ -477,6 +477,10 @@ abstract class FrameworkExtensionTest extends TestCase
public function testFileLinkFormat()
{
if (ini_get('xdebug.file_link_format') || get_cfg_var('xdebug.file_link_format')) {
$this->markTestSkipped('A custom file_link_format is defined.');
}
$container = $this->createContainerFromFile('full');
$this->assertEquals('file%link%format', $container->getParameter('debug.file_link_format'));

View File

@ -4,8 +4,7 @@ Public services
Definitions
-----------
definition_1
~~~~~~~~~~~~
### definition_1
- Class: `Full\Qualified\Class1`
- Public: yes
@ -21,14 +20,12 @@ definition_1
Aliases
-------
alias_1
~~~~~~~
### alias_1
- Service: `service_1`
- Public: yes
alias_2
~~~~~~~
### alias_2
- Service: `service_2`
- Public: no

View File

@ -4,8 +4,7 @@ Public and private services
Definitions
-----------
definition_1
~~~~~~~~~~~~
### definition_1
- Class: `Full\Qualified\Class1`
- Public: yes
@ -17,8 +16,7 @@ definition_1
- Factory Class: `Full\Qualified\FactoryClass`
- Factory Method: `get`
definition_2
~~~~~~~~~~~~
### definition_2
- Class: `Full\Qualified\Class2`
- Public: no
@ -42,14 +40,12 @@ definition_2
Aliases
-------
alias_1
~~~~~~~
### alias_1
- Service: `service_1`
- Public: yes
alias_2
~~~~~~~
### alias_2
- Service: `service_2`
- Public: no

View File

@ -4,8 +4,7 @@ Public and private services with tag `tag1`
Definitions
-----------
definition_2
~~~~~~~~~~~~
### definition_2
- Class: `Full\Qualified\Class2`
- Public: no

View File

@ -4,8 +4,7 @@ Container tags
tag1
----
definition_2
~~~~~~~~~~~~
### definition_2
- Class: `Full\Qualified\Class2`
- Public: no
@ -23,8 +22,7 @@ definition_2
tag2
----
definition_2
~~~~~~~~~~~~
### definition_2
- Class: `Full\Qualified\Class2`
- Public: no

View File

@ -369,11 +369,11 @@ class MainConfiguration implements ConfigurationInterface
$providerNodeBuilder
->validate()
->ifTrue(function ($v) {return count($v) > 1;})
->ifTrue(function ($v) { return count($v) > 1; })
->thenInvalid('You cannot set multiple provider types for the same provider')
->end()
->validate()
->ifTrue(function ($v) {return count($v) === 0;})
->ifTrue(function ($v) { return count($v) === 0; })
->thenInvalid('You must set a provider definition for the provider.')
->end()
;

View File

@ -88,7 +88,7 @@ class ExtensionPass implements CompilerPassInterface
$twigLoader = $container->getDefinition('twig.loader.native_filesystem');
if ($container->has('templating')) {
$loader = $container->getDefinition('twig.loader.filesystem');
$loader->setMethodCalls($twigLoader->getMethodCalls());
$loader->setMethodCalls(array_merge($twigLoader->getMethodCalls(), $loader->getMethodCalls()));
$loader->replaceArgument(2, $composerRootDir);
$twigLoader->clearTag('twig.loader');

View File

@ -0,0 +1,41 @@
<?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\Bundle\TwigBundle\Tests\DependencyInjection\Compiler;
use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\ExtensionPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
class ExtensionPassTest extends \PHPUnit_Framework_TestCase
{
public function testProcessDoesNotDropExistingFileLoaderMethodCalls()
{
$container = new ContainerBuilder();
$container->setParameter('kernel.debug', false);
$container->register('twig.app_variable', '\Symfony\Bridge\Twig\AppVariable');
$container->register('templating', '\Symfony\Bundle\TwigBundle\TwigEngine');
$nativeTwigLoader = new Definition('\Twig_Loader_Filesystem');
$nativeTwigLoader->addMethodCall('addPath', array());
$container->setDefinition('twig.loader.native_filesystem', $nativeTwigLoader);
$filesystemLoader = new Definition('\Symfony\Bundle\TwigBundle\Loader\FilesystemLoader');
$filesystemLoader->addMethodCall('addPath', array());
$container->setDefinition('twig.loader.filesystem', $filesystemLoader);
$extensionPass = new ExtensionPass();
$extensionPass->process($container);
$this->assertCount(2, $filesystemLoader->getMethodCalls());
}
}

View File

@ -135,7 +135,8 @@ class ContentSecurityPolicyHandler
if (isset($headers[$header]['default-src'])) {
$headers[$header][$type] = $headers[$header]['default-src'];
} else {
$headers[$header][$type] = array();
// If there is no script-src/style-src and no default-src, no additional rules required.
continue;
}
}
$ruleIsSet = true;

View File

@ -118,6 +118,13 @@ class ContentSecurityPolicyHandlerTest extends \PHPUnit_Framework_TestCase
$this->createResponse($responseNonceHeaders),
array('Content-Security-Policy' => null, 'X-Content-Security-Policy' => null),
),
array(
$nonce,
array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce),
$this->createRequest(),
$this->createResponse(array('Content-Security-Policy' => 'frame-ancestors https: ; form-action: https:')),
array('Content-Security-Policy' => 'frame-ancestors https: ; form-action: https:', 'X-Content-Security-Policy' => null),
),
array(
$nonce,
array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce),
@ -130,7 +137,7 @@ class ContentSecurityPolicyHandlerTest extends \PHPUnit_Framework_TestCase
array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce),
$this->createRequest(),
$this->createResponse(array('Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'')),
array('Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'; style-src \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null),
array('Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'', 'X-Content-Security-Policy' => null),
),
array(
$nonce,
@ -144,21 +151,21 @@ class ContentSecurityPolicyHandlerTest extends \PHPUnit_Framework_TestCase
array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce),
$this->createRequest(),
$this->createResponse(array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'')),
array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'; style-src \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null),
array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'', 'Content-Security-Policy' => null),
),
array(
$nonce,
array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce),
$this->createRequest(),
$this->createResponse(array('X-Content-Security-Policy' => 'script-src \'self\'')),
array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null),
array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null),
),
array(
$nonce,
array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce),
$this->createRequest(),
$this->createResponse(array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'sha384-LALALALALAAL\'')),
array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'sha384-LALALALALAAL\' \'nonce-'.$nonce.'\'; style-src \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null),
array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'sha384-LALALALALAAL\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null),
),
array(
$nonce,

View File

@ -15,10 +15,23 @@ use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\CacheItem;
/**
* Interface for adapters managing instances of Symfony's {@see CacheItem}.
* Interface for adapters managing instances of Symfony's CacheItem.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
interface AdapterInterface extends CacheItemPoolInterface
{
/**
* {@inheritdoc}
*
* @return CacheItem
*/
public function getItem($key);
/**
* {@inheritdoc}
*
* return \Traversable|CacheItem[]
*/
public function getItems(array $keys = array());
}

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Cache\Adapter;
use Symfony\Component\Cache\Exception\CacheException;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/

View File

@ -108,9 +108,20 @@ class PdoAdapter extends AbstractAdapter
$conn = $this->getConnection();
if ($conn instanceof Connection) {
$types = array(
'mysql' => 'binary',
'sqlite' => 'text',
'pgsql' => 'string',
'oci' => 'string',
'sqlsrv' => 'string',
);
if (!isset($types[$this->driver])) {
throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $this->driver));
}
$schema = new Schema();
$table = $schema->createTable($this->table);
$table->addColumn($this->idCol, 'blob', array('length' => 255));
$table->addColumn($this->idCol, $types[$this->driver], array('length' => 255));
$table->addColumn($this->dataCol, 'blob', array('length' => 16777215));
$table->addColumn($this->lifetimeCol, 'integer', array('unsigned' => true, 'notnull' => false));
$table->addColumn($this->timeCol, 'integer', array('unsigned' => true, 'foo' => 'bar'));

View File

@ -26,6 +26,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface
private $deferred = array();
private $createCacheItem;
private $getTagsByKey;
private $invalidateTags;
private $tagsAdapter;
public function __construct(AdapterInterface $itemsAdapter, AdapterInterface $tagsAdapter = null)
@ -33,17 +34,15 @@ class TagAwareAdapter implements TagAwareAdapterInterface
$this->itemsAdapter = $itemsAdapter;
$this->tagsAdapter = $tagsAdapter ?: $itemsAdapter;
$this->createCacheItem = \Closure::bind(
function ($key, $value = null, CacheItem $protoItem = null) {
function ($key, $value, CacheItem $protoItem) {
$item = new CacheItem();
$item->key = $key;
$item->value = $value;
$item->isHit = false;
if (null !== $protoItem) {
$item->defaultLifetime = $protoItem->defaultLifetime;
$item->innerItem = $protoItem->innerItem;
$item->poolHash = $protoItem->poolHash;
}
$item->defaultLifetime = $protoItem->defaultLifetime;
$item->expiry = $protoItem->expiry;
$item->innerItem = $protoItem->innerItem;
$item->poolHash = $protoItem->poolHash;
return $item;
},
@ -62,6 +61,20 @@ class TagAwareAdapter implements TagAwareAdapterInterface
null,
CacheItem::class
);
$this->invalidateTags = \Closure::bind(
function (AdapterInterface $tagsAdapter, array $tags) {
foreach ($tagsAdapter->getItems($tags) as $v) {
$v->set(1 + (int) $v->get());
$v->defaultLifetime = 0;
$v->expiry = null;
$tagsAdapter->saveDeferred($v);
}
return $tagsAdapter->commit();
},
null,
CacheItem::class
);
}
/**
@ -74,13 +87,9 @@ class TagAwareAdapter implements TagAwareAdapterInterface
$tags[$k] = $tag.static::TAGS_PREFIX;
}
}
$f = $this->invalidateTags;
foreach ($this->tagsAdapter->getItems($tags) as $v) {
$v->set(1 + (int) $v->get());
$this->tagsAdapter->saveDeferred($v);
}
return $this->tagsAdapter->commit();
return $f($this->tagsAdapter, $tags);
}
/**
@ -211,7 +220,8 @@ class TagAwareAdapter implements TagAwareAdapterInterface
$ok = true;
if ($this->deferred) {
foreach ($this->deferred as $key => $item) {
$items = $this->deferred;
foreach ($items as $key => $item) {
if (!$this->itemsAdapter->saveDeferred($item)) {
unset($this->deferred[$key]);
$ok = false;
@ -219,14 +229,14 @@ class TagAwareAdapter implements TagAwareAdapterInterface
}
$f = $this->getTagsByKey;
$tagsByKey = $f($this->deferred);
$tagsByKey = $f($items);
$deletedTags = $this->deferred = array();
$tagVersions = $this->getTagVersions($tagsByKey);
$f = $this->createCacheItem;
foreach ($tagsByKey as $key => $tags) {
if ($tags) {
$this->itemsAdapter->saveDeferred($f(static::TAGS_PREFIX.$key, array_intersect_key($tagVersions, $tags)));
$this->itemsAdapter->saveDeferred($f(static::TAGS_PREFIX.$key, array_intersect_key($tagVersions, $tags), $items[$key]));
} else {
$deletedTags[] = static::TAGS_PREFIX.$key;
}

View File

@ -97,4 +97,21 @@ class TagAwareAdapterTest extends AdapterTestCase
$this->assertTrue($pool->getItem('k')->isHit());
}
public function testTagItemExpiry()
{
$pool = $this->createCachePool(10);
$item = $pool->getItem('foo');
$item->tag(array('baz'));
$item->expiresAfter(100);
$pool->save($item);
$pool->invalidateTags(array('baz'));
$this->assertFalse($pool->getItem('foo')->isHit());
sleep(20);
$this->assertFalse($pool->getItem('foo')->isHit());
}
}

View File

@ -4,7 +4,7 @@
* foo
*/
declare (strict_types = 1);
declare(strict_types=1);
namespace Namespaced;

View File

@ -225,7 +225,7 @@ class ErrorHandler
if ($flush) {
foreach ($this->bootstrappingLogger->cleanLogs() as $log) {
$type = $log[2]['exception']->getSeverity();
$type = $log[2]['exception'] instanceof \ErrorException ? $log[2]['exception']->getSeverity() : E_ERROR;
if (!isset($flush[$type])) {
$this->bootstrappingLogger->log($log[0], $log[1], $log[2]);
} elseif ($this->loggers[$type][0]) {

View File

@ -173,7 +173,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface
);
if ($prefix) {
$candidates = array_filter($candidates, function ($candidate) use ($prefix) {return 0 === strpos($candidate, $prefix);});
$candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); });
}
// We cannot use the autoloader here as most of them use require; but if the class

View File

@ -417,6 +417,25 @@ class ErrorHandlerTest extends \PHPUnit_Framework_TestCase
$handler->setLoggers(array(E_DEPRECATED => array($mockLogger, LogLevel::WARNING)));
}
public function testSettingLoggerWhenExceptionIsBuffered()
{
$bootLogger = new BufferingLogger();
$handler = new ErrorHandler($bootLogger);
$exception = new \Exception('Foo message');
$mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$mockLogger->expects($this->once())
->method('log')
->with(LogLevel::CRITICAL, 'Uncaught Exception: Foo message', array('exception' => $exception));
$handler->setExceptionHandler(function () use ($handler, $mockLogger) {
$handler->setDefaultLogger($mockLogger);
});
$handler->handleException($exception);
}
public function testHandleFatalError()
{
try {

View File

@ -106,7 +106,7 @@ class Definition
}
/**
* Gets the service that decorates this service.
* Gets the service that this service is decorating.
*
* @return null|array An array composed of the decorated service id, the new id for it and the priority of decoration, null if no service is decorated
*/

View File

@ -121,7 +121,7 @@ class YamlFileLoader extends FileLoader
* @param array $content
* @param string $file
*/
private function parseImports($content, $file)
private function parseImports(array $content, $file)
{
if (!isset($content['imports'])) {
return;
@ -148,7 +148,7 @@ class YamlFileLoader extends FileLoader
* @param array $content
* @param string $file
*/
private function parseDefinitions($content, $file)
private function parseDefinitions(array $content, $file)
{
if (!isset($content['services'])) {
return;
@ -229,10 +229,10 @@ class YamlFileLoader extends FileLoader
/**
* Parses a definition.
*
* @param string $id
* @param array $service
* @param string $file
* @param array $defaults
* @param string $id
* @param array|string $service
* @param string $file
* @param array $defaults
*
* @throws InvalidArgumentException When tags are invalid
*/
@ -615,7 +615,7 @@ class YamlFileLoader extends FileLoader
*
* @param array $content
*/
private function loadFromExtensions($content)
private function loadFromExtensions(array $content)
{
foreach ($content as $namespace => $values) {
if (in_array($namespace, array('imports', 'parameters', 'services'))) {

View File

@ -192,7 +192,7 @@ class Crawler implements \Countable, \IteratorAggregate
$dom = new \DOMDocument('1.0', $charset);
$dom->validateOnParse = true;
set_error_handler(function () {throw new \Exception();});
set_error_handler(function () { throw new \Exception(); });
try {
// Convert charset to HTML-entities to work around bugs in DOMDocument::loadHTML()

View File

@ -212,7 +212,7 @@ class DateType extends AbstractType
array('year' => $default, 'month' => $default, 'day' => $default),
$choiceTranslationDomain
);
};
}
return array(
'year' => $choiceTranslationDomain,

View File

@ -213,7 +213,7 @@ class TimeType extends AbstractType
array('hour' => $default, 'minute' => $default, 'second' => $default),
$choiceTranslationDomain
);
};
}
return array(
'hour' => $choiceTranslationDomain,

View File

@ -290,7 +290,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
{
$html = '';
$dumper = new HtmlDumper(function ($line) use (&$html) {$html .= $line;}, $this->charset);
$dumper = new HtmlDumper(function ($line) use (&$html) { $html .= $line; }, $this->charset);
$dumper->setDumpHeader('');
$dumper->setDumpBoundaries('', '');

View File

@ -52,6 +52,6 @@ class AddRequestFormatsListener implements EventSubscriberInterface
*/
public static function getSubscribedEvents()
{
return array(KernelEvents::REQUEST => 'onKernelRequest');
return array(KernelEvents::REQUEST => array('onKernelRequest', 1));
}
}

View File

@ -45,7 +45,7 @@ class AddRequestFormatsListenerTest extends \PHPUnit_Framework_TestCase
public function testRegisteredEvent()
{
$this->assertEquals(
array(KernelEvents::REQUEST => 'onKernelRequest'),
array(KernelEvents::REQUEST => array('onKernelRequest', 1)),
AddRequestFormatsListener::getSubscribedEvents()
);
}

View File

@ -42,9 +42,6 @@ abstract class AbstractDataGenerator
$this->dirName = $dirName;
}
/**
* {@inheritdoc}
*/
public function generateData(GeneratorConfig $config)
{
$filesystem = new Filesystem();

View File

@ -57,9 +57,6 @@ class LocaleDataGenerator
$this->regionDataProvider = $regionDataProvider;
}
/**
* {@inheritdoc}
*/
public function generateData(GeneratorConfig $config)
{
$filesystem = new Filesystem();

View File

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
pcntl_signal(SIGUSR1, function () {echo 'SIGUSR1'; exit;});
pcntl_signal(SIGUSR1, function () { echo 'SIGUSR1'; exit; });
echo 'Caught ';

View File

@ -223,6 +223,9 @@ class PhpDocExtractor implements PropertyDescriptionExtractorInterface, Property
try {
$reflectionMethod = new \ReflectionMethod($class, $methodName);
if ($reflectionMethod->isStatic()) {
continue;
}
if (
(self::ACCESSOR === $type && 0 === $reflectionMethod->getNumberOfRequiredParameters()) ||

View File

@ -73,6 +73,10 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
}
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
if ($reflectionMethod->isStatic()) {
continue;
}
$propertyName = $this->getPropertyName($reflectionMethod->name, $reflectionProperties);
if (!$propertyName || isset($properties[$propertyName])) {
continue;
@ -263,6 +267,9 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
foreach (self::$accessorPrefixes as $prefix) {
try {
$reflectionMethod = new \ReflectionMethod($class, $prefix.$ucProperty);
if ($reflectionMethod->isStatic()) {
continue;
}
if (0 === $reflectionMethod->getNumberOfRequiredParameters()) {
return array($reflectionMethod, $prefix);
@ -298,6 +305,9 @@ class ReflectionExtractor implements PropertyListExtractorInterface, PropertyTyp
foreach ($names as $name) {
try {
$reflectionMethod = new \ReflectionMethod($class, $prefix.$name);
if ($reflectionMethod->isStatic()) {
continue;
}
// Parameter can be optional to allow things like: method(array $foo = null)
if ($reflectionMethod->getNumberOfParameters() >= 1) {

View File

@ -44,7 +44,7 @@ class PropertyInfoExtractor implements PropertyInfoExtractorInterface
* @param PropertyDescriptionExtractorInterface[] $descriptionExtractors
* @param PropertyAccessExtractorInterface[] $accessExtractors
*/
public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array())
public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array())
{
$this->listExtractors = $listExtractors;
$this->typeExtractors = $typeExtractors;

View File

@ -68,6 +68,8 @@ class PhpDocExtractorTest extends \PHPUnit_Framework_TestCase
array('e', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_RESOURCE))), null, null),
array('f', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null),
array('donotexist', null, null, null),
array('staticGetter', null, null, null),
array('staticSetter', null, null, null),
);
}

View File

@ -73,6 +73,8 @@ class ReflectionExtractorTest extends \PHPUnit_Framework_TestCase
array('e', null),
array('f', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')))),
array('donotexist', null),
array('staticGetter', null),
array('staticSetter', null),
);
}

View File

@ -51,6 +51,21 @@ class Dummy extends ParentDummy
*/
public $B;
public static function getStatic()
{
}
/**
* @return string
*/
public static function staticGetter()
{
}
public static function staticSetter(\DateTime $d)
{
}
/**
* A.
*

View File

@ -138,11 +138,6 @@ abstract class AnnotationClassLoader implements LoaderInterface
}
$defaults = array_replace($globals['defaults'], $annot->getDefaults());
foreach ($method->getParameters() as $param) {
if (!isset($defaults[$param->getName()]) && $param->isDefaultValueAvailable()) {
$defaults[$param->getName()] = $param->getDefaultValue();
}
}
$requirements = array_replace($globals['requirements'], $annot->getRequirements());
$options = array_replace($globals['options'], $annot->getOptions());
$schemes = array_merge($globals['schemes'], $annot->getSchemes());

View File

@ -136,11 +136,10 @@ class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
array_intersect_assoc($routeData['options'], $route->getOptions()),
'->load preserves options annotation'
);
$defaults = array_replace($methodArgs, $routeData['defaults']);
$this->assertCount(
count($defaults),
array_intersect_assoc($defaults, $route->getDefaults()),
'->load preserves defaults annotation and merges them with default arguments in method signature'
count($routeData['defaults']),
$route->getDefaults(),
'->load preserves defaults annotation'
);
$this->assertEquals($routeData['schemes'], $route->getSchemes(), '->load preserves schemes annotation');
$this->assertEquals($routeData['methods'], $route->getMethods(), '->load preserves methods annotation');

View File

@ -151,6 +151,48 @@ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
);
}
/**
* @expectedException \Symfony\Component\Security\Core\Exception\InvalidArgumentException
*/
public function testLoadUserByUsernameFailsIfEntryHasNoUidKeyAttribute()
{
$result = $this->getMock(CollectionInterface::class);
$query = $this->getMock(QueryInterface::class);
$query
->expects($this->once())
->method('execute')
->will($this->returnValue($result))
;
$ldap = $this->getMock(LdapInterface::class);
$result
->expects($this->once())
->method('offsetGet')
->with(0)
->will($this->returnValue(new Entry('foo', array())))
;
$result
->expects($this->once())
->method('count')
->will($this->returnValue(1))
;
$ldap
->expects($this->once())
->method('escape')
->will($this->returnValue('foo'))
;
$ldap
->expects($this->once())
->method('query')
->will($this->returnValue($query))
;
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com', null, null, array(), 'sAMAccountName', '({uid_key}={username})');
$this->assertInstanceOf(
'Symfony\Component\Security\Core\User\User',
$provider->loadUserByUsername('foo')
);
}
/**
* @expectedException \Symfony\Component\Security\Core\Exception\InvalidArgumentException
*/
@ -238,7 +280,7 @@ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
);
}
public function testLoadUserByUsernameIsSuccessfulWithPasswordAttribute()
public function testLoadUserByUsernameIsSuccessfulWithoutPasswordAttributeAndWrongCase()
{
$result = $this->getMockBuilder(CollectionInterface::class)->getMock();
$query = $this->getMockBuilder(QueryInterface::class)->getMock();
@ -248,6 +290,45 @@ class LdapUserProviderTest extends \PHPUnit_Framework_TestCase
->will($this->returnValue($result))
;
$ldap = $this->getMockBuilder(LdapInterface::class)->getMock();
$result
->expects($this->once())
->method('offsetGet')
->with(0)
->will($this->returnValue(new Entry('foo', array(
'sAMAccountName' => array('foo'),
)
)))
;
$result
->expects($this->once())
->method('count')
->will($this->returnValue(1))
;
$ldap
->expects($this->once())
->method('escape')
->will($this->returnValue('Foo'))
;
$ldap
->expects($this->once())
->method('query')
->will($this->returnValue($query))
;
$provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com');
$this->assertSame('foo', $provider->loadUserByUsername('Foo')->getUsername());
}
public function testLoadUserByUsernameIsSuccessfulWithPasswordAttribute()
{
$result = $this->getMock(CollectionInterface::class);
$query = $this->getMock(QueryInterface::class);
$query
->expects($this->once())
->method('execute')
->will($this->returnValue($result))
;
$ldap = $this->getMock(LdapInterface::class);
$result
->expects($this->once())
->method('offsetGet')

View File

@ -31,6 +31,7 @@ class LdapUserProvider implements UserProviderInterface
private $searchDn;
private $searchPassword;
private $defaultRoles;
private $uidKey;
private $defaultSearch;
private $passwordAttribute;
@ -46,11 +47,16 @@ class LdapUserProvider implements UserProviderInterface
*/
public function __construct(LdapInterface $ldap, $baseDn, $searchDn = null, $searchPassword = null, array $defaultRoles = array(), $uidKey = 'sAMAccountName', $filter = '({uid_key}={username})', $passwordAttribute = null)
{
if (null === $uidKey) {
$uidKey = 'uid';
}
$this->ldap = $ldap;
$this->baseDn = $baseDn;
$this->searchDn = $searchDn;
$this->searchPassword = $searchPassword;
$this->defaultRoles = $defaultRoles;
$this->uidKey = $uidKey;
$this->defaultSearch = str_replace('{uid_key}', $uidKey, $filter);
$this->passwordAttribute = $passwordAttribute;
}
@ -80,7 +86,10 @@ class LdapUserProvider implements UserProviderInterface
throw new UsernameNotFoundException('More than one user found');
}
return $this->loadUser($username, $entries[0]);
$entry = $entries[0];
$username = $this->getAttributeValue($entry, $this->uidKey);
return $this->loadUser($username, $entry);
}
/**
@ -113,30 +122,30 @@ class LdapUserProvider implements UserProviderInterface
*/
protected function loadUser($username, Entry $entry)
{
$password = $this->getPassword($entry);
$password = null;
if (null !== $this->passwordAttribute) {
$password = $this->getAttributeValue($entry, $this->passwordAttribute);
}
return new User($username, $password, $this->defaultRoles);
}
/**
* Fetches the password from an LDAP entry.
* Fetches a required unique attribute value from an LDAP entry.
*
* @param null|Entry $entry
* @param string $attribute
*/
private function getPassword(Entry $entry)
private function getAttributeValue(Entry $entry, $attribute)
{
if (null === $this->passwordAttribute) {
return;
if (!$entry->hasAttribute($attribute)) {
throw new InvalidArgumentException(sprintf('Missing attribute "%s" for user "%s".', $attribute, $entry->getDn()));
}
if (!$entry->hasAttribute($this->passwordAttribute)) {
throw new InvalidArgumentException(sprintf('Missing attribute "%s" for user "%s".', $this->passwordAttribute, $entry->getDn()));
}
$values = $entry->getAttribute($this->passwordAttribute);
$values = $entry->getAttribute($attribute);
if (1 !== count($values)) {
throw new InvalidArgumentException(sprintf('Attribute "%s" has multiple values.', $this->passwordAttribute));
throw new InvalidArgumentException(sprintf('Attribute "%s" has multiple values.', $attribute));
}
return $values[0];

View File

@ -61,7 +61,7 @@ class JsonDecodeTest extends \PHPUnit_Framework_TestCase
*/
public function testDecodeWithException($value)
{
$this->decode->decode($value, JsonEncoder::FORMAT);
$this->decode->decode($value, JsonEncoder::FORMAT);
}
public function decodeProviderException()

View File

@ -54,6 +54,6 @@ class JsonEncodeTest extends \PHPUnit_Framework_TestCase
*/
public function testEncodeWithError()
{
$this->encode->encode("\xB1\x31", JsonEncoder::FORMAT);
$this->encode->encode("\xB1\x31", JsonEncoder::FORMAT);
}
}

View File

@ -26,7 +26,7 @@ class FileDumperTest extends \PHPUnit_Framework_TestCase
$dumper = new ConcreteFileDumper();
$dumper->dump($catalogue, array('path' => $tempDir));
$this->assertTrue(file_exists($tempDir.'/messages.en.concrete'));
$this->assertFileExists($tempDir.'/messages.en.concrete');
}
/**

View File

@ -62,7 +62,7 @@ class ArrayConverter
* $tree['foo'] was string before we found array {bar: test2}.
* Treat new element as string too, e.g. add $tree['foo.bar'] = 'test2';
*/
$elem = &$elem[ implode('.', array_slice($parts, $i)) ];
$elem = &$elem[implode('.', array_slice($parts, $i))];
break;
}
$parentOfElem = &$elem;

View File

@ -17,7 +17,7 @@ use Symfony\Component\Validator\ConstraintValidator;
/**
* @author Michael Hirschler <michael.vhirsch@gmail.com>
*
* @link https://en.wikipedia.org/wiki/ISO_9362#Structure
* @see https://en.wikipedia.org/wiki/ISO_9362#Structure
*/
class BicValidator extends ConstraintValidator
{

View File

@ -2,7 +2,9 @@
namespace Symfony\Component\Workflow\Tests\Validator;
use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\Tests\WorkflowBuilderTrait;
use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\Validator\WorkflowValidator;
class WorkflowValidatorTest extends \PHPUnit_Framework_TestCase
@ -26,4 +28,36 @@ class WorkflowValidatorTest extends \PHPUnit_Framework_TestCase
(new WorkflowValidator(true))->validate($definition, 'foo');
}
/**
* @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException
* @expectedExceptionMessage All transitions for a place must have an unique name. Multiple transitions named "t1" where found for place "a" in workflow "foo".
*/
public function testWorkflowWithInvalidNames()
{
$places = range('a', 'c');
$transitions = array();
$transitions[] = new Transition('t0', 'c', 'b');
$transitions[] = new Transition('t1', 'a', 'b');
$transitions[] = new Transition('t1', 'a', 'c');
$definition = new Definition($places, $transitions);
(new WorkflowValidator())->validate($definition, 'foo');
}
public function testSameTransitionNameButNotSamePlace()
{
$places = range('a', 'd');
$transitions = array();
$transitions[] = new Transition('t1', 'a', 'b');
$transitions[] = new Transition('t1', 'b', 'c');
$transitions[] = new Transition('t1', 'd', 'c');
$definition = new Definition($places, $transitions);
(new WorkflowValidator())->validate($definition, 'foo');
}
}

View File

@ -49,6 +49,34 @@ trait WorkflowBuilderTrait
// +---+ +----+ +---+ +----+ +---+
}
private function createWorkflowWithSameNameTransition()
{
$places = range('a', 'c');
$transitions = array();
$transitions[] = new Transition('a_to_bc', 'a', array('b', 'c'));
$transitions[] = new Transition('b_to_c', 'b', 'c');
$transitions[] = new Transition('to_a', 'b', 'a');
$transitions[] = new Transition('to_a', 'c', 'a');
return new Definition($places, $transitions);
// The graph looks like:
// +------------------------------------------------------------+
// | |
// | |
// | +----------------------------------------+ |
// v | v |
// +---+ +---------+ +---+ +--------+ +---+ +------+
// | a | --> | a_to_bc | --> | b | --> | b_to_c | --> | c | --> | to_a | -+
// +---+ +---------+ +---+ +--------+ +---+ +------+ |
// ^ | ^ |
// | +----------------------------------+ |
// | |
// | |
// +--------------------------------------------------------------------+
}
private function createComplexStateMachineDefinition()
{
$places = array('a', 'b', 'c', 'd');

View File

@ -48,7 +48,7 @@ class WorkflowTest extends \PHPUnit_Framework_TestCase
public function testGetMarkingWithImpossiblePlace()
{
$subject = new \stdClass();
$subject->marking = array('nope' => true);
$subject->marking = array('nope' => 1);
$workflow = new Workflow(new Definition(array(), array()), new MultipleStateMarkingStore());
$workflow->getMarking($subject);
@ -83,10 +83,6 @@ class WorkflowTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($marking->has('c'));
}
/**
* @expectedException \Symfony\Component\Workflow\Exception\LogicException
* @expectedExceptionMessage Transition "foobar" does not exist for workflow "unnamed".
*/
public function testCanWithUnexistingTransition()
{
$definition = $this->createComplexWorkflowDefinition();
@ -94,7 +90,7 @@ class WorkflowTest extends \PHPUnit_Framework_TestCase
$subject->marking = null;
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
$workflow->can($subject, 'foobar');
$this->assertFalse($workflow->can($subject, 'foobar'));
}
public function testCan()
@ -136,6 +132,23 @@ class WorkflowTest extends \PHPUnit_Framework_TestCase
$workflow->apply($subject, 't2');
}
public function testCanWithSameNameTransition()
{
$definition = $this->createWorkflowWithSameNameTransition();
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
$subject = new \stdClass();
$subject->marking = null;
$this->assertTrue($workflow->can($subject, 'a_to_bc'));
$this->assertFalse($workflow->can($subject, 'b_to_c'));
$this->assertFalse($workflow->can($subject, 'to_a'));
$subject->marking = array('b' => 1);
$this->assertFalse($workflow->can($subject, 'a_to_bc'));
$this->assertTrue($workflow->can($subject, 'b_to_c'));
$this->assertTrue($workflow->can($subject, 'to_a'));
}
public function testApply()
{
$definition = $this->createComplexWorkflowDefinition();
@ -151,6 +164,59 @@ class WorkflowTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($marking->has('c'));
}
public function testApplyWithSameNameTransition()
{
$subject = new \stdClass();
$subject->marking = null;
$definition = $this->createWorkflowWithSameNameTransition();
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
$marking = $workflow->apply($subject, 'a_to_bc');
$this->assertFalse($marking->has('a'));
$this->assertTrue($marking->has('b'));
$this->assertTrue($marking->has('c'));
$marking = $workflow->apply($subject, 'to_a');
$this->assertTrue($marking->has('a'));
$this->assertFalse($marking->has('b'));
$this->assertFalse($marking->has('c'));
$marking = $workflow->apply($subject, 'a_to_bc');
$marking = $workflow->apply($subject, 'b_to_c');
$this->assertFalse($marking->has('a'));
$this->assertFalse($marking->has('b'));
$this->assertTrue($marking->has('c'));
$marking = $workflow->apply($subject, 'to_a');
$this->assertTrue($marking->has('a'));
$this->assertFalse($marking->has('b'));
$this->assertFalse($marking->has('c'));
}
public function testApplyWithSameNameTransition2()
{
$subject = new \stdClass();
$subject->marking = array('a' => 1, 'b' => 1);
$places = range('a', 'd');
$transitions = array();
$transitions[] = new Transition('t', 'a', 'c');
$transitions[] = new Transition('t', 'b', 'd');
$definition = new Definition($places, $transitions);
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
$marking = $workflow->apply($subject, 't');
$this->assertFalse($marking->has('a'));
$this->assertFalse($marking->has('b'));
$this->assertTrue($marking->has('c'));
$this->assertTrue($marking->has('d'));
}
public function testApplyWithEventDispatcher()
{
$definition = $this->createComplexWorkflowDefinition();
@ -198,17 +264,36 @@ class WorkflowTest extends \PHPUnit_Framework_TestCase
$this->assertEmpty($workflow->getEnabledTransitions($subject));
$subject->marking = array('d' => true);
$subject->marking = array('d' => 1);
$transitions = $workflow->getEnabledTransitions($subject);
$this->assertCount(2, $transitions);
$this->assertSame('t3', $transitions[0]->getName());
$this->assertSame('t4', $transitions[1]->getName());
$subject->marking = array('c' => true, 'e' => true);
$subject->marking = array('c' => 1, 'e' => 1);
$transitions = $workflow->getEnabledTransitions($subject);
$this->assertCount(1, $transitions);
$this->assertSame('t5', $transitions[0]->getName());
}
public function testGetEnabledTransitionsWithSameNameTransition()
{
$definition = $this->createWorkflowWithSameNameTransition();
$subject = new \stdClass();
$subject->marking = null;
$workflow = new Workflow($definition, new MultipleStateMarkingStore());
$transitions = $workflow->getEnabledTransitions($subject);
$this->assertCount(1, $transitions);
$this->assertSame('a_to_bc', $transitions[0]->getName());
$subject->marking = array('b' => 1, 'c' => 1);
$transitions = $workflow->getEnabledTransitions($subject);
$this->assertCount(3, $transitions);
$this->assertSame('b_to_c', $transitions[0]->getName());
$this->assertSame('to_a', $transitions[1]->getName());
$this->assertSame('to_a', $transitions[2]->getName());
}
}
class EventDispatcherMock implements \Symfony\Component\EventDispatcher\EventDispatcherInterface
@ -223,21 +308,27 @@ class EventDispatcherMock implements \Symfony\Component\EventDispatcher\EventDis
public function addListener($eventName, $listener, $priority = 0)
{
}
public function addSubscriber(\Symfony\Component\EventDispatcher\EventSubscriberInterface $subscriber)
{
}
public function removeListener($eventName, $listener)
{
}
public function removeSubscriber(\Symfony\Component\EventDispatcher\EventSubscriberInterface $subscriber)
{
}
public function getListeners($eventName = null)
{
}
public function getListenerPriority($eventName, $listener)
{
}
public function hasListeners($eventName = null)
{
}

View File

@ -31,6 +31,17 @@ class WorkflowValidator implements DefinitionValidatorInterface
public function validate(Definition $definition, $name)
{
// Make sure all transitions for one place has unique name.
$places = array_fill_keys($definition->getPlaces(), array());
foreach ($definition->getTransitions() as $transition) {
foreach ($transition->getFroms() as $from) {
if (in_array($transition->getName(), $places[$from])) {
throw new InvalidDefinitionException(sprintf('All transitions for a place must have an unique name. Multiple transitions named "%s" where found for place "%s" in workflow "%s".', $transition->getName(), $from, $name));
}
$places[$from][] = $transition->getName();
}
}
if (!$this->singlePlace) {
return;
}

View File

@ -89,15 +89,18 @@ class Workflow
* @param string $transitionName A transition
*
* @return bool true if the transition is enabled
*
* @throws LogicException If the transition does not exist
*/
public function can($subject, $transitionName)
{
$transitions = $this->getTransitions($transitionName);
$marking = $this->getMarking($subject);
$transitions = $this->getEnabledTransitions($subject, $this->getMarking($subject));
return null !== $this->getTransitionForSubject($subject, $marking, $transitions);
foreach ($transitions as $transition) {
if ($transitionName === $transition->getName()) {
return true;
}
}
return false;
}
/**
@ -113,22 +116,36 @@ class Workflow
*/
public function apply($subject, $transitionName)
{
$transitions = $this->getTransitions($transitionName);
$marking = $this->getMarking($subject);
$transitions = $this->getEnabledTransitions($subject, $this->getMarking($subject));
if (null === $transition = $this->getTransitionForSubject($subject, $marking, $transitions)) {
throw new LogicException(sprintf('Unable to apply transition "%s" for workflow "%s".', $transitionName, $this->name));
// We can shortcut the getMarking method in order to boost performance,
// since the "getEnabledTransitions" method already checks the Marking
// state
$marking = $this->markingStore->getMarking($subject);
$applied = false;
foreach ($transitions as $transition) {
if ($transitionName !== $transition->getName()) {
continue;
}
$applied = true;
$this->leave($subject, $transition, $marking);
$this->transition($subject, $transition, $marking);
$this->enter($subject, $transition, $marking);
$this->markingStore->setMarking($subject, $marking);
$this->announce($subject, $transition, $marking);
}
$this->leave($subject, $transition, $marking);
$this->transition($subject, $transition, $marking);
$this->enter($subject, $transition, $marking);
$this->markingStore->setMarking($subject, $marking);
$this->announce($subject, $transition, $marking);
if (!$applied) {
throw new LogicException(sprintf('Unable to apply transition "%s" for workflow "%s".', $transitionName, $this->name));
}
return $marking;
}
@ -146,7 +163,7 @@ class Workflow
$marking = $this->getMarking($subject);
foreach ($this->definition->getTransitions() as $transition) {
if (null !== $this->getTransitionForSubject($subject, $marking, array($transition))) {
if ($this->doCan($subject, $marking, $transition)) {
$enabled[] = $transition;
}
}
@ -167,6 +184,21 @@ class Workflow
return $this->definition;
}
private function doCan($subject, Marking $marking, Transition $transition)
{
foreach ($transition->getFroms() as $place) {
if (!$marking->has($place)) {
return false;
}
}
if (true === $this->guardTransition($subject, $marking, $transition)) {
return false;
}
return true;
}
/**
* @param object $subject
* @param Marking $marking
@ -246,56 +278,8 @@ class Workflow
$event = new Event($subject, $marking, $initialTransition);
foreach ($this->definition->getTransitions() as $transition) {
if (null !== $this->getTransitionForSubject($subject, $marking, array($transition))) {
$this->dispatcher->dispatch(sprintf('workflow.%s.announce.%s', $this->name, $transition->getName()), $event);
}
}
}
/**
* @param $transitionName
*
* @return Transition[]
*/
private function getTransitions($transitionName)
{
$transitions = $this->definition->getTransitions();
$transitions = array_filter($transitions, function (Transition $transition) use ($transitionName) {
return $transitionName === $transition->getName();
});
if (!$transitions) {
throw new LogicException(sprintf('Transition "%s" does not exist for workflow "%s".', $transitionName, $this->name));
}
return $transitions;
}
/**
* Return the first Transition in $transitions that is valid for the
* $subject and $marking. null is returned when you cannot do any Transition
* in $transitions on the $subject.
*
* @param object $subject
* @param Marking $marking
* @param Transition[] $transitions
*
* @return Transition|null
*/
private function getTransitionForSubject($subject, Marking $marking, array $transitions)
{
foreach ($transitions as $transition) {
foreach ($transition->getFroms() as $place) {
if (!$marking->has($place)) {
continue 2;
}
}
if (true !== $this->guardTransition($subject, $marking, $transition)) {
return $transition;
}
foreach ($this->getEnabledTransitions($subject) as $transition) {
$this->dispatcher->dispatch(sprintf('workflow.%s.announce.%s', $this->name, $transition->getName()), $event);
}
}
}

View File

@ -23,7 +23,7 @@ use Symfony\Component\Yaml\Exception\DumpException;
*/
class Inline
{
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')';
const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
public static $parsedLineNumber;

View File

@ -676,4 +676,14 @@ class InlineTest extends \PHPUnit_Framework_TestCase
{
Inline::parse('{this, is not, supported}');
}
public function testVeryLongQuotedStrings()
{
$longStringWithQuotes = str_repeat("x\r\n\\\"x\"x", 1000);
$yamlString = Inline::dump(array('longStringWithQuotes' => $longStringWithQuotes));
$arrayFromYaml = Inline::parse($yamlString);
$this->assertEquals($longStringWithQuotes, $arrayFromYaml['longStringWithQuotes']);
}
}