src/Soluble/Normalist/Synthetic/Table.php
public function insertOnDuplicateKey($data, array $duplicate_exclude = [], $validate_datatypes = false)
    {
        $platform = $this->tableManager->getDbAdapter()->platform;
/*
        $unique_keys   = $this->tableManager->metadata()->getUniqueKeys($this->prefixed_table);
        $unique_keys[]
        $primary_keys = $this->getPrimaryKeys();

        $uniques = array_merge(array($unique_keys, 'primary_keys' => $primary_keys));
        $cols = ['index2', 'index1'];
        $data = ['index1' => 'coool', 'index2' => 'hello'];


        $unique_found = false;
        $data_columns = array_keys($data);
        var_dump($uniques);
        while ($cols = array_pop($uniques) && !$unique_found) {

            var_dump($cols);
            die();
            $intersect = array_intersect($cols, $data_columns);
            $unique_found = ($intersect == $data_columns);
        }

        dump($intersect);

        die();
        $intersect = array_intersect($cols, array_keys($data));
        dump($intersect);
        dump($intersect == $cols);
        die();

        foreach($unique_keys as $index => $columns) {
        //    if (array_diff_key($duplicate_exclude, $d))

        }
dump($unique_keys);
dump($primary_keys);
die();
 *
 */
        $primary = $this->getPrimaryKey();

        if ($data instanceof ArrayObject) {
            $d = (array) $data;
        } else {
            $d = $data;
        }

        $this->checkDataColumns($d);
        $this->checkDataColumns(array_fill_keys($duplicate_exclude, null));

        if ($validate_datatypes) {
            $this->validateDatatypes($d);
        }

        $insert = $this->sql->insert($this->prefixed_table);
        $insert->values($d);
        $sql_string = $this->sql->getSqlStringForSqlObject($insert);


        $extras = [];

        /**
         * No reason to exclude primary key from
         */
        //$excluded_columns = array_merge($duplicate_exclude, array($primary));
        $excluded_columns = $duplicate_exclude;

        foreach ($d as $column => $value) {
            if (!in_array($column, $excluded_columns)) {
                $v = ($value === null) ? 'NULL' : $v = $platform->quoteValue($value);
                $extras[] = $platform->quoteIdentifier($column) . ' = ' . $v;
            }
        }
        $sql_string .= ' on duplicate key update ' . implode(',', $extras);

        try {
            $this->executeStatement($sql_string);
        } catch (\Exception $e) {
            $messages = [];
            $ex = $e;
            do {
                $messages[] = $ex->getMessage();
            } while ($ex = $ex->getPrevious());
            $msg = implode(', ', array_unique($messages));
            $message = __METHOD__ . ": failed, $msg [ $sql_string ]";
            throw new Exception\RuntimeException($message);
        }

        if (array_key_exists($primary, $d)) {
            // not using autogenerated value
            $pk_value = $d[$primary];
            $record = $this->findOrFail($pk_value);
        } else {
            $id = $this->tableManager->getDbAdapter()->getDriver()->getLastGeneratedValue();

            // This test is not made with id !== null, understand why before changing
            if ($id > 0) {
                $pk_value = $id;
                $record = $this->find($pk_value);
            } else {
                // if the id was not generated, we have to guess on which key
                // the duplicate has been fired
                $unique_keys = $this->tableManager->metadata()->getUniqueKeys($this->prefixed_table);
                $data_columns = array_keys($d);

                // Uniques keys could be
                // array(
                //      'unique_idx' => array('categ', 'legacy_mapping'),
                //      'unique_idx_2' => array('test', 'test2')
                //      )
                //

                $record = false;

                foreach ($unique_keys as $index_name => $unique_columns) {
                    //echo "On duplicate key\n\n $index_name \n";
                    $intersect = array_intersect($data_columns, $unique_columns);
                    if (count($intersect) == count($unique_columns)) {
                        // Try to see if we can find a record with the key
                        $conditions = [];
                        foreach ($intersect as $key) {
                            $conditions[$key] = $d[$key];
                        }
                        $record = $this->findOneBy($conditions);
                        if ($record) {
                            //$found = true;
                            //$pk_value = $record[$primary];
                            break;
                        }
                    }
                }

                // I cannot write a test case for that
                // It should never happen but in case :
                //@codeCoverageIgnoreStart
                if (!$record) {
                    throw new \Exception(__METHOD__ . ": after probing all unique keys in table '{$this->table}', cannot dertermine which one was fired when using on duplicate key.");
                }
                //@codeCoverageIgnoreEnd
            }
        }
        return $record;
    }
public function insertOnDuplicateKey($data, array $duplicate_exclude = [], $validate_datatypes = false)
    {
        $platform = $this->tableManager->getDbAdapter()->platform;
/*
        $unique_keys   = $this->tableManager->metadata()->getUniqueKeys($this->prefixed_table);
        $unique_keys[]
        $primary_keys = $this->getPrimaryKeys();

        $uniques = array_merge(array($unique_keys, 'primary_keys' => $primary_keys));
        $cols = ['index2', 'index1'];
        $data = ['index1' => 'coool', 'index2' => 'hello'];


        $unique_found = false;
        $data_columns = array_keys($data);
        var_dump($uniques);
        while ($cols = array_pop($uniques) && !$unique_found) {

            var_dump($cols);
            die();
            $intersect = array_intersect($cols, $data_columns);
            $unique_found = ($intersect == $data_columns);
        }

        dump($intersect);

        die();
        $intersect = array_intersect($cols, array_keys($data));
        dump($intersect);
        dump($intersect == $cols);
        die();

        foreach($unique_keys as $index => $columns) {
        //    if (array_diff_key($duplicate_exclude, $d))

        }
dump($unique_keys);
dump($primary_keys);
die();
 *
 */
        $primary = $this->getPrimaryKey();

        if ($data instanceof ArrayObject) {
            $d = (array) $data;
        } else {
            $d = $data;
        }

        $this->checkDataColumns($d);
        $this->checkDataColumns(array_fill_keys($duplicate_exclude, null));

        if ($validate_datatypes) {
            $this->validateDatatypes($d);
        }

        $insert = $this->sql->insert($this->prefixed_table);
        $insert->values($d);
        $sql_string = $this->sql->getSqlStringForSqlObject($insert);


        $extras = [];

        /**
         * No reason to exclude primary key from
         */
        //$excluded_columns = array_merge($duplicate_exclude, array($primary));
        $excluded_columns = $duplicate_exclude;

        foreach ($d as $column => $value) {
            if (!in_array($column, $excluded_columns)) {
                $v = ($value === null) ? 'NULL' : $v = $platform->quoteValue($value);
                $extras[] = $platform->quoteIdentifier($column) . ' = ' . $v;
            }
        }
        $sql_string .= ' on duplicate key update ' . implode(',', $extras);

        try {
            $this->executeStatement($sql_string);
        } catch (\Exception $e) {
            $messages = [];
            $ex = $e;
            do {
                $messages[] = $ex->getMessage();
            } while ($ex = $ex->getPrevious());
            $msg = implode(', ', array_unique($messages));
            $message = __METHOD__ . ": failed, $msg [ $sql_string ]";
            throw new Exception\RuntimeException($message);
        }

        if (array_key_exists($primary, $d)) {
            // not using autogenerated value
            $pk_value = $d[$primary];
            $record = $this->findOrFail($pk_value);
        } else {
            $id = $this->tableManager->getDbAdapter()->getDriver()->getLastGeneratedValue();

            // This test is not made with id !== null, understand why before changing
            if ($id > 0) {
                $pk_value = $id;
                $record = $this->find($pk_value);
            } else {
                // if the id was not generated, we have to guess on which key
                // the duplicate has been fired
                $unique_keys = $this->tableManager->metadata()->getUniqueKeys($this->prefixed_table);
                $data_columns = array_keys($d);

                // Uniques keys could be
                // array(
                //      'unique_idx' => array('categ', 'legacy_mapping'),
                //      'unique_idx_2' => array('test', 'test2')
                //      )
                //

                $record = false;

                foreach ($unique_keys as $index_name => $unique_columns) {
                    //echo "On duplicate key\n\n $index_name \n";
                    $intersect = array_intersect($data_columns, $unique_columns);
                    if (count($intersect) == count($unique_columns)) {
                        // Try to see if we can find a record with the key
                        $conditions = [];
                        foreach ($intersect as $key) {
                            $conditions[$key] = $d[$key];
                        }
                        $record = $this->findOneBy($conditions);
                        if ($record) {
                            //$found = true;
                            //$pk_value = $record[$primary];
                            break;
                        }
                    }
                }

                // I cannot write a test case for that
                // It should never happen but in case :
                //@codeCoverageIgnoreStart
                if (!$record) {
                    throw new \Exception(__METHOD__ . ": after probing all unique keys in table '{$this->table}', cannot dertermine which one was fired when using on duplicate key.");
                }
                //@codeCoverageIgnoreEnd
            }
        }
        return $record;
    }
Insert on duplicate key

@param array|ArrayObject $data
@param array|null $duplicate_exclude
@param boolean $validate_datatypes ensure data are compatible with database columns datatypes

@throws Exception\ColumnNotFoundException
@throws Exception\RecordNotFoundException
@throws Exception\ForeignKeyException when insertion failed because of an invalid foreign key
@throws Exception\DuplicateEntryException when insertion failed because of an invalid foreign key
@throws Exception\NotNullException when insertion failed because a column cannot be null

@return Record|false