From 44a49ab105fcdc5631623860a87277d5b7ad45c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Wed, 24 Oct 2012 18:03:38 +0200 Subject: [PATCH 01/12] [http-foundation] Added 'AcceptHeaderItem' class + test. --- .../HttpFoundation/AcceptHeaderItem.php | 199 ++++++++++++++++++ .../Tests/AcceptHeaderItemTest.php | 112 ++++++++++ 2 files changed, 311 insertions(+) create mode 100644 src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderItemTest.php diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php new file mode 100644 index 0000000000000..abcef2887852b --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php @@ -0,0 +1,199 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation; + +/** + * Represents an Accept-* header item. + * + * @author Jean-François Simon + */ +class AcceptHeaderItem +{ + /** + * @var string + */ + private $value; + + /** + * @var float + */ + private $quality; + + /** + * @var array + */ + private $attributes; + + /** + * Builds an AcceptHeaderInstance instance from a string. + * + * @param string $itemValue + * + * @return AcceptHeaderItem + */ + public static function fromString($itemValue) + { + $bits = preg_split('/\s*(?:;*("[^"]+");*|;*(\'[^\']+\');*|;+)\s*/', $itemValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); + $value = array_shift($bits); + $attributes = array(); + + $lastNullAttribute = null; + foreach ($bits as $bit) { + if (($start = substr($bit, 0, 1)) === ($end = substr($bit, -1)) && ($start === '"' || $start === '\'')) { + $attributes[$lastNullAttribute] = substr($bit, 1, -1); + } elseif ('=' === $end) { + $lastNullAttribute = $bit = substr($bit, 0, -1); + $attributes[$bit] = null; + } else { + $parts = explode('=', $bit); + $attributes[$parts[0]] = isset($parts[1]) && strlen($parts[1]) > 0 ? $parts[1] : ''; + } + } + + return new static(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ($start === '"' || $start === '\'') ? substr($value, 1, -1) : $value, $attributes); + } + + /** + * Constructor. + * + * @param string $value + * @param array $attributes + */ + public function __construct($value, array $attributes = array()) + { + $this->value = $value; + $this->quality = 1.0; + $this->attributes = array(); + foreach ($attributes as $name => $value) { + $this->setAttribute($name, $value); + } + } + + /** + * Returns header value's string representation. + * + * @return string + */ + public function __toString() + { + $string = $this->value.($this->quality < 1 ? ';q='.$this->quality : ''); + if (count($this->attributes) > 0) { + $string .= ';'.implode(';', array_map(function($name, $value) { + return sprintf(preg_match('/[,;=]/', $value) ? '%s="%s"' : '%s=%s', $name, $value); + }, array_keys($this->attributes), $this->attributes)); + } + + return $string; + } + + /** + * Set the item value. + * + * @param string $value + * + * @return AcceptHeaderItem + */ + public function setValue($value) + { + $this->value = $value; + + return $this; + } + + /** + * Returns the item value. + * + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * Set the item quality. + * + * @param float $quality + * + * @return AcceptHeaderItem + */ + public function setQuality($quality) + { + $this->quality = $quality; + + return $this; + } + + /** + * Returns the item quality. + * + * @return float + */ + public function getQuality() + { + return $this->quality; + } + + /** + * Tests if an attribute exists. + * + * @param string $name + * + * @return bool + */ + public function hasAttribute($name) + { + return isset($this->attributes[$name]); + } + + /** + * Returns an attribute by its name. + * + * @param string $name + * @param mixed $default + * + * @return mixed + */ + public function getAttribute($name, $default = null) + { + return isset($this->attributes[$name]) ? $this->attributes[$name] : $default; + } + + /** + * Returns all attributes. + * + * @return array + */ + public function getAttributes() + { + return $this->attributes; + } + + /** + * Set an attribute. + * + * @param string $name + * @param string $value + * + * @return AcceptHeaderItem + */ + public function setAttribute($name, $value) + { + if ('q' === $name) { + $this->quality = (float) $value; + } else { + $this->attributes[$name] = (string) $value; + } + + return $this; + } +} \ No newline at end of file diff --git a/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderItemTest.php b/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderItemTest.php new file mode 100644 index 0000000000000..d579be820093e --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderItemTest.php @@ -0,0 +1,112 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests; + +use Symfony\Component\HttpFoundation\AcceptHeaderItem; + +class AcceptHeaderItemTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideFromStringData + */ + public function testFromString($string, $value, array $attributes) + { + $item = AcceptHeaderItem::fromString($string); + $this->assertEquals($value, $item->getValue()); + $this->assertEquals($attributes, $item->getAttributes()); + } + + /** + * @dataProvider provideToStringData + */ + public function testToString($value, array $attributes, $string) + { + $item = new AcceptHeaderItem($value, $attributes); + $this->assertEquals($string, (string) $item); + } + + public function testValue() + { + $item = new AcceptHeaderItem('value', array()); + $this->assertEquals('value', $item->getValue()); + + $item->setValue('new value'); + $this->assertEquals('new value', $item->getValue()); + + $item->setValue(1); + $this->assertEquals('1', $item->getValue()); + } + + public function testQuality() + { + $item = new AcceptHeaderItem('value', array()); + $this->assertEquals(1.0, $item->getQuality()); + + $item->setQuality(0.5); + $this->assertEquals(0.5, $item->getQuality()); + + $item->setAttribute('q', 0.75); + $this->assertEquals(0.75, $item->getQuality()); + $this->assertFalse($item->hasAttribute('q')); + } + + public function testAttribute() + { + $item = new AcceptHeaderItem('value', array()); + $this->assertEquals(array(), $item->getAttributes()); + $this->assertFalse($item->hasAttribute('test')); + $this->assertNull($item->getAttribute('test')); + $this->assertEquals('default', $item->getAttribute('test', 'default')); + + $item->setAttribute('test', 'value'); + $this->assertEquals(array('test' => 'value'), $item->getAttributes()); + $this->assertTrue($item->hasAttribute('test')); + $this->assertEquals('value', $item->getAttribute('test')); + $this->assertEquals('value', $item->getAttribute('test', 'default')); + } + + public function provideFromStringData() + { + return array( + array( + 'text/html', + 'text/html', array() + ), + array( + '"this;should,not=matter"', + 'this;should,not=matter', array() + ), + array( + "text/plain; charset=utf-8;param=\"this;should,not=matter\";\tfootnotes=true", + 'text/plain', array('charset' => 'utf-8', 'param' => 'this;should,not=matter', 'footnotes' => 'true') + ), + array( + '"this;should,not=matter";charset=utf-8', + 'this;should,not=matter', array('charset' => 'utf-8') + ), + ); + } + + public function provideToStringData() + { + return array( + array( + 'text/html', array(), + 'text/html' + ), + array( + 'text/plain', array('charset' => 'utf-8', 'param' => 'this;should,not=matter', 'footnotes' => 'true'), + 'text/plain;charset=utf-8;param="this;should,not=matter";footnotes=true' + ), + ); + } +} From 645b6568d823336437f51aa18a00078775670c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Thu, 25 Oct 2012 12:40:18 +0200 Subject: [PATCH 02/12] [http-foundation] Added 'AcceptHeader' class + test. --- .../Component/HttpFoundation/AcceptHeader.php | 163 ++++++++++++++++++ .../HttpFoundation/Tests/AcceptHeaderTest.php | 89 ++++++++++ 2 files changed, 252 insertions(+) create mode 100644 src/Symfony/Component/HttpFoundation/AcceptHeader.php create mode 100644 src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderTest.php diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeader.php b/src/Symfony/Component/HttpFoundation/AcceptHeader.php new file mode 100644 index 0000000000000..ac69f1482aaa0 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/AcceptHeader.php @@ -0,0 +1,163 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation; + +/** + * Represents an Accept-* header. + * + * An accept header is compound with a list of items, + * sorted by descending quality. + * + * @author Jean-François Simon + */ +class AcceptHeader +{ + const EPSILON = 0.00001; + + /** + * @var AcceptHeaderItem[] + */ + private $items; + + /** + * @var bool + */ + private $sorted; + + /** + * Builds an AcceptHeader instance from a string. + * + * @param string $headerValue + * + * @return AcceptHeader + */ + public static function fromString($headerValue) + { + return new static(array_map(function ($itemValue) { + return AcceptHeaderItem::fromString($itemValue); + }, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE))); + } + + /** + * Constructor. + * + * @param array $items + */ + public function __construct(array $items) + { + $this->sorted = true; + $this->items = array(); + foreach ($items as $item) { + $this->add($item); + } + } + + /** + * Returns header value's string representation. + * + * @return string + */ + public function __toString() + { + return implode(',', $this->items); + } + + /** + * Tests if header has given value. + * + * @param string $value + * + * @return bool + */ + public function has($value) + { + return isset($this->items[$value]); + } + + /** + * Returns given value's item, if exists. + * + * @param string $value + * + * @return AcceptHeaderItem|null + */ + public function get($value) + { + return isset($this->items[$value]) ? $this->items[$value] : null; + } + + /** + * Adds an item. + * + * @param AcceptHeaderItem $item + * + * @return AcceptHeader + */ + public function add(AcceptHeaderItem $item) + { + $this->items[$item->getValue()] = $item; + $this->sorted = false; + + return $this; + } + + /** + * Returns all items. + * + * @return AcceptHeaderItem[] + */ + public function all() + { + $this->ensureSorted(); + + return $this->items; + } + + /** + * Filters items on their value using given regex. + * + * @param string $pattern + * + * @return AcceptHeader + */ + public function filter($pattern) + { + return new static(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) { + return preg_match($pattern, $item->getValue()); + })); + } + + /** + * Returns first item. + * + * @return AcceptHeaderItem|null + */ + public function first() + { + $this->ensureSorted(); + + return count($this->items) ? current($this->items) : null; + } + + /** + * Ensures items are sorted by descending quality + */ + private function ensureSorted() + { + if (!$this->sorted) { + $epsilon = self::EPSILON; + uasort($this->items, function (AcceptHeaderItem $a, AcceptHeaderItem $b) use ($epsilon) { + return $a->getQuality() - $epsilon < $b->getQuality() + $epsilon; + }); + } + } +} \ No newline at end of file diff --git a/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderTest.php b/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderTest.php new file mode 100644 index 0000000000000..15823eab9be87 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests; + +use Symfony\Component\HttpFoundation\AcceptHeader; +use Symfony\Component\HttpFoundation\AcceptHeaderItem; + +class AcceptHeaderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @dataProvider provideFromStringData + */ + public function testFromString($string, array $items) + { + $header = AcceptHeader::fromString($string); + $this->assertEquals($items, array_values($header->all())); + } + + /** + * @dataProvider provideToStringData + */ + public function testToString(array $items, $string) + { + $header = new AcceptHeader($items); + $this->assertEquals($string, (string) $header); + } + + /** + * @dataProvider provideFilterData + */ + public function testFilter($string, $filter, array $values) + { + $header = AcceptHeader::fromString($string)->filter($filter); + $this->assertEquals($values, array_keys($header->all())); + } + + /** + * @dataProvider provideSortingData + */ + public function testSorting($string, array $values) + { + $header = AcceptHeader::fromString($string); + $this->assertEquals($values, array_keys($header->all())); + } + + public function provideFromStringData() + { + return array( + array('', array()), + array('gzip', array(new AcceptHeaderItem('gzip'))), + array('gzip,deflate,sdch', array(new AcceptHeaderItem('gzip'), new AcceptHeaderItem('deflate'), new AcceptHeaderItem('sdch'))), + array("gzip, deflate\t,sdch", array(new AcceptHeaderItem('gzip'), new AcceptHeaderItem('deflate'), new AcceptHeaderItem('sdch'))), + array('"this;should,not=matter"', array(new AcceptHeaderItem('this;should,not=matter'))), + ); + } + + public function provideFilterData() + { + return array( + array('fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4', '/fr.*/', array('fr-FR', 'fr')), + ); + } + + public function provideSortingData() + { + return array( + array('*;q=0.3,ISO-8859-1,utf-8;q=0.7', array('ISO-8859-1', 'utf-8', '*')), + ); + } + + public function provideToStringData() + { + return array( + array(array(), ''), + array(array(new AcceptHeaderItem('gzip')), 'gzip'), + array(array(new AcceptHeaderItem('gzip'), new AcceptHeaderItem('deflate'), new AcceptHeaderItem('sdch')), 'gzip,deflate,sdch'), + array(array(new AcceptHeaderItem('this;should,not=matter')), 'this;should,not=matter'), + ); + } +} From a94cb11da7c2e13a650cfc4b137f5e91ac1839da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Thu, 25 Oct 2012 18:28:55 +0200 Subject: [PATCH 03/12] [http-foundation] Fixed 'AcceptHeader' sorting. --- .../Component/HttpFoundation/AcceptHeader.php | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeader.php b/src/Symfony/Component/HttpFoundation/AcceptHeader.php index ac69f1482aaa0..52ab736d35af6 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeader.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeader.php @@ -21,8 +21,6 @@ */ class AcceptHeader { - const EPSILON = 0.00001; - /** * @var AcceptHeaderItem[] */ @@ -154,10 +152,45 @@ public function first() private function ensureSorted() { if (!$this->sorted) { - $epsilon = self::EPSILON; - uasort($this->items, function (AcceptHeaderItem $a, AcceptHeaderItem $b) use ($epsilon) { - return $a->getQuality() - $epsilon < $b->getQuality() + $epsilon; - }); + $this->items = $this->sort($this->items); + } + } + + /** + * @param array $array + * + * @return array + */ + private function sort(array $array) + { + if (count($array) < 2) { + return $array; } + + $middle = count($array) / 2; + + return $this->merge( + $this->sort(array_slice($array, 0, $middle)), + $this->sort(array_slice($array, $middle)) + ); + } + + private function merge(array $left, array $right) + { + $array = array(); + while (count($left) + count($right) > 0) { + if (0 === count($left) || $shiftLeft = 0 === count($right)) { + list($key, $value) = $shiftLeft + ? each(array_splice($left, 0, 1)) + : each(array_splice($right, 0, 1)); + } else { + list($key, $value) = current($right)->getQuality() > current($left)->getQuality() + ? each(array_splice($right, 0, 1)) + : each(array_splice($left, 0, 1)); + } + $array[$key] = $value; + } + + return $array; } } \ No newline at end of file From 2e73660325804c184fedb881fb2984dcc0ab03af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Fri, 26 Oct 2012 10:03:06 +0200 Subject: [PATCH 04/12] [http-foudation] Updated request object & tests. --- .../Component/HttpFoundation/Request.php | 34 +----------- .../HttpFoundation/Tests/RequestTest.php | 52 ++++++++++++++++--- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 7ce29c3a7be0d..91793844712cd 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1189,7 +1189,7 @@ public function getLanguages() $languages = $this->splitHttpAcceptHeader($this->headers->get('Accept-Language')); $this->languages = array(); - foreach ($languages as $lang => $q) { + foreach (array_keys($languages) as $lang) { if (strstr($lang, '-')) { $codes = explode('-', $lang); if ($codes[0] == 'i') { @@ -1272,37 +1272,7 @@ public function isXmlHttpRequest() */ public function splitHttpAcceptHeader($header) { - if (!$header) { - return array(); - } - - $values = array(); - $groups = array(); - foreach (array_filter(explode(',', $header)) as $value) { - // Cut off any q-value that might come after a semi-colon - if (preg_match('/;\s*(q=.*$)/', $value, $match)) { - $q = substr(trim($match[1]), 2); - $value = trim(substr($value, 0, -strlen($match[0]))); - } else { - $q = 1; - } - - $groups[$q][] = $value; - } - - krsort($groups); - - foreach ($groups as $q => $items) { - $q = (float) $q; - - if (0 < $q) { - foreach ($items as $value) { - $values[trim($value)] = $q; - } - } - } - - return $values; + return AcceptHeader::fromString($header)->all(); } /* diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 0a03eeb6514c3..1fde4f15c1b2b 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -14,6 +14,8 @@ use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\AcceptHeader; +use Symfony\Component\HttpFoundation\AcceptHeaderItem; class RequestTest extends \PHPUnit_Framework_TestCase { @@ -1023,13 +1025,49 @@ public function splitHttpAcceptHeaderData() { return array( array(null, array()), - array('text/html;q=0.8', array('text/html' => 0.8)), - array('text/html;foo=bar;q=0.8 ', array('text/html;foo=bar' => 0.8)), - array('text/html;charset=utf-8; q=0.8', array('text/html;charset=utf-8' => 0.8)), - array('text/html,application/xml;q=0.9,*/*;charset=utf-8; q=0.8', array('text/html' => 1, 'application/xml' => 0.9, '*/*;charset=utf-8' => 0.8)), - array('text/html,application/xhtml+xml;q=0.9,*/*;q=0.8; foo=bar', array('text/html' => 1, 'application/xhtml+xml' => 0.9, '*/*' => 0.8)), - array('text/html,application/xhtml+xml;charset=utf-8;q=0.9; foo=bar,*/*', array('text/html' => 1, '*/*' => 1, 'application/xhtml+xml;charset=utf-8' => 0.9)), - array('text/html,application/xhtml+xml', array('application/xhtml+xml' => 1, 'text/html' => 1)), + array( + 'text/html;q=0.8', + array('text/html' => new AcceptHeaderItem('text/html', array('q' => 0.8))) + ), + array( + 'text/html;foo=bar;q=0.8 ', + array('text/html' => new AcceptHeaderItem('text/html', array('q' => 0.8, 'foo' => 'bar'))) + ), + array( + 'text/html;charset=utf-8; q=0.8', + array('text/html' => new AcceptHeaderItem('text/html', array('q' => 0.8, 'charset' => 'utf-8'))) + ), + array( + 'text/html,application/xml;q=0.9,*/*;charset=utf-8; q=0.8', + array( + 'text/html' => new AcceptHeaderItem('text/html'), + 'application/xml' => new AcceptHeaderItem('application/xml', array('q' => 0.9)), + '*/*' => new AcceptHeaderItem('*/*', array('q' => 0.8, 'charset' => 'utf-8')), + ) + ), + array( + 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8; foo=bar', + array( + 'text/html' => new AcceptHeaderItem('text/html'), + 'application/xhtml+xml' => new AcceptHeaderItem('application/xhtml+xml', array('q' => 0.9)), + '*/*' => new AcceptHeaderItem('*/*', array('q' => 0.8, 'foo' => 'bar')), + ) + ), + array( + 'text/html,application/xhtml+xml;charset=utf-8;q=0.9; foo=bar,*/*', + array( + 'text/html' => new AcceptHeaderItem('text/html'), + 'application/xhtml+xml' => new AcceptHeaderItem('application/xhtml+xml', array('q' => 0.9, 'charset' => 'utf-8', 'foo' => 'bar')), + '*/*' => new AcceptHeaderItem('*/*'), + ) + ), + array( + 'text/html,application/xhtml+xml', + array( + 'text/html' => new AcceptHeaderItem('text/html'), + 'application/xhtml+xml' => new AcceptHeaderItem('application/xhtml+xml'), + ) + ), ); } From 7f22b6f7ccdb7933883f050522e66b0c61b2bb9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Fri, 26 Oct 2012 10:48:11 +0200 Subject: [PATCH 05/12] [http-foundation] Fixed reference problem. --- src/Symfony/Component/HttpFoundation/AcceptHeader.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeader.php b/src/Symfony/Component/HttpFoundation/AcceptHeader.php index 52ab736d35af6..6b248442aa931 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeader.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeader.php @@ -180,14 +180,11 @@ private function merge(array $left, array $right) $array = array(); while (count($left) + count($right) > 0) { if (0 === count($left) || $shiftLeft = 0 === count($right)) { - list($key, $value) = $shiftLeft - ? each(array_splice($left, 0, 1)) - : each(array_splice($right, 0, 1)); + $item = $shiftLeft ? array_splice($left, 0, 1) : array_splice($right, 0, 1); } else { - list($key, $value) = current($right)->getQuality() > current($left)->getQuality() - ? each(array_splice($right, 0, 1)) - : each(array_splice($left, 0, 1)); + $item = current($right)->getQuality() > current($left)->getQuality() ? array_splice($right, 0, 1) : array_splice($left, 0, 1); } + list($key, $value) = each($item); $array[$key] = $value; } From aea1fa8165079a738b9904257dfe8768e6d53e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Fri, 26 Oct 2012 14:03:06 +0200 Subject: [PATCH 06/12] [http-foundation] Applied advices. --- .../Component/HttpFoundation/AcceptHeader.php | 16 ++++++++-------- .../HttpFoundation/AcceptHeaderItem.php | 8 +++----- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeader.php b/src/Symfony/Component/HttpFoundation/AcceptHeader.php index 6b248442aa931..2d7f58bf6d6de 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeader.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeader.php @@ -24,12 +24,12 @@ class AcceptHeader /** * @var AcceptHeaderItem[] */ - private $items; + private $items = array(); /** * @var bool */ - private $sorted; + private $sorted = true; /** * Builds an AcceptHeader instance from a string. @@ -52,8 +52,6 @@ public static function fromString($headerValue) */ public function __construct(array $items) { - $this->sorted = true; - $this->items = array(); foreach ($items as $item) { $this->add($item); } @@ -143,7 +141,7 @@ public function first() { $this->ensureSorted(); - return count($this->items) ? current($this->items) : null; + return !empty($this->items) ? current($this->items) : null; } /** @@ -179,8 +177,10 @@ private function merge(array $left, array $right) { $array = array(); while (count($left) + count($right) > 0) { - if (0 === count($left) || $shiftLeft = 0 === count($right)) { - $item = $shiftLeft ? array_splice($left, 0, 1) : array_splice($right, 0, 1); + if (empty($left)) { + $item = array_splice($right, 0, 1); + } elseif(empty($right)) { + $item = array_splice($left, 0, 1); } else { $item = current($right)->getQuality() > current($left)->getQuality() ? array_splice($right, 0, 1) : array_splice($left, 0, 1); } @@ -190,4 +190,4 @@ private function merge(array $left, array $right) return $array; } -} \ No newline at end of file +} diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php index abcef2887852b..2ab8b3f61b3e5 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php @@ -26,12 +26,12 @@ class AcceptHeaderItem /** * @var float */ - private $quality; + private $quality = 1.0; /** * @var array */ - private $attributes; + private $attributes = array(); /** * Builds an AcceptHeaderInstance instance from a string. @@ -71,8 +71,6 @@ public static function fromString($itemValue) public function __construct($value, array $attributes = array()) { $this->value = $value; - $this->quality = 1.0; - $this->attributes = array(); foreach ($attributes as $name => $value) { $this->setAttribute($name, $value); } @@ -196,4 +194,4 @@ public function setAttribute($name, $value) return $this; } -} \ No newline at end of file +} From a9d6ff07f5d352b06521cb61d53a9e660c1c1241 Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Sat, 27 Oct 2012 12:31:09 +0200 Subject: [PATCH 07/12] [HttpFoundation] Avoid slow merge sort by preserving the index of every AcceptHeaderItem --- .../Component/HttpFoundation/AcceptHeader.php | 53 ++++++------------- .../HttpFoundation/AcceptHeaderItem.php | 29 ++++++++++ .../HttpFoundation/Tests/AcceptHeaderTest.php | 11 +++- .../HttpFoundation/Tests/RequestTest.php | 7 ++- 4 files changed, 59 insertions(+), 41 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeader.php b/src/Symfony/Component/HttpFoundation/AcceptHeader.php index 2d7f58bf6d6de..465a62c86b0b6 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeader.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeader.php @@ -40,8 +40,13 @@ class AcceptHeader */ public static function fromString($headerValue) { - return new static(array_map(function ($itemValue) { - return AcceptHeaderItem::fromString($itemValue); + $index = 0; + + return new static(array_map(function ($itemValue) use (&$index) { + $item = AcceptHeaderItem::fromString($itemValue); + $item->setIndex($index++); + + return $item; }, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE))); } @@ -150,44 +155,16 @@ public function first() private function ensureSorted() { if (!$this->sorted) { - $this->items = $this->sort($this->items); - } - } - - /** - * @param array $array - * - * @return array - */ - private function sort(array $array) - { - if (count($array) < 2) { - return $array; - } + uasort($this->items, function ($a, $b) { + $qA = $a->getQuality(); + $qB = $b->getQuality(); - $middle = count($array) / 2; + if ($qA === $qB) { + return $a->getIndex() > $b->getIndex() ? 1 : -1; + } - return $this->merge( - $this->sort(array_slice($array, 0, $middle)), - $this->sort(array_slice($array, $middle)) - ); - } - - private function merge(array $left, array $right) - { - $array = array(); - while (count($left) + count($right) > 0) { - if (empty($left)) { - $item = array_splice($right, 0, 1); - } elseif(empty($right)) { - $item = array_splice($left, 0, 1); - } else { - $item = current($right)->getQuality() > current($left)->getQuality() ? array_splice($right, 0, 1) : array_splice($left, 0, 1); - } - list($key, $value) = each($item); - $array[$key] = $value; + return $qA > $qB ? -1 : 1; + }); } - - return $array; } } diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php index 2ab8b3f61b3e5..6827d10042ee8 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php @@ -28,6 +28,11 @@ class AcceptHeaderItem */ private $quality = 1.0; + /** + * @var int + */ + private $index = 0; + /** * @var array */ @@ -141,6 +146,30 @@ public function getQuality() return $this->quality; } + /** + * Set the item index. + * + * @param int $index + * + * @return AcceptHeaderItem + */ + public function setIndex($index) + { + $this->index = $index; + + return $this; + } + + /** + * Returns the item index. + * + * @return int + */ + public function getIndex() + { + return $this->index; + } + /** * Tests if an attribute exists. * diff --git a/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderTest.php b/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderTest.php index 15823eab9be87..dcb4b964cb6a5 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/AcceptHeaderTest.php @@ -22,7 +22,12 @@ class AcceptHeaderTest extends \PHPUnit_Framework_TestCase public function testFromString($string, array $items) { $header = AcceptHeader::fromString($string); - $this->assertEquals($items, array_values($header->all())); + $parsed = array_values($header->all()); + // reset index since the fixtures don't have them set + foreach ($parsed as $item) { + $item->setIndex(0); + } + $this->assertEquals($items, $parsed); } /** @@ -73,7 +78,9 @@ public function provideFilterData() public function provideSortingData() { return array( - array('*;q=0.3,ISO-8859-1,utf-8;q=0.7', array('ISO-8859-1', 'utf-8', '*')), + 'quality has priority' => array('*;q=0.3,ISO-8859-1,utf-8;q=0.7', array('ISO-8859-1', 'utf-8', '*')), + 'order matters when q is equal' => array('*;q=0.3,ISO-8859-1;q=0.7,utf-8;q=0.7', array('ISO-8859-1', 'utf-8', '*')), + 'order matters when q is equal2' => array('*;q=0.3,utf-8;q=0.7,ISO-8859-1;q=0.7', array('utf-8', 'ISO-8859-1', '*')), ); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 1fde4f15c1b2b..dd995eca530fd 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1018,7 +1018,12 @@ public function testSplitHttpAcceptHeader($acceptHeader, $expected) { $request = new Request(); - $this->assertEquals($expected, $request->splitHttpAcceptHeader($acceptHeader)); + $items = $request->splitHttpAcceptHeader($acceptHeader); + // reset index since the fixtures don't have them set + foreach ($items as $item) { + $item->setIndex(0); + } + $this->assertEquals($expected, $items); } public function splitHttpAcceptHeaderData() From 8bfff27db232f0cbbef86613a864d40fe3afec21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Mon, 29 Oct 2012 21:01:37 +0100 Subject: [PATCH 08/12] [HttpFoundation] Removed previously introduced BC break. --- .../Component/HttpFoundation/Request.php | 19 +++++-- .../HttpFoundation/Tests/RequestTest.php | 57 +++---------------- 2 files changed, 23 insertions(+), 53 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 91793844712cd..3a99c591de367 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1187,7 +1187,7 @@ public function getLanguages() return $this->languages; } - $languages = $this->splitHttpAcceptHeader($this->headers->get('Accept-Language')); + $languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all(); $this->languages = array(); foreach (array_keys($languages) as $lang) { if (strstr($lang, '-')) { @@ -1229,7 +1229,7 @@ public function getCharsets() return $this->charsets; } - return $this->charsets = array_keys($this->splitHttpAcceptHeader($this->headers->get('Accept-Charset'))); + return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all()); } /** @@ -1245,7 +1245,7 @@ public function getAcceptableContentTypes() return $this->acceptableContentTypes; } - return $this->acceptableContentTypes = array_keys($this->splitHttpAcceptHeader($this->headers->get('Accept'))); + return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all()); } /** @@ -1269,10 +1269,21 @@ public function isXmlHttpRequest() * @param string $header Header to split * * @return array Array indexed by the values of the Accept-* header in preferred order + * + * @deprecated */ public function splitHttpAcceptHeader($header) { - return AcceptHeader::fromString($header)->all(); + $headers = array(); + foreach (AcceptHeader::fromString($header)->all() as $item) { + $key = $item->getValue(); + foreach ($item->getAttributes() as $name => $value) { + $key.= sprintf(';%s=%s', $name, $value); + } + $headers[$key] = $item->getQuality(); + } + + return $headers; } /* diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index dd995eca530fd..69cd7ea1ec99e 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1018,61 +1018,20 @@ public function testSplitHttpAcceptHeader($acceptHeader, $expected) { $request = new Request(); - $items = $request->splitHttpAcceptHeader($acceptHeader); - // reset index since the fixtures don't have them set - foreach ($items as $item) { - $item->setIndex(0); - } - $this->assertEquals($expected, $items); + $this->assertEquals($expected, $request->splitHttpAcceptHeader($acceptHeader)); } public function splitHttpAcceptHeaderData() { return array( array(null, array()), - array( - 'text/html;q=0.8', - array('text/html' => new AcceptHeaderItem('text/html', array('q' => 0.8))) - ), - array( - 'text/html;foo=bar;q=0.8 ', - array('text/html' => new AcceptHeaderItem('text/html', array('q' => 0.8, 'foo' => 'bar'))) - ), - array( - 'text/html;charset=utf-8; q=0.8', - array('text/html' => new AcceptHeaderItem('text/html', array('q' => 0.8, 'charset' => 'utf-8'))) - ), - array( - 'text/html,application/xml;q=0.9,*/*;charset=utf-8; q=0.8', - array( - 'text/html' => new AcceptHeaderItem('text/html'), - 'application/xml' => new AcceptHeaderItem('application/xml', array('q' => 0.9)), - '*/*' => new AcceptHeaderItem('*/*', array('q' => 0.8, 'charset' => 'utf-8')), - ) - ), - array( - 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8; foo=bar', - array( - 'text/html' => new AcceptHeaderItem('text/html'), - 'application/xhtml+xml' => new AcceptHeaderItem('application/xhtml+xml', array('q' => 0.9)), - '*/*' => new AcceptHeaderItem('*/*', array('q' => 0.8, 'foo' => 'bar')), - ) - ), - array( - 'text/html,application/xhtml+xml;charset=utf-8;q=0.9; foo=bar,*/*', - array( - 'text/html' => new AcceptHeaderItem('text/html'), - 'application/xhtml+xml' => new AcceptHeaderItem('application/xhtml+xml', array('q' => 0.9, 'charset' => 'utf-8', 'foo' => 'bar')), - '*/*' => new AcceptHeaderItem('*/*'), - ) - ), - array( - 'text/html,application/xhtml+xml', - array( - 'text/html' => new AcceptHeaderItem('text/html'), - 'application/xhtml+xml' => new AcceptHeaderItem('application/xhtml+xml'), - ) - ), + array('text/html;q=0.8', array('text/html' => 0.8)), + array('text/html;foo=bar;q=0.8 ', array('text/html;foo=bar' => 0.8)), + array('text/html;charset=utf-8; q=0.8', array('text/html;charset=utf-8' => 0.8)), + array('text/html,application/xml;q=0.9,*/*;charset=utf-8; q=0.8', array('text/html' => 1.0, 'application/xml' => 0.9, '*/*;charset=utf-8' => 0.8)), + array('text/html,application/xhtml+xml;q=0.9,*/*;q=0.8; foo=bar', array('text/html' => 1.0, 'application/xhtml+xml' => 0.9, '*/*;foo=bar' => 0.8)), + array('text/html,application/xhtml+xml;charset=utf-8;q=0.9; foo=bar,*/*', array('text/html' => 1.0, '*/*' => 1.0, 'application/xhtml+xml;charset=utf-8;foo=bar' => 0.9)), + array('text/html,application/xhtml+xml', array('text/html' => 1.0, 'application/xhtml+xml' => 1.0)), ); } From 85e9e28de8b6fc5c3c2a2b611b68d640715e416f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Mon, 29 Oct 2012 21:41:39 +0100 Subject: [PATCH 09/12] Added changelog infos, upgrade file & removed unused code. --- UPGRADE-2.2.md | 22 +++++++++++++++++++ .../Component/HttpFoundation/CHANGELOG.md | 5 +++++ .../Component/HttpFoundation/Request.php | 2 +- .../HttpFoundation/Tests/RequestTest.php | 2 -- 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 UPGRADE-2.2.md diff --git a/UPGRADE-2.2.md b/UPGRADE-2.2.md new file mode 100644 index 0000000000000..d48a2cccb5b6e --- /dev/null +++ b/UPGRADE-2.2.md @@ -0,0 +1,22 @@ +UPGRADE FROM 2.1 to 2.2 +======================= + +#### Deprecations + + * The `Request::splitHttpAcceptHeader()` is deprecated and will be removed in 2.3. + + You should now use the `AcceptHeader` class which give you fluent methods to + parse request accept-* headers. Some examples: + + ``` + $accept = AcceptHeader::fromString($request->headers->get('Accept')); + if ($accept->has('text/html') { + $item = $accept->get('html'); + $charset = $item->getAttribute('charset', 'utf-8'); + $quality = $item->getQuality(); + } + + // accepts items are sorted by descending quality + $accepts = AcceptHeader::fromString($request->headers->get('Accept'))->all(); + + ``` diff --git a/src/Symfony/Component/HttpFoundation/CHANGELOG.md b/src/Symfony/Component/HttpFoundation/CHANGELOG.md index 4a00207e67004..8cb0db89673b1 100644 --- a/src/Symfony/Component/HttpFoundation/CHANGELOG.md +++ b/src/Symfony/Component/HttpFoundation/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +2.2.0 +----- + + * Request::splitHttpAcceptHeader() method is deprecated and will be removed in 2.3 + 2.1.0 ----- diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 3a99c591de367..57ad516e2ac97 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1270,7 +1270,7 @@ public function isXmlHttpRequest() * * @return array Array indexed by the values of the Accept-* header in preferred order * - * @deprecated + * @deprecated Deprecated since version 2.2, to be removed in 2.3. */ public function splitHttpAcceptHeader($header) { diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 69cd7ea1ec99e..56c127ae7440b 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -14,8 +14,6 @@ use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\AcceptHeader; -use Symfony\Component\HttpFoundation\AcceptHeaderItem; class RequestTest extends \PHPUnit_Framework_TestCase { From 1caf92d06478085628bc570840a7bd1033d2ef11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Tue, 30 Oct 2012 08:00:00 +0100 Subject: [PATCH 10/12] [HttpFoundation] Fixed CS. --- .../Component/HttpFoundation/AcceptHeader.php | 32 +++++++++---------- .../HttpFoundation/AcceptHeaderItem.php | 28 ++++++++-------- .../Component/HttpFoundation/Request.php | 2 +- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeader.php b/src/Symfony/Component/HttpFoundation/AcceptHeader.php index 465a62c86b0b6..a4c32142b3c96 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeader.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeader.php @@ -31,6 +31,18 @@ class AcceptHeader */ private $sorted = true; + /** + * Constructor. + * + * @param array $items + */ + public function __construct(array $items) + { + foreach ($items as $item) { + $this->add($item); + } + } + /** * Builds an AcceptHeader instance from a string. * @@ -50,18 +62,6 @@ public static function fromString($headerValue) }, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE))); } - /** - * Constructor. - * - * @param array $items - */ - public function __construct(array $items) - { - foreach ($items as $item) { - $this->add($item); - } - } - /** * Returns header value's string representation. * @@ -118,7 +118,7 @@ public function add(AcceptHeaderItem $item) */ public function all() { - $this->ensureSorted(); + $this->sort(); return $this->items; } @@ -144,15 +144,15 @@ public function filter($pattern) */ public function first() { - $this->ensureSorted(); + $this->sort(); return !empty($this->items) ? current($this->items) : null; } /** - * Ensures items are sorted by descending quality + * Sorts items by descending quality */ - private function ensureSorted() + private function sort() { if (!$this->sorted) { uasort($this->items, function ($a, $b) { diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php index 6827d10042ee8..ec1688fd19014 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php @@ -38,6 +38,20 @@ class AcceptHeaderItem */ private $attributes = array(); + /** + * Constructor. + * + * @param string $value + * @param array $attributes + */ + public function __construct($value, array $attributes = array()) + { + $this->value = $value; + foreach ($attributes as $name => $value) { + $this->setAttribute($name, $value); + } + } + /** * Builds an AcceptHeaderInstance instance from a string. * @@ -67,20 +81,6 @@ public static function fromString($itemValue) return new static(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ($start === '"' || $start === '\'') ? substr($value, 1, -1) : $value, $attributes); } - /** - * Constructor. - * - * @param string $value - * @param array $attributes - */ - public function __construct($value, array $attributes = array()) - { - $this->value = $value; - foreach ($attributes as $name => $value) { - $this->setAttribute($name, $value); - } - } - /** * Returns header value's string representation. * diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 57ad516e2ac97..73a00bf9fbf27 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1278,7 +1278,7 @@ public function splitHttpAcceptHeader($header) foreach (AcceptHeader::fromString($header)->all() as $item) { $key = $item->getValue(); foreach ($item->getAttributes() as $name => $value) { - $key.= sprintf(';%s=%s', $name, $value); + $key .= sprintf(';%s=%s', $name, $value); } $headers[$key] = $item->getQuality(); } From 1a33082cc813c58525057d8196b1e130eb4eeeea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Tue, 30 Oct 2012 17:14:34 +0100 Subject: [PATCH 11/12] [HttpFoundation] Fixed CS. --- src/Symfony/Component/HttpFoundation/AcceptHeader.php | 10 +++++----- .../Component/HttpFoundation/AcceptHeaderItem.php | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeader.php b/src/Symfony/Component/HttpFoundation/AcceptHeader.php index a4c32142b3c96..8deb414d4defc 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeader.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeader.php @@ -34,7 +34,7 @@ class AcceptHeader /** * Constructor. * - * @param array $items + * @param AcceptHeaderItem[] $items */ public function __construct(array $items) { @@ -54,7 +54,7 @@ public static function fromString($headerValue) { $index = 0; - return new static(array_map(function ($itemValue) use (&$index) { + return new self(array_map(function ($itemValue) use (&$index) { $item = AcceptHeaderItem::fromString($itemValue); $item->setIndex($index++); @@ -63,7 +63,7 @@ public static function fromString($headerValue) } /** - * Returns header value's string representation. + * Returns header value's string representation. * * @return string */ @@ -77,7 +77,7 @@ public function __toString() * * @param string $value * - * @return bool + * @return Boolean */ public function has($value) { @@ -132,7 +132,7 @@ public function all() */ public function filter($pattern) { - return new static(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) { + return new self(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) { return preg_match($pattern, $item->getValue()); })); } diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php index ec1688fd19014..9d4c3132d32e8 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeaderItem.php @@ -78,7 +78,7 @@ public static function fromString($itemValue) } } - return new static(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ($start === '"' || $start === '\'') ? substr($value, 1, -1) : $value, $attributes); + return new self(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ($start === '"' || $start === '\'') ? substr($value, 1, -1) : $value, $attributes); } /** @@ -175,7 +175,7 @@ public function getIndex() * * @param string $name * - * @return bool + * @return Boolean */ public function hasAttribute($name) { From 2e4a048e7723ef1e6c054cc51f206a05be623dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Fran=C3=A7ois=20Simon?= Date: Tue, 30 Oct 2012 17:48:20 +0100 Subject: [PATCH 12/12] [HttpFoudation] Fixed error. --- src/Symfony/Component/HttpFoundation/AcceptHeader.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/HttpFoundation/AcceptHeader.php b/src/Symfony/Component/HttpFoundation/AcceptHeader.php index 8deb414d4defc..e88f5b85438ad 100644 --- a/src/Symfony/Component/HttpFoundation/AcceptHeader.php +++ b/src/Symfony/Component/HttpFoundation/AcceptHeader.php @@ -165,6 +165,8 @@ private function sort() return $qA > $qB ? -1 : 1; }); + + $this->sorted = true; } } }