* 1.x:
fixed batch filter clobbers array keys when fill parameter is used
added preserveKeys support for the batch filter
removed dead code
fixed "embed" support when used from "template_from_string"
fixed CS
... | ... |
@@ -163,6 +163,9 @@ |
163 | 163 |
|
164 | 164 |
* 1.38.0 (2019-XX-XX) |
165 | 165 |
|
166 |
+ * fixed batch filter clobbers array keys when fill parameter is used |
|
167 |
+ * added preserveKeys support for the batch filter |
|
168 |
+ * fixed "embed" support when used from "template_from_string" |
|
166 | 169 |
* added the possibility to pass a TemplateWrapper to Twig\Environment::load() |
167 | 170 |
* improved the performance of the sandbox |
168 | 171 |
* added a spaceless filter |
... | ... |
@@ -299,7 +299,7 @@ class Environment |
299 | 299 |
{ |
300 | 300 |
$key = $this->getLoader()->getCacheKey($name).$this->optionsHash; |
301 | 301 |
|
302 |
- return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '_'.$index); |
|
302 |
+ return $this->templateClassPrefix.hash('sha256', $key).(null === $index ? '' : '___'.$index); |
|
303 | 303 |
} |
304 | 304 |
|
305 | 305 |
/** |
... | ... |
@@ -379,9 +379,17 @@ class Environment |
379 | 379 |
*/ |
380 | 380 |
public function loadTemplate($name, $index = null) |
381 | 381 |
{ |
382 |
- $cls = $mainCls = $this->getTemplateClass($name); |
|
382 |
+ return $this->loadClass($this->getTemplateClass($name), $name, $index); |
|
383 |
+ } |
|
384 |
+ |
|
385 |
+ /** |
|
386 |
+ * @internal |
|
387 |
+ */ |
|
388 |
+ public function loadClass($cls, $name, $index = null) |
|
389 |
+ { |
|
390 |
+ $mainCls = $cls; |
|
383 | 391 |
if (null !== $index) { |
384 |
- $cls .= '_'.$index; |
|
392 |
+ $cls .= '___'.$index; |
|
385 | 393 |
} |
386 | 394 |
|
387 | 395 |
if (isset($this->loadedTemplates[$cls])) { |
... | ... |
@@ -411,7 +419,7 @@ class Environment |
411 | 419 |
} |
412 | 420 |
|
413 | 421 |
if (!class_exists($cls, false)) { |
414 |
- throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache is corrupted.', $name, $index), -1, $source); |
|
422 |
+ throw new RuntimeError(sprintf('Failed to load Twig template "%s", index "%s": cache might be corrupted.', $name, $index), -1, $source); |
|
415 | 423 |
} |
416 | 424 |
} |
417 | 425 |
} |
... | ... |
@@ -1469,23 +1469,22 @@ function twig_constant_is_defined($constant, $object = null) |
1469 | 1469 |
* |
1470 | 1470 |
* @return array |
1471 | 1471 |
*/ |
1472 |
-function twig_array_batch($items, $size, $fill = null) |
|
1472 |
+function twig_array_batch($items, $size, $fill = null, $preserveKeys = true) |
|
1473 | 1473 |
{ |
1474 | 1474 |
if ($items instanceof \Traversable) { |
1475 |
- $items = iterator_to_array($items, false); |
|
1475 |
+ $items = iterator_to_array($items, $preserveKeys); |
|
1476 | 1476 |
} |
1477 | 1477 |
|
1478 | 1478 |
$size = ceil($size); |
1479 | 1479 |
|
1480 |
- $result = array_chunk($items, $size, true); |
|
1480 |
+ $result = array_chunk($items, $size, $preserveKeys); |
|
1481 | 1481 |
|
1482 |
- if (null !== $fill && !empty($result)) { |
|
1482 |
+ if (null !== $fill && $result) { |
|
1483 | 1483 |
$last = \count($result) - 1; |
1484 | 1484 |
if ($fillCount = $size - \count($result[$last])) { |
1485 |
- $result[$last] = array_merge( |
|
1486 |
- $result[$last], |
|
1487 |
- array_fill(0, $fillCount, $fill) |
|
1488 |
- ); |
|
1485 |
+ for ($i = 0; $i < $fillCount; $i++) { |
|
1486 |
+ $result[$last][] = $fill; |
|
1487 |
+ } |
|
1489 | 1488 |
} |
1490 | 1489 |
} |
1491 | 1490 |
|
... | ... |
@@ -39,10 +39,6 @@ final class NodeTraverser |
39 | 39 |
|
40 | 40 |
public function addVisitor(NodeVisitorInterface $visitor) |
41 | 41 |
{ |
42 |
- if (!isset($this->visitors[$visitor->getPriority()])) { |
|
43 |
- $this->visitors[$visitor->getPriority()] = []; |
|
44 |
- } |
|
45 |
- |
|
46 | 42 |
$this->visitors[$visitor->getPriority()][] = $visitor; |
47 | 43 |
} |
48 | 44 |
|
... | ... |
@@ -309,6 +309,15 @@ abstract class Template |
309 | 309 |
return $template; |
310 | 310 |
} |
311 | 311 |
|
312 |
+ if ($template === $this->getTemplateName()) { |
|
313 |
+ $class = get_class($this); |
|
314 |
+ if (false !== $pos = strrpos($class, '___', -1)) { |
|
315 |
+ $class = substr($class, 0, $pos); |
|
316 |
+ } |
|
317 |
+ |
|
318 |
+ return $this->env->loadClass($class, $template, $index); |
|
319 |
+ } |
|
320 |
+ |
|
312 | 321 |
return $this->env->loadTemplate($template, $index); |
313 | 322 |
} catch (Error $e) { |
314 | 323 |
if (!$e->getSourceContext()) { |
... | ... |
@@ -364,7 +364,7 @@ class Twig_Tests_EnvironmentTest extends \PHPUnit\Framework\TestCase |
364 | 364 |
|
365 | 365 |
/** |
366 | 366 |
* @expectedException \Twig\Error\RuntimeError |
367 |
- * @expectedExceptionMessage Failed to load Twig template "testFailLoadTemplate.twig", index "abc": cache is corrupted in "testFailLoadTemplate.twig". |
|
367 |
+ * @expectedExceptionMessage Failed to load Twig template "testFailLoadTemplate.twig", index "abc": cache might be corrupted in "testFailLoadTemplate.twig". |
|
368 | 368 |
*/ |
369 | 369 |
public function testFailLoadTemplate() |
370 | 370 |
{ |
... | ... |
@@ -1,8 +1,8 @@ |
1 | 1 |
--TEST-- |
2 | 2 |
"batch" filter preserves array keys |
3 | 3 |
--TEMPLATE-- |
4 |
-{{ {'foo': 'bar', 'key': 'value'}|batch(4)|first|keys|join(',') }} |
|
5 |
-{{ {'foo': 'bar', 'key': 'value'}|batch(4, 'fill')|first|keys|join(',') }} |
|
4 |
+{{ {'foo': 'bar', 'key': 'value'}|batch(4)|first|keys|join(',') }} |
|
5 |
+{{ {'foo': 'bar', 'key': 'value'}|batch(4, 'fill')|first|keys|join(',') }} |
|
6 | 6 |
--DATA-- |
7 | 7 |
return [] |
8 | 8 |
--EXPECT-- |
9 | 9 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,23 @@ |
1 |
+--TEST-- |
|
2 |
+"batch" filter |
|
3 |
+--TEMPLATE-- |
|
4 |
+{% for row in items|batch(3, 'fill') %} |
|
5 |
+ <div class=row> |
|
6 |
+ {% for key, column in row %} |
|
7 |
+ <div class={{ key }}>{{ column }}</div> |
|
8 |
+ {% endfor %} |
|
9 |
+ </div> |
|
10 |
+{% endfor %} |
|
11 |
+--DATA-- |
|
12 |
+return ['items' => ['a' => 'a', 'b' => 'b', 'c' => 'c', 'd' => 'd', '123' => 'e']] |
|
13 |
+--EXPECT-- |
|
14 |
+<div class=row> |
|
15 |
+ <div class=a>a</div> |
|
16 |
+ <div class=b>b</div> |
|
17 |
+ <div class=c>c</div> |
|
18 |
+ </div> |
|
19 |
+ <div class=row> |
|
20 |
+ <div class=d>d</div> |
|
21 |
+ <div class=123>e</div> |
|
22 |
+ <div class=124>fill</div> |
|
23 |
+ </div> |
0 | 24 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,11 @@ |
1 |
+--TEST-- |
|
2 |
+"template_from_string" function works in an "include" |
|
3 |
+--TEMPLATE-- |
|
4 |
+{% set embed = '{% embed "embed.twig" %}{% endembed %}' %} |
|
5 |
+{{ include(template_from_string(embed)) }} |
|
6 |
+--TEMPLATE(embed.twig)-- |
|
7 |
+Cool |
|
8 |
+--DATA-- |
|
9 |
+return [] |
|
10 |
+--EXPECT-- |
|
11 |
+Cool |