Skip to content

Instantly share code, notes, and snippets.

@bel1k0v
Created September 14, 2017 17:06
Show Gist options
  • Save bel1k0v/abc62a9ff1ca7b63ce67c9980b36b36a to your computer and use it in GitHub Desktop.
Save bel1k0v/abc62a9ff1ca7b63ce67c9980b36b36a to your computer and use it in GitHub Desktop.
<?php
namespace common\components\pgsql;
use yii\base\Behavior;
use yii\db\ActiveRecord;
class ArrayBehavior extends Behavior
{
public $attributes;
/**
* @return array
*/
public function events()
{
return [
ActiveRecord::EVENT_INIT => 'loadArrays',
ActiveRecord::EVENT_AFTER_FIND => 'loadArrays',
ActiveRecord::EVENT_AFTER_INSERT => 'loadArrays',
ActiveRecord::EVENT_AFTER_UPDATE => 'loadArrays',
ActiveRecord::EVENT_BEFORE_INSERT => 'saveArrays',
ActiveRecord::EVENT_BEFORE_UPDATE => 'saveArrays'
];
}
/**
* void
*/
public function saveArrays()
{
/* @var $owner ActiveRecord */
$owner = $this->owner;
$values = $owner->getAttributes($this->attributes);
foreach ($values as $attr => $value) {
if (is_array($value)) {
$value = $this->arrayToPg($value);
} elseif (empty($value)) {
$value = '{}';
}
$owner->setAttribute($attr, $value);
}
}
/**
* @throws \Exception
*/
public function loadArrays()
{
/* @var $owner ActiveRecord */
$owner = $this->owner;
$values = $owner->getAttributes($this->attributes);
foreach ($values as $attr => $value) {
$value = $this->pgToArray($value);
$value = $value ?: [];
$owner->setAttribute($attr, $value);
}
}
/**
* Преобразует массив PostgreSQL в массив PHP
* @param string $array_string
* @param boolean $reset
* @throws \Exception
* @return array
*/
protected function pgToArray($array_string, $reset = true)
{
static $i = 0;
if ($reset) $i = 0;
$matches = array();
$indexer = 1; // by default sql attributes start at 1
// handle [0,2]= cases
if (preg_match('/^\[(?P<index_start>\d+):(?P<index_end>\d+)]=/', substr($array_string, $i), $matches)) {
$indexer = (int)$matches['index_start'];
$i = strpos($array_string, '{');
}
if ($array_string[$i] != '{') {
return NULL;
}
if (is_array($array_string)) return $array_string;
// handles btyea and blob binary streams
if (is_resource($array_string)) return fread($array_string, 4096);
$i++;
$work = array();
$curr = '';
$length = strlen($array_string);
$quoted = false;
while ($i < $length) {
// echo "\n [ $i ] ..... $array_string[$i] .... $curr";
switch ($array_string[$i]) {
case '{':
$sub = self::pgToArray($array_string, false);
if (!empty($sub)) {
$work[$indexer++] = $sub;
}
break;
case '}':
$i++;
if (!empty($curr)) {
$work[$indexer++] = $curr;
}
return $work;
break;
case '\\':
$i++;
$curr .= $array_string[$i];
$i++;
break;
case '"':
$quoted = true;
$openq = $i;
do {
$closeq = strpos($array_string, '"', $i + 1);
if ($closeq > $openq && $array_string[$closeq - 1] == '\\') {
$i = $closeq;
} else {
break;
}
} while (true);
if ($closeq <= $openq) {
throw new \Exception('Unexpected condition');
}
$curr .= substr($array_string, $openq + 1, $closeq - ($openq + 1));
$i = $closeq + 1;
break;
case ',':
if (strlen($curr) > 0) {
if (!$quoted && (strtoupper($curr) == 'NULL')) {
$curr = null;
}
$work[$indexer++] = $curr;
}
$curr = '';
$quoted = false;
$i++;
break;
default:
$curr .= $array_string[$i];
$i++;
}
}
}
/**
* Преобразует массив PHP в массив PostgreSQL
* @param mixed $value
* @return string
*/
protected function arrayToPg(array $value)
{
$f = function (&$value) {
if (is_string($value) && !empty($value)) {
$value = "\"{$value}\"";
}
if (is_array($value)) {
$value = '{' . implode(',', $value) . '}';
}
};
array_walk_recursive($value, $f);
$f($value);
return $value;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment