array($this, 'getClauseInsertInto'), 'VALUES' => array($this, 'getClauseValues'), 'ON DUPLICATE KEY UPDATE' => array($this, 'getClauseOnDuplicateKeyUpdate'), ); parent::__construct($fluent, $clauses); $this->statements['INSERT INTO'] = $table; $this->values($values); } /** * Execute insert query * * @param mixed $sequence * * @return integer last inserted id or false */ public function execute($sequence = null) { $result = parent::execute(); if ($result) { return $this->getPDO()->lastInsertId($sequence); } return false; } /** * Add ON DUPLICATE KEY UPDATE * * @param array $values * * @return Insert */ public function onDuplicateKeyUpdate($values) { $this->statements['ON DUPLICATE KEY UPDATE'] = array_merge( $this->statements['ON DUPLICATE KEY UPDATE'], $values ); return $this; } /** * Add VALUES * * @param $values * * @return Insert * @throws \Exception */ public function values($values) { if (!is_array($values)) { throw new \Exception('Param VALUES for INSERT query must be array'); } $first = current($values); if (is_string(key($values))) { // is one row array $this->addOneValue($values); } elseif (is_array($first) && is_string(key($first))) { // this is multi values foreach ($values as $oneValue) { $this->addOneValue($oneValue); } } return $this; } /** * Force insert operation to fail silently * * @return Insert */ public function ignore() { $this->ignore = true; return $this; } /** Force insert operation delay support * * @return Insert */ public function delayed() { $this->delayed = true; return $this; } /** * @return string */ protected function getClauseInsertInto() { return 'INSERT' . ($this->ignore ? " IGNORE" : '') . ($this->delayed ? " DELAYED" : '') . ' INTO ' . $this->statements['INSERT INTO']; } /** * @param $param * * @return string */ protected function parameterGetValue($param) { return $param instanceof Literal ? (string)$param : '?'; } /** * @return string */ protected function getClauseValues() { $valuesArray = array(); foreach ($this->statements['VALUES'] as $rows) { // literals should not be parametrized. // They are commonly used to call engine functions or literals. // Eg: NOW(), CURRENT_TIMESTAMP etc $placeholders = array_map(array($this, 'parameterGetValue'), $rows); $valuesArray[] = '(' . implode(', ', $placeholders) . ')'; } $columns = implode(', ', $this->columns); $values = implode(', ', $valuesArray); return " ($columns) VALUES $values"; } /** * Removes all Literal instances from the argument * since they are not to be used as PDO parameters but rather injected directly into the query * * @param $statements * * @return array */ protected function filterLiterals($statements) { $f = function ($item) { return !$item instanceof Literal; }; return array_map(function ($item) use ($f) { if (is_array($item)) { return array_filter($item, $f); } return $item; }, array_filter($statements, $f)); } /** * @return array */ protected function buildParameters() { $this->parameters = array_merge( $this->filterLiterals($this->statements['VALUES']), $this->filterLiterals($this->statements['ON DUPLICATE KEY UPDATE']) ); return parent::buildParameters(); } /** * @return string */ protected function getClauseOnDuplicateKeyUpdate() { $result = array(); foreach ($this->statements['ON DUPLICATE KEY UPDATE'] as $key => $value) { $result[] = "$key = " . $this->parameterGetValue($value); } return ' ON DUPLICATE KEY UPDATE ' . implode(', ', $result); } /** * @param array $oneValue * * @throws \Exception */ private function addOneValue($oneValue) { // check if all $keys are strings foreach ($oneValue as $key => $value) { if (!is_string($key)) { throw new \Exception('INSERT query: All keys of value array have to be strings.'); } } if (!$this->firstValue) { $this->firstValue = $oneValue; } if (!$this->columns) { $this->columns = array_keys($oneValue); } if ($this->columns != array_keys($oneValue)) { throw new \Exception('INSERT query: All VALUES have to same keys (columns).'); } $this->statements['VALUES'][] = $oneValue; } }