Passed
Push — master ( 40ca60...430c98 )
by Sebastian
02:56
created

prepareCalculations()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 12
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 24
rs 9.8666
1
<?php
2
/**
3
 * File containing the {@see Mailcode_Parser_Safeguard_Placeholder_Locator_Replacer} class.
4
 *
5
 * @package Mailcode
6
 * @subpackage Parser
7
 * @see Mailcode_Parser_Safeguard_Placeholder_Locator_Replacer
8
 */
9
10
declare(strict_types=1);
11
12
namespace Mailcode;
13
14
/**
15
 * Used to replace a placeholder at a specific location
16
 * with another text. The replacement handles inseting the
17
 * new text, while shifting the positions of all other 
18
 * instances of the placeholder to account for the change
19
 * in text length. 
20
 *
21
 * @package Mailcode
22
 * @subpackage Parser
23
 * @author Sebastian Mordziol <[email protected]>
24
 * 
25
 * @see Mailcode_Parser_Safeguard_Placeholder_Locator::replaceWith()
26
 */
27
class Mailcode_Parser_Safeguard_Placeholder_Locator_Replacer
28
{
29
    const ERROR_PLACEHOLDER_STRING_MISSING = 63501;
30
    const ERROR_COULD_NOT_FIND_PLACEHOLDER_TEXT = 63502;
31
    
32
   /**
33
    * @var string
34
    */
35
    private $replacementText;
36
    
37
   /**
38
    * @var Mailcode_Parser_Safeguard_Placeholder_Locator
39
    */
40
    private $locator;
0 ignored issues
show
introduced by
The private property $locator is not used, and could be removed.
Loading history...
41
    
42
   /**
43
    * @var Mailcode_Parser_Safeguard_Placeholder_Locator_Location
44
    */
45
    private $origin;
46
    
47
   /**
48
    * @var string
49
    */
50
    private $placeholderText;
51
    
52
   /**
53
    * @var integer
54
    */
55
    private $offset = 0;
0 ignored issues
show
introduced by
The private property $offset is not used, and could be removed.
Loading history...
56
    
57
   /**
58
    * @var string
59
    */
60
    private $subject;
61
    
62
   /**
63
    * @var integer
64
    */
65
    private $prefixLength = 0;
66
67
   /**
68
    * @var integer
69
    */
70
    private $placeholderLength = 0;
71
72
   /**
73
    * @var integer
74
    */
75
    private $lengthDifference = 0;
76
    
77
    public function __construct(Mailcode_Parser_Safeguard_Placeholder_Locator_Location $origin, string $replacementText, string $subject)
78
    {
79
        $this->replacementText = $replacementText;
80
        $this->origin = $origin;
81
        $this->placeholderText = $this->origin->getPlaceholder()->getReplacementText();
82
        $this->subject = $subject;
83
    }
84
    
85
    public function replace() : string
86
    {
87
        $this->prepareCalculations();
88
        $this->replaceLocation();
89
        $this->adjustPositions();
90
        
91
        return $this->subject;
92
    }
93
    
94
   /**
95
    * Adjusts the positions of all locations that come after 
96
    * this one, to account for the added string length of the
97
    * placeholder that has been replaced.
98
    */
99
    private function adjustPositions() : void
100
    {
101
        $locations = $this->origin->getNextAll();
102
        $offset = $this->lengthDifference;
103
        
104
        foreach($locations as $location)
105
        {
106
            $location->updatePositionByOffset($offset);
107
            
108
            $offset += $this->lengthDifference;
109
        }
110
    }
111
    
112
    private function prepareCalculations() : void
113
    {
114
        $length = mb_strpos($this->replacementText, $this->placeholderText);
115
        
116
        if($length === false)
117
        {
118
            throw new Mailcode_Exception(
119
                'Replacement text does not contain placeholder string.',
120
                sprintf(
121
                    'The placeholder string [%s] is not present in the replacement text: %s',
122
                    $this->placeholderText,
123
                    $this->replacementText
124
                ),
125
                self::ERROR_PLACEHOLDER_STRING_MISSING
126
            );
127
        }
128
        
129
        // Find the beginning position of the placeholder in the replacement text
130
        $this->prefixLength = $length;
131
        
132
        $this->placeholderLength = mb_strlen($this->placeholderText);
133
        
134
        // The total length that was added to the placeholder, front and back 
135
        $this->lengthDifference = mb_strlen($this->replacementText) - $this->placeholderLength;
136
    }
137
    
138
    private function replaceLocation() : void
139
    {
140
        // Get the starting position, with cumulated total offset
141
        $position = $this->origin->getStartPosition();
142
        
143
        // Cut the subject string so we can insert the adjusted placeholder
144
        $start = mb_substr($this->subject, 0, $position);
145
        $end = mb_substr($this->subject, $position + $this->placeholderLength);
146
        
147
        // Rebuild the subject string from the parts
148
        $this->subject = $start.$this->replacementText.$end;
149
        
150
        // Add the prefix length as offset to the location, now that 
151
        // we have added it. This way the position of the placeholder 
152
        // itself stays correct.
153
        $this->origin->updatePositionByOffset($this->prefixLength);
154
    }
155
}
156