Browse Source

added HtmlHelper::startTag();
ArrayHelper::map() & ::mapIfSet(): pass key to callback if callback accepts 2 params

Fabian Peter Hammerle 7 years ago
parent
commit
3448b8e423
6 changed files with 171 additions and 60 deletions
  1. 33 20
      ArrayHelper.php
  2. 25 0
      HtmlHelper.php
  3. 11 4
      StringHelper.php
  4. 37 2
      tests/ArrayHelperTest.php
  5. 48 0
      tests/HtmlHelperTest.php
  6. 17 34
      tests/StringHelperTest.php

+ 33 - 20
ArrayHelper.php

@@ -20,14 +20,24 @@ class ArrayHelper
      * @param \Closure $callback
      * @return mixed
      */
-   public static function map($source, \Closure $callback)
-   {
-       if(is_array($source)) {
-           return array_map($callback, $source);
-       } else {
-           return $callback($source);
-       }
-   }
+    public static function map($source, \Closure $callback)
+    {
+        $callback_reflection = new \ReflectionFunction($callback);
+        if($callback_reflection->getNumberOfRequiredParameters() == 1) {
+            $mapper = function($k, $v) use ($callback) {
+                return $callback($v);
+                };
+        } else {
+            $mapper = $callback;
+        }
+        if(is_array($source)) {
+            return self::multimap($source, function($k, $v) use ($mapper) {
+                return [$k => $mapper($k, $v)];
+                });
+        } else {
+            return $mapper(null, $source);
+        }
+    }
 
     /**
      * @param mixed $source_array
@@ -38,17 +48,20 @@ class ArrayHelper
     {
         if($source === null) {
             return null;
-        } elseif(is_array($source)) {
-            return array_map(
-                function($v) use ($callback) {
-                    return $v === null ? null : $callback($v);
-                    },
-                $source
-                );
-       } else {
-           return $callback($source);
-       }
-   }
+        } else {
+            $callback_reflection = new \ReflectionFunction($callback);
+            if($callback_reflection->getNumberOfRequiredParameters() == 1) {
+                $mapper = function($k, $v) use ($callback) {
+                    return is_null($v) ? null : $callback($v);
+                    };
+            } else {
+                $mapper = function($k, $v) use ($callback) {
+                    return is_null($v) ? null : $callback($k, $v);
+                    };
+            }
+            return self::map($source, $mapper);
+        }
+    }
 
     /**
      * @param array $source_array
@@ -61,7 +74,7 @@ class ArrayHelper
        foreach($source_array as $old_key => $old_value) {
            $pairs = $callback($old_key, $old_value);
            if($pairs === null) {
-               // skipp
+               // skip
            } elseif(is_array($pairs)) {
                foreach($pairs as $new_key => $new_pair) {
                    $mapped_array[$new_key] = $new_pair;

+ 25 - 0
HtmlHelper.php

@@ -9,6 +9,31 @@ class HtmlHelper
         return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE);
     }
 
+    public static function startTag($tag_name, array $attributes = [])
+    {
+        if($tag_name === null) {
+            return null;
+        } elseif(!is_string($tag_name)) {
+            throw new \TypeError(
+                sprintf('expected string or null as tag name, %s given', gettype($tag_name))
+                );
+        } else {
+            $rendered_attributes = StringHelper::implode(' ', ArrayHelper::mapIfSet(
+                $attributes,
+                function($k, $v) {
+                    if($v === true) {
+                        return sprintf('%s="%s"', $k, $k); 
+                    } elseif($v === false) {
+                        return null; 
+                    } else {
+                        return sprintf('%s="%s"', $k, self::encode($v));
+                    }
+                    }
+                ));
+            return '<' . $tag_name . StringHelper::prepend(' ', $rendered_attributes) . '>';
+        }
+    }
+
     public static function endTag($name)
     {
         if($name === null) {

+ 11 - 4
StringHelper.php

@@ -55,13 +55,20 @@ class StringHelper
     /**
      * @return string|null
      */
-    public static function implode($glue, array $pieces)
+    public static function implode($glue, array $pieces = null)
     {
-        $pieces = array_filter($pieces);
-        if(sizeof($pieces) == 0) {
+        if($pieces === null) {
             return null;
         } else {
-            return implode($glue, $pieces);
+            $pieces = array_filter(
+                $pieces,
+                function($piece) { return $piece !== null; }
+                );
+            if(sizeof($pieces) == 0) {
+                return null;
+            } else {
+                return implode($glue, $pieces);
+            }
         }
     }
 

+ 37 - 2
tests/ArrayHelperTest.php

@@ -110,6 +110,11 @@ class ArrayHelperTest extends \PHPUnit_Framework_TestCase
                 function($v) { return null; },
                 null,
                 ],
+            [
+                'string',
+                function($k, $v) { return [$v => $k]; },
+                ['string' => null],
+                ],
             [
                 ['a' => 1, 'b' => 2, 'c' => 3],
                 function($v) { return $v; },
@@ -126,9 +131,24 @@ class ArrayHelperTest extends \PHPUnit_Framework_TestCase
                 ['a' => 1, 'b' => null, 'c' => 3],
                 ],
             [
-                ['a' => 1, 'b' => 2, 'b' => 3],
+                ['a' => 1, 'b' => 2, 'c' => 3],
                 function($v) { return $v * $v; },
-                ['a' => 1, 'b' => 4, 'b' => 9],
+                ['a' => 1, 'b' => 4, 'c' => 9],
+                ],
+            [
+                ['a' => 1, 'b' => 2, 'c' => 3],
+                function($k, $v) { return $k . $v; },
+                ['a' => 'a1', 'b' => 'b2', 'c' => 'c3'],
+                ],
+            [
+                ['a' => 1, 'b' => 2, 'c' => 3],
+                function($k, $v) { return [strtoupper($k) => $v]; },
+                ['a' => ['A' => 1], 'b' => ['B' => 2], 'c' => ['C' => 3]],
+                ],
+            [
+                ['a' => 1, 'b' => 2, 'c' => null],
+                function($k, $v) { return $k . (is_null($v) ? ' null' : ' not null'); },
+                ['a' => 'a not null', 'b' => 'b not null', 'c' => 'c null'],
                 ],
             ];
     }
@@ -179,6 +199,21 @@ class ArrayHelperTest extends \PHPUnit_Framework_TestCase
                 function($v) { return $v * $v; },
                 ['a' => 1, 'b' => 4, 'b' => 9],
                 ],
+            [
+                ['a' => 1, 'b' => 2, 'c' => 3],
+                function($k, $v) { return $k . $v; },
+                ['a' => 'a1', 'b' => 'b2', 'c' => 'c3'],
+                ],
+            [
+                ['a' => 1, 'b' => 2, 'c' => 3],
+                function($k, $v) { return [strtoupper($k) => $v]; },
+                ['a' => ['A' => 1], 'b' => ['B' => 2], 'c' => ['C' => 3]],
+                ],
+            [
+                ['a' => 1, 'b' => 2, 'c' => null],
+                function($k, $v) { return $k . (is_null($v) ? ' null' : ' not null'); },
+                ['a' => 'a not null', 'b' => 'b not null', 'c' => null],
+                ],
             ];
     }
 

+ 48 - 0
tests/HtmlHelperTest.php

@@ -26,6 +26,54 @@ class HtmlHelperTest extends \PHPUnit_Framework_TestCase
         $this->assertSame($expected, HtmlHelper::encode($string));
     }
 
+    public function startTagTypeErrorProvider()
+    {
+        return [
+            [1, []],
+            [false, []],
+            ['tag', true],
+            ['tag', 'attr'],
+            ];
+    }
+
+    /**
+     * @dataProvider startTagTypeErrorProvider
+     * @expectedException \TypeError
+     */
+    public function testStartTagTypeError($name, $attributes)
+    {
+        HtmlHelper::startTag($name, $attributes);
+    }
+
+    public function startTagProvider()
+    {
+        return [
+            ['tag', [], '<tag>'],
+            ['start', ['a' => '1'], '<start a="1">'],
+            ['start', ['a' => 1], '<start a="1">'],
+            ['start', ['a' => '1', 'b' => '2'], '<start a="1" b="2">'],
+            ['start', ['b' => '1', 'a' => '2'], '<start b="1" a="2">'],
+            ['start', ['a' => null, 'b' => '2'], '<start b="2">'],
+            ['start', ['a' => true], '<start a="a">'],
+            ['start', ['a' => true, 'b' => '2'], '<start a="a" b="2">'],
+            ['start', ['a' => false], '<start>'],
+            ['start', ['a' => false, 'b' => '2'], '<start b="2">'],
+            ['script', ['type' => 'text/javascript'], '<script type="text/javascript">'],
+            ['span', ['onclick' => 'alert(":-)")'], '<span onclick="alert(&quot;:-)&quot;)">'],
+            ['span', ['onclick' => "alert(':-)')"], '<span onclick="alert(&#039;:-)&#039;)">'],
+            [null, [], null],
+            [null, ['attr' => 'v'], null],
+            ];
+    }
+
+    /**
+     * @dataProvider startTagProvider
+     */
+    public function testStartTag($name, $attributes, $expected_tag)
+    {
+        $this->assertSame($expected_tag, HtmlHelper::startTag($name, $attributes));
+    }
+
     public function endTagTypeErrorProvider()
     {
         return [

+ 17 - 34
tests/StringHelperTest.php

@@ -230,44 +230,27 @@ class StringHelperTest extends \PHPUnit_Framework_TestCase
             );
     }
 
-    public function testImplode()
+    public function implodeProvider()
     {
-        $this->assertEquals(
-            'a,b,c,d',
-            StringHelper::implode(',', ['a', 'b', 'c', 'd'])
-            );
-    }
-
-    public function testImplodeWithNull()
-    {
-        $this->assertEquals(
-            'a,b,d',
-            StringHelper::implode(',', ['a', 'b', null, 'd'])
-            );
-    }
-
-    public function testImplodeEmpty()
-    {
-        $this->assertEquals(
-            'acd',
-            StringHelper::implode('', ['a', '', 'c', 'd'])
-            );
-    }
-
-    public function testImplodeByEmpty()
-    {
-        $this->assertEquals(
-            'abcd',
-            StringHelper::implode('', ['a', 'b', 'c', 'd'])
-            );
+        return [
+            [',', ['a', 'b', null, 'd'], 'a,b,d'],
+            [',', ['a', 'b', '', 'd'], 'a,b,,d'],
+            [',', ['a', 'b', 'c', 'd'], 'a,b,c,d'],
+            [',', [null, null, null], null],
+            [',', null, null],
+            ['', ['a', '', 'c', 'd'], 'acd'],
+            ['', ['a', 3, 'c', 'd'], 'a3cd'],
+            ['', ['a', 'b', 'c', 'd'], 'abcd'],
+            [null, ['a', 'b', 'c', 'd'], 'abcd'],
+            ];
     }
 
-    public function testImplodeNothing()
+    /**
+     * @dataProvider implodeProvider
+     */
+    public function testImplode($glue, $pieces, $expected)
     {
-        $this->assertEquals(
-            null,
-            StringHelper::implode(',', [null, null, null])
-            );
+        $this->assertSame($expected, StringHelper::implode($glue, $pieces));
     }
 
     public function containsAnyProvider()