Parameter::replacePlaceholders()   A
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 17
rs 9.2
c 0
b 0
f 0
cc 4
eloc 13
nc 3
nop 3
1
<?php
2
/**
3
 * Phossa Project
4
 *
5
 * PHP version 5.4
6
 *
7
 * @category  Library
8
 * @package   Phossa2\Query
9
 * @copyright Copyright (c) 2016 phossa.com
10
 * @license   http://mit-license.org/ MIT License
11
 * @link      http://www.phossa.com/
12
 */
13
/*# declare(strict_types=1); */
14
15
namespace Phossa2\Query\Misc;
16
17
/**
18
 * Parameter
19
 *
20
 * Dealing with positioned or named parameters
21
 *
22
 * @package Phossa2\Query
23
 * @author  Hong Zhang <[email protected]>
24
 * @version 2.0.0
25
 * @since   2.0.0 added
26
 */
27
class Parameter
28
{
29
    /**
30
     * parameter pool
31
     *
32
     * @var    array
33
     * @access protected
34
     */
35
    protected $parameters;
36
37
    /**
38
     * The escape callable
39
     *
40
     * @var    callable
41
     * @access protected
42
     */
43
    protected $escape;
44
45
    /**
46
     * Returns a replacement placeholder for a $value
47
     *
48
     * @param  mixed $value
49
     * @return string
50
     * @access public
51
     */
52
    public function getPlaceholder($value)/*# : string */
53
    {
54
        // unique key with a pattern
55
        $key = uniqid('__PHQUERY_') . '__';
56
        $this->parameters[$key] = $value;
57
        return $key;
58
    }
59
60
    /**
61
     * Replace placeholders in the SQL with '?' or real value
62
     *
63
     * @param  string $sql
64
     * @param  array &$bindings
65
     * @param  array $settings
66
     * @return string
67
     * @access public
68
     */
69
    public function bindValues(
70
        /*# string */ $sql,
71
        array &$bindings,
72
        array $settings
73
    )/*# : string */ {
74
        // make sure escape function ok
75
        $this->setEscapeCallable($settings['escapeFunction']);
76
77
        // replace each placeholder with corresponding ?/:name/value
78
        return preg_replace_callback(
79
            '/\b__PHQUERY_[^_]++__\b/',
80
            function ($m) use (&$bindings, $settings) {
81
                return $this->replacePlaceholders($m[0], $bindings, $settings);
82
            },
83
            $sql
84
        );
85
    }
86
87
    /**
88
     * Replace '?' in the string with placeholders for value.
89
     *
90
     * e.q.  replace 'RANGE(?, ?)' with values [1, 10] etc.
91
     *
92
     * @param  string $string
93
     * @param  array $values
94
     * @access public
95
     */
96
    public function replaceQuestionMark(
97
        /*# string */ $string,
98
        array $values
99
    )/*# : string */ {
100
        $pat = $rep = [];
101
        foreach ($values as $val) {
102
            $pat[] = '/\?/'; // question mark
103
            $rep[] = $this->getPlaceholder($val); // placeholder
104
        }
105
        return preg_replace($pat, $rep, $string, 1);
106
    }
107
108
    /**
109
     * Replace each placeholder with '?', ':name' or value
110
     *
111
     * @param  string $key
112
     * @param  array &$bindings
113
     * @param  array $settings
114
     * @return string
115
     * @access protected
116
     */
117
    protected function replacePlaceholders(
118
        /*# string */ $key,
119
        array &$bindings,
120
        array $settings
121
    )/*# : string */ {
122
        $escape = $this->escape;
123
124
        $value = $this->parameters[$key];
125
        if ($settings['positionedParam']) {
126
            $bindings[] = $value;
127
            return '?';
128
        } elseif ($settings['namedParam'] && $this->isNamedParam($value)) {
129
            return $value;
130
        } else {
131
            return $escape($value);
132
        }
133
    }
134
135
    /**
136
     * Is it a named parameter ?
137
     *
138
     * @param  mixed $value
139
     * @return bool
140
     * @access protected
141
     */
142
    protected function isNamedParam($value)/*# : bool */
143
    {
144
        return is_string($value) && preg_match('/^:[a-zA-Z]\w*$/', $value);
145
    }
146
147
    /**
148
     * Set escape/quote method/function
149
     *
150
     * @param  null|callable $escapeFunction defult escape function
151
     * @return $this
152
     * @access protected
153
     */
154
    protected function setEscapeCallable($escapeFunction)/*# : callable */
155
    {
156
        if (!is_callable($escapeFunction)) {
157
            $this->escape = function ($v) {
158
                if (is_numeric($v) && !is_string($v)) {
159
                    return $v;
160
                } else {
161
                    return "'" . str_replace("'", "\\'", (string) $v) . "'";
162
                }
163
            };
164
        } else {
165
            $this->escape = $escapeFunction;
166
        }
167
        return $this;
168
    }
169
}
170