Completed
Push — master ( 2972d6...a3a7c9 )
by Richard
01:57
created

Repeat::createHook()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 7
rs 9.4285
cc 2
eloc 5
nc 2
nop 3
1
<?php
2
/* @description     Transformation Style Sheets - Revolutionising PHP templating    *
3
 * @author          Tom Butler [email protected]                                             *
4
 * @copyright       2015 Tom Butler <[email protected]> | https://r.je/                      *
5
 * @license         http://www.opensource.org/licenses/bsd-license.php  BSD License *
6
 * @version         1.0                                                             */
7
namespace Transphporm\Property;
8
class Repeat implements \Transphporm\Property {
9
	private $functionSet;
10
	private $elementData;
11
	private $line;
12
13
	public function __construct(\Transphporm\FunctionSet $functionSet, \Transphporm\Hook\ElementData $elementData, &$line) {
14
		$this->functionSet = $functionSet;
15
		$this->elementData = $elementData;
16
		$this->line = &$line;
17
	}
18
19
	public function run(array $values, \DomElement $element, array $rules, \Transphporm\Hook\PseudoMatcher $pseudoMatcher, array $properties = []) {
20
		$values = $this->fixEmpty($values);
21
		if ($element->getAttribute('transphporm') === 'added') return $element->parentNode->removeChild($element);
22
		$max = $this->getMax($values);
23
		$count = 0;
24
25
		$repeat = $this->getRepeatValue($values, $max);
26
27
		//Don't run repeat on the clones element or it will loop forever
28
		unset($rules['repeat']);
29
		$hook = $this->createHook($rules, $pseudoMatcher, $properties);
30
31
		foreach ($repeat as $key => $iteration) {
32
			if ($count+1 > $max) break;
33
			$clone = $this->cloneElement($element, $iteration, $key, $count++);
34
			//Re-run the hook on the new element, but use the iterated data
35
			$hook->run($clone);
36
		}
37
		//Remove the original element
38
		$element->parentNode->removeChild($element);
39
		return false;
40
	}
41
42
	private function getRepeatValue($values, &$max) {
43
		$mode = $this->getMode($values);
44
		if ($mode === 'each') $repeat = $values[0];
45
		else if ($mode === 'loop') {
46
			$repeat = range($values[0], $max);
47
			$max++;
48
		}
49
		return $repeat;
0 ignored issues
show
Bug introduced by
The variable $repeat does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
50
	}
51
52
	private function getMode($args) {
53
		return isset($args[2]) ? $args[2] : 'each';
54
	}
55
56
	private function fixEmpty($value) {
57
		if (empty($value[0])) $value[0] = [];
58
		return $value;
59
	}
60
61
	private function cloneElement($element, $iteration, $key, $count) {
62
		$clone = $element->cloneNode(true);
63
		$this->tagElement($clone, $count);
64
65
		$this->elementData->bind($clone, $iteration, 'iteration');
66
		$this->elementData->bind($clone, $key, 'key');
67
		$element->parentNode->insertBefore($clone, $element);
68
		return $clone;
69
	}
70
71
	private function tagElement($element, $count) {
72
		//Mark all but one of the nodes as having been added by transphporm, when the hook is run again, these are removed
73
		if ($count > 0) $element->setAttribute('transphporm', 'added');
74
	}
75
76
	private function getMax($values) {
77
		return isset($values[1]) ? $values[1] : PHP_INT_MAX;
78
	}
79
80
	private function createHook($newRules, $pseudoMatcher, $properties) {
81
		$var = ""; // PropertyHook requires that baseDir be passed by refrence
82
		// and there is no reason to pass it so create $var to avoid errors
83
		$hook = new \Transphporm\Hook\PropertyHook($newRules, $var, $this->line, "", $this->line, $pseudoMatcher, new \Transphporm\Parser\Value($this->functionSet), $this->functionSet);
84
		foreach ($properties as $name => $property) $hook->registerProperty($name, $property);
85
		return $hook;
86
	}
87
}
88