Написание функции, которая преобразует строки результата SQL в объект - PullRequest
1 голос
/ 19 июля 2011

Предположим, у меня есть схема базы данных, подобная этой:

http://img98.imageshack.us/img98/786/samplequ.png

Я использую следующий SQL, чтобы выбрать все строки из таблицы customer , а также всесвязанные строки:

SELECT c.*,
cty.id AS country__id, cty.name AS country__name,
o.id AS order__id, o.date AS order__date, o.total AS order__total,
ol.id AS order__orderline__id, ol.quantity AS order__orderline__quantity, ol.sub_total AS order__orderline__sub_total,
p.id AS order__orderline__product__id, p.name AS order__orderline__product__name, p.price AS order__orderline__product__price,
s.id AS order__shop__id, s.name AS order__shop__name
FROM customer c
JOIN country cty ON cty.id=c.country_id
JOIN order o ON o.customer_id=c.id
JOIN shop s ON s.id=o.shop_id
JOIN orderline ol ON ol.order_id=o.id
JOIN product p ON ol.product_id=p.id
ORDER BY
c.last_name ASC,
c.first_name ASC,
o.date DESC,
ol.id ASC

Вы можете видеть, что, несмотря на столбцы из таблицы customer , все остальные столбцы используют псевдоним, который отражает его отношение, которое можно использовать для создания объекта.Двойные подчеркивания в псевдониме используются для идентификации иерархии отношений.

Я хотел бы написать функцию PHP, которая принимает строки результата и возвращает массив объектов Customer .Эти Customer объекты должны быть загружены с другими связанными объектами:

$customers=convert_result_rows_to_objects($result_rows,'Customer');
foreach($customers as $cust){
 echo $cust->id;
 echo $cust->get_full_name();
 echo $cust->country->name;
 foreach($cust->orders as $o){
  echo $o->id;
  echo $o->date;
  echo $o->shop->name;
  foreach($o->orderlines as $ol){
   echo $ol->product->name
   echo $ol->quantity;
   echo $ol->sub_total;
  }
  echo $o->total;
 }
}

Я уже написал модели для каждой таблицы базы данных, например:

class Customer{
 public function get_full_name(){...}
}

Длядля простоты я игнорирую методы получения и установки для всех других полей.

Но как мне написать convert_result_rows_to_objects функцию?

Я не хочу использоватьORM еще нет.

Теперь у меня в мозгу есть функция, которая должна выглядеть следующим образом:

function convert_result_rows_to_objects($result_rows, $main_class_name){

    $main_objs = array(); //containing the main objects to be returned, customer objects in my example
    $main_obj = NULL;
    $previous_row = NULL;
    $next_row = NULL;

    for($i = 0; $i<count($result_rows); $i++){

        $previous_row = ($i > 0 ? ($result_rows[$i - 1]) : NULL);
        $this_row = $result_rows[$i];
        $next_row = $i === ( count($result_rows) - 1) ? NULL : ($result_rows[$i + 1]);

        if ($previous_row === NULL || $previous_row->id !== $this_row->id) {
            $main_obj = new $main_class_name(); //create the main object  

        //what should be done next?

    }
}

Ответы [ 3 ]

3 голосов
/ 19 июля 2011

РЕДАКТИРОВАТЬ: Одна вещь, которую я не указал в исходном посте, это то, что я использую представление, чтобы собрать все соответствующие столбцы вместе. Пример кода не особо выделяет его, но если вы создаете представление, которое объединяет все, что вы хотите, то вы можете создать модель, основанную на этом, и запрос, а также модель будут очень простыми. / EDIT

Это не так уж сложно. Вы должны убедиться, что ваш класс модели выглядит как строка вашей базы данных, в противном случае вам придется выполнять сопоставление вручную. У меня есть базовый класс для моей модели базы данных, который выглядит следующим образом:

class Ashurex_Model
{
    public function __construct($args = null)
    {
        if(is_array($args))
        {
            $this->setOptions($args);
        }
    }

    // Magic setter changes user_id to setUserId
    public function __set($name, $value)
    {
        $method = 'set' . Ashurex_Utilities::underscoreToCamelCase($name);
        if (method_exists($this, $method))
        {
            $this->$method($value);
        }
    }

    // Magic getter changes user_id to getUserId
    public function __get($name)
    {
        $method = 'get' . Ashurex_Utilities::underscoreToCamelCase($name);
        if (method_exists($this, $method))
        {
            return $this->$method();
        }
    }

    public function __call($name, $args)
    {
        if (method_exists($this, $name))
        {
            return call_user_func_array(array($this, $name), $args);
        }
    }

    // Used for initializing an object off the database row
    // transforms all the row names (like user_id to UserId)
    // from underscores to camel case
    protected function setOptions(array $options)
    {
        foreach($options as $key => $value)
        {
            $this->__set($key,$value);
        }
        return $this;
    }
}

Пример пользовательского класса будет выглядеть так:

class Ashurex_Model_User extends Ashurex_Model
{
    protected $_id;
    protected $_username;
    protected $_userpass;
    protected $_firstName;

    { ... }

    public function getId(){ return $this->_id; }
    public function getUsername(){ return $this->_username; }
    public function getUserpass(){ return $this->_userpass; }
    public function getFirstName(){ return $this->_firstName; }

    { ... }

    public function setId($id){ $this->_id = $id; }
    public function setUsername($username){ $this->_username = $username; }
    public function setUserpass($password){ $this->_userpass = $password; }
    public function setFirstName($firstName){ $this->_firstName = $firstName; }

    { ... }

    // This function will help when automatically saving the object back to the database
    // The array keys must be named exactly what the database columns are called
    public function toArray()
    {
        $data = array(
            'id'                    => $this->getId(),
            'username'              => $this->getUsername(),
            'userpass'              => $this->getUserpass(),
            'first_name'            => $this->getFirstName(),
            { ... }
        );

        return $data;
    }
}

Таблица базы данных выглядит следующим образом:

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(64) NOT NULL,
  `userpass` varchar(160) NOT NULL,
  `first_name` varchar(64) NOT NULL,
  `last_name` varchar(64) NOT NULL,
  `email` varchar(64) NOT NULL,
  `role_id` tinyint(4) NOT NULL,
  `is_active` tinyint(1) NOT NULL DEFAULT '1',
  `force_password_change` tinyint(1) NOT NULL DEFAULT '0',
  `creation_datetime` datetime NOT NULL,
  `updated_datetime` datetime NOT NULL,
  `user_salt` varchar(32) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`),
  KEY `role_id` (`role_id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Как видите, наиболее важным аспектом является то, что вы называете столбцы соответствующим образом, чтобы ваш базовый класс модели мог "автоматически" сопоставить имя столбца с методом.

Наконец, вот как будет выглядеть код сохранения ...

public function save(Ashurex_Model $obj)
    {
        try
        {
            $data = $obj->toArray();
                    // If no id is set, we are inserting a new row
            if(null === ($id = $data['id']))
            {
                unset($data['id']);
                $this->getDbTable()->insert($data);
                return $this->getDb()->lastInsertId();
            }
            else
            {
                            // We have an Id, do an update
                $where = $this->getDbTable()->getAdapter()->quoteInto('id = ?',array($id));
                $this->getDbTable()->update($data,$where);
                return $id;
            }
        }
        catch(Exception $e)
        {
            self::logException(__METHOD__,$e);
        }
        return false;
    }

Пример кода поиска выглядит следующим образом, поскольку вы можете видеть, что он инициализирует новый объект прямо из строки результатов базы данных на основе имен столбцов:

public function find($id)
    {
        try
        {
            $table = $this->getDbView();
            $stmt = $table->select()
                        ->where('id = ?')
                        ->bind(array($id));

            $row = $table->fetchRow($stmt);
            if(!is_null($row))
            {
                $r = $row->toArray();
                $obj = new Ashurex_Model_User($r);
                return $obj;
            }
            else
            {
                return null;
            }
        }
        catch(Exception $ex)
        {
            self::logException(__METHOD__,$ex);
            return null;
        }
    }
2 голосов
/ 19 июля 2011

РЕДАКТИРОВАТЬ:

Извините, я не обратил внимания, когда вы сказали, что у вас уже есть модель.Во-первых, для заполнения объектов вам нужно идентифицировать поля (конечно).Поскольку у вас есть префикс, вы можете использовать strstr или strpos для поиска идентификатора объекта (каждого из них), и они получают имя поля, используя substr .Тогда вы готовы заселить объекты.Если вы хотите, чтобы он был действительно универсальным, вам нужно разбить поля на двойные подчеркивания и динамически создавать объекты.

Было бы неплохо, если бы вы могли показать пример возвращаемых данных.

1 голос
/ 19 июля 2011

Уверен, что интересующую вас информацию можно найти здесь: http://php.net/manual/en/book.reflection.php

Я считаю, что при прохождении всех граничных случаев мы обнаружим немного странности в отображении столбцов базы данных в методы получения / установки, избегая загрузки всей базы данных при запуске и т. Д., В итоге вы создадите ORM.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...