Пятница. Говнокод. Парсинг плейсхолдеров.

riff

Новичок
Я что-то упустил, специально или случайно не было плейсхолдера для float?
 

Фанат

oncle terrible
Команда форума
Я что-то упустил, специально или случайно не было плейсхолдера для float?
Я не встречал случая, когда флоат нельзя забиндить как стринг.
Не говоря уже о том, что флоаты в базе надо использовать ОЧЕНЬ осторожно. И мне почти неизвестны случаи, когда флоат вообще в принципе нужен.
 

ksnk

прохожий
Деньги - в копейках, центах. С бухгалтерами потом проще общаться.
С процентами, вообще говоря, засада. Хотя, практически всегда хватало целого.
 

riff

Новичок
флоаты в базе надо использовать ОЧЕНЬ осторожно
Float'ы да, а Decimal'ы, то используются

Для int парсёр
$data = str_replace(',', '.', $data); //заменяет
if (!is_numeric($data)) //проверяет
return number_format($data, 0, '.', ''); //оставляет целую часть

Для float'ов парсер мог бы
$data = str_replace(',', '.', $data); //заменять
if (!is_numeric($data)) //проверять
return $data; //если всё ок, возвращать без дальнейших приведений к типу
 
  • Like
Реакции: AmdY

hell0w0rd

Продвинутый новичок
riff, он говорил про саму базу, я так понимаю с переполнениями типа связанно, хотя мне вот странно - в базах нет длинной арифметики?
хватит пытаться просунуть свой валидатор в драйвер))
 

riff

Новичок
хватит пытаться просунуть свой валидатор в драйвер
Объективности ради, его(драйвер) таким строгим Фанат сделал. Он кажется уже объяснял почему на ошибках в данных он вызывает Exceptions, а не преобразовывает к нужному типу. Я лишь спросил почему не было ещё одного типа.
 
Последнее редактирование:

WMix

герр M:)ller
Партнер клуба
Фанат, хотел тебе одну штучку предложить для разширения функциональности класса.
PHP:
 public function getInd()
{
    $args = func_get_args();
    $index = array_shift($args);
    $query = $this->prepareQuery($args);
    $ret = array();
    if ( $res = $this->rawQuery($query) )
    {
        while($row = $this->fetch($res))
        {
            // feature
            if(is_array($index)){
                foreach($index as  $idx){
                    $ret[ $idx ][ $row[$idx] ] = $row;
                }
            }
            // standart
            else $ret[$row[$index]] = $row;
        }
        $this->free($res);
    }
    return $ret;
}
// дает возможность получить несколько индексов
$db->getInd(array('id','name'));
можно кстати и getGrp() впихнуть
 
Последнее редактирование:

riff

Новичок
Простите, а можно поинтересоваться, в целях повышения самообразования (c)

Можно в двух словах объяснить, что делает эта функция? (не получилось в уме её скомпилировать)
И где она полезна?
 

WMix

герр M:)ller
Партнер клуба
PHP:
$db = new SafeMySQL($opts);
$data = $db->getInd(array('id','nick'),'SELECT * FROM users');
print_r( $data['id'][42] );
print_r( $data['nick']['wmix'] );
получить доступ к строке по любому указанному индексу ( в 8 словах )
 

fixxxer

К.О.
Партнер клуба
Он вложенные массивы хочет. У меня для этого немного сумасшедший getAll():
PHP:
    /**
     * Executes a select query. Retrns array of rows, grouped depending on arguments.
     *
     * @code
     * #Example 1:
     *       getAll('select user_id, group_id, f1, f2 from T where user_type={{s(type)}}',
     *              array('type'=>'member'), array('group_id'=>INF, 'user_id'=>INF))
     *
     *       user_id   group_id   f1      f2
     *       -------   --------   -----   -----
     *       1         1          f1_1    f2_1
     *       2         1          f1_2    f2_2
     *       3         2          f1_3    f2_3
     *
     *       array(
     *           #group_id
     *            1 => array(
     *              #user_id
     *               1 => array(array('user_id'=>1, 'group_id'=>1, 'f1'=>'f1_1', 'f2'=>'f2_1')),
     *               2 => array(array('user_id'=>2, 'group_id'=>1, 'f1'=>'f1_2', 'f2'=>'f2_2')),
     *            ),
     *            2 => array(
     *               3 => array(array('user_id'=>3, 'group_id'=>2, 'f1'=>'f1_3', 'f2'=>'f2_3')),
     *            ),
     *        )
     *
     * #Example 2:
     *       getAll('select user_id, group_id, f1, f2 from T where user_type={{s(type)}}',
     *             array('type'=>'member'), array('user_id'=>1))
     *       # returned rows are identical to Example 1
     *       array(
     *           #user_id
     *            1 => array('user_id'=>1, 'group_id'=>1, 'f1'=>'f1_1', 'f2'=>'f2_1'),
     *            2 => array('user_id'=>2, 'group_id'=>1, 'f1'=>'f1_2', 'f2'=>'f2_2'),
     *            3 => array('user_id'=>3, 'group_id'=>2, 'f1'=>'f1_3', 'f2'=>'f2_3'),
     *       )
     *
     * #Example 3:
     *       getAll('select user_id, group_id, f1, f2 from T where user_type={{s(type)}}',
     *             array('type'=>'member'), array('user_id'=>INF))
     *       array(
     *           #user_id
     *            1 => array(array('user_id'=>1, 'group_id'=>1, 'f1'=>'f1_1', 'f2'=>'f2_1')),
     *            ...
     *       )
     * @endcode
     *
     * @param string $tpl template query
     * @param array $params args
     * @param array $keys group keys array of ( group_by_key => 1|INF|field_name ),
     *                             where 1 = values are unique => do not create nested arrays;
     *                                   INF = values are not unique => create nested arrays;
     *                                   string field_name = create scalar value of field_name (must be the last group key)
     * @return array|null
     */
    public function getAll($tpl, array $params = [], array $keys = []) {
        if (null === ($h = $this->executeQueryTemplate($tpl, $params))) {
            return null;
        }
        $result = [];
        $num_keys = count($keys);
        while (null !== ($row = $this->Connection->fetch($h))) {
            if (!$num_keys) {
                $result[] = $row;
            } else {
                $r = & $result;
                foreach ($keys as $key_name => $num_of_values) {
                    if (is_string($num_of_values) && '1' !== $num_of_values) {
                        $r[$row[$key_name]] = $row[$num_of_values];
                        continue 2;
                    }
                    $r = & $r[$row[$key_name]];
                    if ($num_of_values === INF) {
                        $r = & $r[];
                    }
                }
                $r = $row;
            }
        }
        $this->Connection->freeResult($h);
        return $result;
    }

//////// кусок теста

        $expected = [
            '1' => ['id'=>'1','s'=>'1'],
            '2' => ['id'=>'2','s'=>'2'],
        ];
        $result = $Client->getAll("SELECT id, s FROM test WHERE id <= {{ id(id) }} ORDER BY id", [ 'id' => 2 ], [ 'id' => 1 ]);
        $this->assertEquals($expected, $result);

        $expected = [
            '1' => [['id'=>'1','s'=>'1']],
            '2' => [['id'=>'2','s'=>'2']],
        ];
        $result = $Client->getAll("SELECT id, s FROM test WHERE id <= {{ id(id) }} ORDER BY id", [ 'id' => 2 ], [ 'id' => INF ]);
        $this->assertEquals($expected, $result);

        $expected = [
            '1' => [['1' => ['id'=>'1','s'=>'1']]],
            '2' => [['2' => ['id'=>'2','s'=>'2']]],
        ];
        $result = $Client->getAll("SELECT id, s FROM test WHERE id <= {{ id(id) }} ORDER BY id", [ 'id' => 2 ], [ 'id' => INF, 's' => 1 ]);
        $this->assertEquals($expected, $result);
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
понял.
это не просто вложенные массивы, это вырожденные коллекции, в php 4 это имело смысл
но ведь xpath-style привычнее и удобнее: $Users->nick->wmix
 

fixxxer

К.О.
Партнер клуба
не совсем, такой штукой удобно приводить в нужный для value object-а модели (точнее, обычно коллекции моделей) вид то, что получилось в результате join-ов.

так, чтобы просто foreach ($results as $id => $row) $collection[$id] = new Item($row)
 

Фанат

oncle terrible
Команда форума
Вот кстати.
Давно хотел спросить.
Я вот думал о том, чтобы для гетОлл() просто сделать необязательным параметром кложуру.
И вот в ней уже пытливый читатель пусть пишет любую логику группировки, какая ему захочется. Это вообще реализуемо?
Исключительно для того, чтобы, с одной стороны, не перегружать "стандартную библиотеку" - API - так, чтобы для ее использования постоянно требовалось чтение документации. А с другой - чтобы не не ограничивать пользователя вообще никак в его фантазиях. Ведь речь не только о группировках, а о любом форматировании вообще.
 
Последнее редактирование:

riff

Новичок
Я вот думал о том, чтобы для гетОлл() просто сделать необязательным параметром кложуру.
PHP:
//namespace ...

/**
* @property int insert_id
*/
class db_mysqli_result extends \mysqli_result
{
    public function __get($name)
    {
        switch ($name) {
            case 'insert_id':
                return DB::$handle->insert_id;
            default:
                return false;
        }
    }

    /**
    * Получает (следующую) запись из результата запроса
    *
    * @return \stdClass|boolean
    */
    public function get()
    {
        //У меня записи в виде объектов забираются, можно на массивы заменить
        return $this->fetch_object();
    }

    /**
    * Загружает все записи из результата запроса
    *
    * @param callable|null $fn
    * @return array|boolean
    */
    public function getAll($fn = null)
    {
        $rows = array();
        //У меня записи в виде объектов забираются, можно на массивы заменить
        while ($row = $this->fetch_object())
        {
            //если есть callback, то
            is_callable($fn)
                ? $fn($row) //ему передаём полученную запись,
                : $rows[] = $row; //иначе загружаем в свой список
        }
        //возвращаем true если был колбэк, иначе записи
        return is_callable($fn) ? true : $rows;
    }
}

class DB
{
    /** @var \mysqli */
    static public $handle = false;

    /**
    * @static
    * @param  $params array
    * @return bool
    */
    static public function connect($params)
    {
        if (self::$handle = new \mysqli('localhost', $params['login'], $params['password']))
        {
            self::$handle->select_db($params['db_name']);
            self::$handle->set_charset('UTF8');
            return true;
        }
        return false;
    }

    /**
    * Выполняет запрос к БД.
    *
    * @param string $sql
    * @param array|null $args
    * @return db_mysqli_result|bool
    */
    public static function query($sql, $args = null)
    {
        if ($args) {
            //подключается парсёр
        }

        if ($query = self::$handle->real_query($sql))
        {
            return new db_mysqli_result(self::$handle);
        }
        trigger_error(self::$handle->error, E_USER_WARNING);
        return false;
    }
}
Пример:
PHP:
$rows = DB::query('SELECT * FROM...')->getAll();

//или
$rows = array();
/* этот пример исправлен, забыл убрать $rows = */
/* $rows = */ DB::query('SELECT * FROM...')->getAll(function($row) use(&$rows) {
    $rows[] = $row;
});

//или по-старинке
$query = DB::query(...);
while ($row = $query->fetch...) {}

P.S. Сейчас заметил неточность во втором своём примере:
$rows = DB::query('SELECT * FROM...')->getAll(function(
следует писать так
DB::query('SELECT * FROM...')->getAll(function(
т.е. без "$rows = "
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
fixxxer, это делается в самой коллекции
так же можно сделать прототип коллекции с движком для связей, а в реализации только указывать имена полей для работы связей,
достоинство - автокомплит
не надо это интегрировать с запросом
 

WMix

герр M:)ller
Партнер клуба
Фанат, а как клоузурой присвоение описать? плохо прочел, прикольненько!
PHP:
$rows = DB::query('SELECT * FROM...')->getAll(function($row) use(&$rows) {
    $rows[] = $row;
}
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
WMix, лямбда получит на вход 2-мерный массив, и отдаст что захочет, в getAll вернет результат работы closure,
и в ней ты можешь хоть присвоения делать, хоть обработку
 
Сверху