SQLFileWriter::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 9
c 0
b 0
f 0
dl 0
loc 14
rs 9.9666
cc 1
nc 1
nop 3
1
<?php
2
3
namespace Jackal\Copycat\Writer;
4
5
use Exception;
6
use InvalidArgumentException;
7
use Symfony\Component\OptionsResolver\OptionsResolver;
8
9
/**
10
 * Class SQLFileWriter
11
 * @package Jackal\Copycat\Writer
12
 */
13
class SQLFileWriter implements WriterInterface
14
{
15
    /**
16
     * @var string
17
     */
18
    protected $outputFilePathname;
19
20
    /**
21
     * @var string
22
     */
23
    protected $tableName;
24
25
    /**
26
     * @var array
27
     */
28
    protected $options = [];
29
30
    /**
31
     * @var int
32
     */
33
    protected $index;
34
35
    /**
36
     * @var array
37
     */
38
    protected $cols = [];
39
40
    /**
41
     * SQLFileWriter constructor.
42
     * @param $tableName
43
     * @param $outputFilePathname
44
     * @param array $options
45
     */
46
    public function __construct($tableName, $outputFilePathname, array $options = [])
47
    {
48
        $this->tableName = $tableName;
49
        $this->outputFilePathname = $outputFilePathname;
50
51
        $resolver = new OptionsResolver();
52
        $resolver->setDefaults([
53
            'replace_file' => false,
54
            'columns' => [],
55
            'exception_on_extra_columns' => false,
56
            'drop_data' => false,
57
        ]);
58
59
        $this->options = $resolver->resolve($options);
60
    }
61
62
    /**
63
     * @param $content
64
     */
65
    private function appendRow($content)
66
    {
67
        file_put_contents($this->outputFilePathname, $content, FILE_APPEND);
68
    }
69
70
    /**
71
     * @param array $item
72
     */
73
    public function writeItem(array $item)
74
    {
75
        if ($this->index == 0) {
76
            if (!$this->options['columns']) {
77
                $this->cols = array_keys($item);
78
            } else {
79
                $this->cols = $this->options['columns'];
80
            }
81
        }
82
83
        //raise exception on extra columns
84
        if ($this->options['exception_on_extra_columns']) {
85
            $extraColumns = [];
86
            foreach (array_keys($item) as $itemKey) {
87
                if (!in_array($itemKey, $this->cols)) {
88
                    $extraColumns[] = $itemKey;
89
                }
90
            }
91
            if ($extraColumns) {
92
                throw new InvalidArgumentException(sprintf(
93
                    'Row %s had extra columns %s. (Defined columns: %s)',
94
                    $this->index + 1,
95
                    '"' . implode('", "', $extraColumns) . '"',
96
                    '"' . implode('", "', $this->cols) . '"'
97
                ));
98
            }
99
        }
100
101
        //Fill array maintain defined order
102
        foreach ($this->cols as $key => $colName) {
103
            if (!array_key_exists($colName, $item)) {
104
                $item[$colName] = null;
105
            }
106
        }
107
108
        $itemOrdered = [];
109
        $colOrder = array_flip($this->cols);
110
        foreach ($colOrder as $colKey => $colValue) {
111
            $itemOrdered[$colKey] = $item[$colKey];
112
        }
113
        $item = $itemOrdered;
114
115
        if ($this->index == 0) {
116
            if ($this->options['drop_data']) {
117
                $this->appendRow(sprintf("delete from %s\n", $this->tableName));
118
            }
119
            $this->appendRow(sprintf("insert into %s (%s) values\n", $this->tableName, implode(', ', array_keys($item))));
120
        } else {
121
            $this->appendRow(",\n");
122
        }
123
124
        $item = array_reduce($item, function ($outCell, $currentCell) {
125
            if (is_null($currentCell)) {
126
                $outCell[] = 'null';
127
128
                return $outCell;
129
            }
130
            //escape sql string
131
            $search = ['\\',  "\x00", "\n",  "\r",  "'",  '"', "\x1a"];
132
            $replace = ['\\\\','\\0','\\n', '\\r', "\'", '\"', '\\Z'];
133
            $outCell[] = '"' . str_replace($search, $replace, $currentCell) . '"';
134
135
            return $outCell;
136
        }, []);
137
138
        $rowString = sprintf('(%s)', implode(', ', array_values($item)));
139
        $this->appendRow($rowString);
140
        $this->index++;
141
    }
142
143
    /**
144
     * @throws Exception
145
     */
146
    public function prepare()
147
    {
148
        if (!is_dir(dirname($this->outputFilePathname))) {
149
            mkdir(dirname($this->outputFilePathname), 0775, true);
150
        }
151
152
        $fileExists = file_exists($this->outputFilePathname);
153
        if ($fileExists and !$this->options['replace_file']) {
154
            throw new Exception('File ' . realpath($this->outputFilePathname) . ' already exists');
155
        }
156
157
        if ($fileExists) {
158
            unlink($this->outputFilePathname);
159
        }
160
    }
161
162
    /**
163
     *
164
     */
165
    public function finish()
166
    {
167
        $this->appendRow(';');
168
    }
169
}
170