За последние 24 часа нас посетили 10117 программистов и 457 роботов. Сейчас ищут 100 программистов ...

Объектный SQL

Тема в разделе "Прочие вопросы по PHP", создана пользователем Sergey89, 26 июл 2008.

  1. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Обсудим?

    PHP:
    1. <?php
    2. $query = Query::select('[n.*], [a.name] AS [author]')
    3.     ->from(array('news' => 'n'))
    4.     ->join(array('authors' => 'a'), '[a.id] = [n.author_id]')
    5.     ->where('[n.active] = 1')
    6.     ->offset(($page - 1) * 10)
    7.     ->limit($items_per_page)
    8. ;
    9.  
    10. if ($sort_by_popular) {
    11.     $query->andWhere('[n.rating] > ?', $min_rating);
    12.     $query->orderByDesc('[n.rating]');
    13. } else {
    14.     $query->orderByDesc('[n.id]');
    15. }
    MySQL:
    [sql]
    SELECT `n`.*, `a`.`name` AS `author`
    FROM `news` `n`
    INNER JOIN `authors` `a`
    ON (`a`.`id` = `n`.`author_id`)
    WHERE `n`.`active` = 1
    AND `n`.`rating` > 10
    ORDER BY `n`.`rating` DESC
    LIMIT 2, 10
    [/sql]

    В идеале - полная абстракция над SQL и не зависимость от СУБД :) Возможность формировать запросы на лету в любом порядке.
     
  2. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Sergey89
    Бесперспективно, имхо. Такой подход реализован в LIMB и onPHP. Въехать и нормально изучить эту систему объектов практически невозможно :( Причем если в LIMB это сделано просто замороченно, то в onPHP тихий ужас.
    Полная абстракция и независимость таким образом все равно недостижима; попробуй придумать объектную обертку для запроса, например

    [sql]SELECT p.*, b.* FROM players p, bands b WHERE p.id IN (10,15,17,20) AND p.bandid=b.id ORDER BY p.name[/sql]

    А потом подумай, сколько людей предпочтут написать такую же конструкцию на PHP, вместо того, чтобы написать нормальный честный SQL-запрос.
     
  3. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    В onPHP слишком детализированная модель. Вплоть до объекта на поле.
     
  4. DarkElf

    DarkElf Активный пользователь

    С нами с:
    22 окт 2006
    Сообщения:
    1.632
    Симпатии:
    0
    Sergey89

    а в чем смысл то?
     
  5. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
     
  6. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    0
    Адрес:
    леноград
    независимости от субд не существует.
     
  7. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    [sql]SELECT p.*, b.* FROM players p, bands b WHERE p.id IN (10,15,17,20) AND p.bandid=b.id ORDER BY p.name[/sql]

    PHP:
    1. <?php
    2. Query::select('[p.*], [b.*]')
    3. ->from(array('players' => 'p'))
    4. ->join(array('bands' => 'b'), '[p.bandid] = [b.id]')
    5. ->whereIn('[p.id]', array(10, 15, 17, 20))
    6. ->orderBy('[p.name]');
     
  8. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Наверное, даже не независимость а просто возможность сменить диалект на другой. Но часть таких запросов, в принципе, переносима от одной СУБД к другой.
     
  9. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    Sergey89
    Угу. Теперь смотри, я давно не работал с этим проектом и мне надо что-то подправить в запросе. Увидев эту обертку, я должен сначала мысленно превратить ее обратно в SQL, чтобы понять, что именно она запрашивает из базы, потом мысленно же внести изменения и превратить эти изменения в изменения в последовательности вызовов методов. Если, конечно, каких-нибудь граблей по пути не окажется, все-таки SQL хорошо известен, изучен и отлажен, а твои "доспехи" - пока нет :(

    Поэтому их лучше в виде запросов и оставить :)
     
  10. Ti

    Ti Активный пользователь

    С нами с:
    3 июл 2006
    Сообщения:
    2.378
    Симпатии:
    1
    Адрес:
    d1.ru, Екатеринбург
    Програмно-генерируемые запросы удобны когда не известен список условий, таблицы выборок, полей сортировок и т.д.

    В нашей реализации ORM используем похожую схему (но проще), так человекам легче юзать его чем писать SQL, мне и самому его на порядок проще воспринимать ;)
     
  11. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Ti, покажешь вашу реализацию?
     
  12. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    +1 к Sergey89
     
  13. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Возможно мысленно этого делать не придётся
    PHP:
    1. print $query;
    и запрос перед тобой.

    Ну например в пиджи, насколько мне известно, LIMIT 30, 10 запишется как LIMIT 10 OFFSET 30.
     
  14. Ti

    Ti Активный пользователь

    С нами с:
    3 июл 2006
    Сообщения:
    2.378
    Симпатии:
    1
    Адрес:
    d1.ru, Екатеринбург
    Это часть фреймверка, если выкладывать то в виде отдельного проекта или весь фреймверк, или попробовать вынести в Zend_Framework - штука действительно вышла удобная.

    Мы стали ее разрабатывать ибо существующие реализации ORM являлись неудобным/нерабочими

    Вся штуковина состоит из следующих частей:
    - Схема (Scheme) - какие у нас таблицы и связи
    - Список (List) - выборка
    - Объект
    - Драйвер - реализация под конкретную БД

    Это полнофункциональная ORM, по этому покажу как это в конечном счете выглядит
    PHP:
    1. <?
    2. // Установка
    3. // Создаем таблицы:
    4. $scheme = ORM_Scheme::GetInstance();
    5.  
    6. $a = $scheme->add('A');
    7. $a->add('name')->setNotNull();
    8. $a->add('type')->setType('int')->setDefault(0);
    9.  
    10. $b = $scheme->add('B');
    11. $b->add('a')->setType('A');
    12.  
    13. $scheme->save();
    14.  
    15. // Использование
    16.  
    17. // Создаем объекты
    18. $a = new A;
    19. $a->name = 'waka';
    20. $a->save();
    21.  
    22. $b = new B;
    23. $b->a = $a;
    24. $b->save();
    25.  
    26. // Получаем
    27. // Список - это итератор, по нему можно бегать через foreach
    28. $a = ORM_List::Get('A')->getOne(); // первый объект
    29. $a = ORM_List::GetById('A', 1); // выборка по id
    30.  
    31. $list = ORM_List::Get('A');
    32. $list->name = 'waka';
    33. $a = $list->getOne();
    34.  
    35. $list = ORM_List::Get('A');
    36. $list->bond('B')->equals('a', $list->id)->equals('id', 123);
    37. $list->limit(10);
    38. $list->offset(10);
    39. $count = count($list); // без лимита
    40. $list->countInResult(); // с учетом лимита
    41.  
    42. // Есть возможность впрыскивать SQL во все его части
    43. $list = ORM_List::Get('A');
    44. $list->getQueryBuilder()->addWhere("$list->name IN (SELECT ...)");
    45. foreach($list as $a) ; //
    46.  
    Система покрыта тестами (в т.ч. на SQL-инъекции), стабильна.
     
  15. Hight

    Hight Старожил
    Команда форума Модератор

    С нами с:
    5 мар 2006
    Сообщения:
    7.154
    Симпатии:
    0
    Адрес:
    из злой параллельной вселенной
    Дану нафиг, жесть какая-то =)
     
  16. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Жесть это когда надо составить запрос по условиям :)
     
  17. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Ti, а схема и модель умеют разворачиваться из какой-нить внешней конфигурации? Например XML или ini файла.
     
  18. Ti

    Ti Активный пользователь

    С нами с:
    3 июл 2006
    Сообщения:
    2.378
    Симпатии:
    1
    Адрес:
    d1.ru, Екатеринбург
    Нет, мне казалась эта система дикой и неудобной.
    Схема хранится в серилизованном виде в отдельной таблице.
    К этой штуке уже прирасло что то типа PhpOrmAdmin =)

    Классы наследуют ORM_Object.
    Создавать их необязательно:
    при их отсутствии автолоадер ORM создаст пустой класс eval("class $class extends ORM_Object {}");
     
  19. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    А ты можешь как-то выложить эту библиотеку? Я бы поковырял сорсы.
     
  20. Ti

    Ti Активный пользователь

    С нами с:
    3 июл 2006
    Сообщения:
    2.378
    Симпатии:
    1
    Адрес:
    d1.ru, Екатеринбург
    можешь, на днях выложу
     
  21. Sergey89

    Sergey89 Активный пользователь

    С нами с:
    4 янв 2007
    Сообщения:
    4.796
    Симпатии:
    0
    Мне нравится решение с использованием Data Mapper, когда модель ничего не знает ни о базе данных, ни о таблице.

    PHP:
    1. <?php
    2. // выборка
    3. $user_mapper = new UserMapper();
    4. $user = $user_mapper->findById(123);
    5.  
    6. print $user->getId();
    7.  
    8. // сохранение
    9. $news = new News();
    10. $news->setTitle('Hello, world!');
    11.  
    12. $news_mapper = new NewsMapper();
    13. $news_mapper->save($news);
    14.  
    15. print $news->getId(); // выведет ID только что вставленной записи
     
  22. Dagdamor

    Dagdamor Активный пользователь

    С нами с:
    4 фев 2006
    Сообщения:
    2.095
    Симпатии:
    1
    Адрес:
    Барнаул
    /me смотрит, как зарождается очередной классомонстр-франкенштейн, и бьется головой об стол
     
  23. Ti

    Ti Активный пользователь

    С нами с:
    3 июл 2006
    Сообщения:
    2.378
    Симпатии:
    1
    Адрес:
    d1.ru, Екатеринбург
    держите: http://stelur.ru/Modules_r5712.tbz 41 Кб.

    PHP5. Драйвер только для pgsql, юзает PDO

    PHP:
    1. <?
    2. set_include_path(get_include_path().PATH_SEPARATOR.'/path/to/Modules');
    3. require_once 'Init.php';
    4. Configuration::GetInstance()->set(
    5.    'DataBase',
    6.    array('dns'=>'pgsql:host=localhost;port=5432;dbname=test', 'user'=>'test', 'password'=>'test')
    7. );
    8. ORM::Init();
    9.  
    10. // поехали!
    11.  
     
  24. Psih

    Psih Активный пользователь
    Команда форума Модератор

    С нами с:
    28 дек 2006
    Сообщения:
    2.678
    Симпатии:
    5
    Адрес:
    Рига, Латвия
    Ключевое слово Doctrine - на данный момент большинство сходиться во мнении, что это лучшая реализация ORM для PHP

    З.Ы. Мотороллер не мой - я просто разместил объяву
     
  25. sword dancer

    sword dancer Активный пользователь

    С нами с:
    17 фев 2008
    Сообщения:
    295
    Симпатии:
    0
    +1 за сырой sql + хелперы

    ну так и используй этот универсальный синтаксис :)