IdiormString   A
last analyzed

Complexity

Total Complexity 8

Size/Duplication

Total Lines 132
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 95.24%

Importance

Changes 0
Metric Value
wmc 8
lcom 1
cbo 1
dl 0
loc 132
c 0
b 0
f 0
ccs 20
cts 21
cp 0.9524
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A value() 0 4 1
A str_replace_outside_quotes() 0 4 1
A __construct() 0 4 1
A replace_outside_quotes() 0 7 1
A _str_replace_outside_quotes() 0 26 2
A _str_replace_outside_quotes_cb() 0 10 2
1
<?php
2
3
namespace idiorm\orm;
4
5
/**
6
 * A class to handle str_replace operations that involve quoted strings
7
 *
8
 * @example IdiormString::str_replace_outside_quotes('?', '%s', 'columnA = "Hello?" AND columnB = ?');
9
 * @example IdiormString::value('columnA = "Hello?" AND columnB = ?')->replace_outside_quotes('?', '%s');
10
 * @author  Jeff Roberson <[email protected]>
11
 * @author  Simon Holywell <[email protected]>
12
 * @link    http://stackoverflow.com/a/13370709/461813 StackOverflow answer
13
 */
14
class IdiormString
15
{
16
  /**
17
   * @var string
18
   */
19
  protected $subject;
20
21
  /**
22
   * @var string
23
   */
24
  protected $search;
25
26
  /**
27
   * @var string
28
   */
29
  protected $replace;
30
31
  /**
32
   * Get an easy to use instance of the class
33
   *
34
   * @param string $subject
35
   *
36
   * @return \static
37
   */
38 4
  public static function value($subject)
39
  {
40 4
    return new static($subject);
41
  }
42
43
  /**
44
   * Shortcut method: Replace all occurrences of the search string with the replacement
45
   * string where they appear outside quotes.
46
   *
47
   * @param string $search
48
   * @param string $replace
49
   * @param string $subject
50
   *
51
   * @return string
52
   */
53 4
  public static function str_replace_outside_quotes($search, $replace, $subject)
54
  {
55 4
    return static::value($subject)->replace_outside_quotes($search, $replace);
56
  }
57
58
  /**
59
   * Set the base string object
60
   *
61
   * @param string $subject
62
   */
63 4
  public function __construct($subject)
64
  {
65 4
    $this->subject = (string)$subject;
66 4
  }
67
68
  /**
69
   * Replace all occurrences of the search string with the replacement
70
   * string where they appear outside quotes
71
   *
72
   * @param string $search
73
   * @param string $replace
74
   *
75
   * @return string
76
   */
77 4
  public function replace_outside_quotes($search, $replace)
78
  {
79 4
    $this->search = $search;
80 4
    $this->replace = $replace;
81
82 4
    return $this->_str_replace_outside_quotes();
83
  }
84
85
  /**
86
   * Validate an input string and perform a replace on all occurrences
87
   * of $this->search with $this->replace
88
   *
89
   * @author Jeff Roberson <[email protected]>
90
   * @link   http://stackoverflow.com/a/13370709/461813 StackOverflow answer
91
   *
92
   * @return string
93
   *
94
   * @throws IdiormStringException
95
   */
96 4
  protected function _str_replace_outside_quotes()
97
  {
98
    $re_valid = '/
99
                # Validate string having embedded quoted substrings.
100
                ^                           # Anchor to start of string.
101
                (?:                         # Zero or more string chunks.
102
                  "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"  # Either a double quoted chunk,
103
                | \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'  # or a single quoted chunk,
104
                | [^\'"\\\\]+               # or an unquoted chunk (no escapes).
105
                )*                          # Zero or more string chunks.
106
                \z                          # Anchor to end of string.
107 4
                /sx';
108 4
    if (!preg_match($re_valid, $this->subject)) {
109
      throw new IdiormStringException('Subject string is not valid in the replace_outside_quotes context.');
110
    }
111
    $re_parse = '/
112
                # Match one chunk of a valid string having embedded quoted substrings.
113
                  (                         # Either $1: Quoted chunk.
114
                    "[^"\\\\]*(?:\\\\.[^"\\\\]*)*"  # Either a double quoted chunk,
115
                  | \'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'  # or a single quoted chunk.
116
                  )                         # End $1: Quoted chunk.
117
                | ([^\'"\\\\]+)             # or $2: an unquoted chunk (no escapes).
118 4
                /sx';
119
120 4
    return (string)preg_replace_callback($re_parse, array($this, '_str_replace_outside_quotes_cb'), $this->subject);
121
  }
122
123
  /**
124
   * Process each matching chunk from preg_replace_callback replacing
125
   * each occurrence of $this->search with $this->replace
126
   *
127
   * @author Jeff Roberson <[email protected]>
128
   * @link   http://stackoverflow.com/a/13370709/461813 StackOverflow answer
129
   *
130
   * @param array $matches
131
   *
132
   * @return string
133
   */
134 4
  protected function _str_replace_outside_quotes_cb($matches)
135
  {
136
    // Return quoted string chunks (in group $1) unaltered.
137 4
    if ($matches[1]) {
138 4
      return $matches[1];
139
    }
140
141
    // Process only unquoted chunks (in group $2).
142 4
    return (string)preg_replace('/' . preg_quote($this->search, '/') . '/', $this->replace, $matches[2]);
143
  }
144
145
}
146