Самописный MVC

Vano

Новичок
Столкнулся с проблемой понимания логики Active Record.
Хочу реализовать круд команды как в YII. Имеется в виду чтобы мог в контроллере
как искать записи -
PHP:
$Test = TestModel::model()->findByPK( 5 );
так и создавать -
PHP:
$Test = new TestModel();
                                 $Test -> title = 'Тайтл';
                                 $Test -> save();
Может кто знает как устроена структура наследований классов в YII для реализации этой задачи. Ато у меня получается либо создание либо поиск(одно из двух).
Мозги уже не варят понять еще большую структуру наследований просто по коду.

Подскажите кто знает, пожалуйста.
 

fixxxer

К.О.
Партнер клуба
В простейшем случае, когда методы типа findByPk всегда находят ровно 0 или 1 запись, - банально:

$Test = (new TestModel)->findByPk(5); // - находит, загружает в себя, и возвращает $this. Если не найдено - смотри как удобнее, можно вернуть null, а можно тоже $this и потом проверять что-то вроде $Test->isLoaded()

Как более универсальный вариант (в случае когда неизвестно что вернем - модель или коллекцию) - TestModel::findByPk и LSB (static::, get_called_class), создаем new $called_class и то же самое.

Вызов вида TestModel::model()->... нужен для чейнинга вызовов, тут уже сам смотри, надо ли оно тебе. Я не смотрел код, но, очевидно, model() возвращает некую собиралку параметров запроса, в которую сеттеры собирают контекст, а конкретный find-метод выполняется с учетом собранного контекста.

Ну а когда получили инстанс модели дальше то просто

$Test->title = 'New Title';
$Test->save(); // обновляем

С инсертом - то же самое: $Test видит, что у него не установлен PK, и делает insert, а не update.

В случае с коллекциями, которые неизбежно придется ввести для методов типа findByNonUniqueValue(), можно, например, возвращать банальный массив моделей. Я предпочитаю возвращать специальную итерабельную коллекцию, которая умеет лениво создавать модели при итерации - но это уже оптимизация.
 
Последнее редактирование:

Vano

Новичок
В общем суть в том, что я не понимал как вот это $Test = TestModel::model( ) -> findByPK(6); создавало обьект класса TestModel на ряду с вот этим $Test = new TestModel;
 

Василий М.

Новичок
и вообще AR - зло
используй DataMapper, т.е. разделяй слой работы с базой и объект бизнес-логики
 

Vano

Новичок
Получилось так (хотя не знаю, правильный ли подход - наверняка нет)):
<?php
//Home контроллер

Код:
class HomeController extends Controller
{

   
  public function actionIndex()
  {
    echo '<pre>';   

  $page = new HomeModel;
      print_r($page);
  $page->title = 'НюТайтл';
      print_r($page);
   
   
  $page2 = HomeModel::model()->findByPK(6);
      print_r($page2);
  $page2->title = 'Тайтл токошо';
      print_r($page2);
   
   
  }
    
}

?>

Дальше Home model:


Код:
<?php
class HomeModel extends MainModel
{
 
  public static function model($className=__CLASS__)
  {
   
    return parent::model($className);
 
  }
 
  public function tableName()
  {
 
  return 'page_table';
 
  }
 
}
?>

И вот главный файл траты 5 часов) (Типа АктивРекорд убогий):

Код:
<?php

class MainModel
{
  private static $object;
   
  public $attributes;
   
   
  function __set($name, $value)
  {
   
  $this->attributes[$name] = $value;
   
  }
   
  function __get($name)
  {
   
  return $this->attributes[$name];
   
  }
   
   
   
  public function __construct()
  {
   
  //echo $this->tableName();
  $this->attributes['title'] = null;
   
  }
   
   
   
  public static function model($className)
  {
   
  self::$object = new $className;
  return self::$object;
   
  }
   
   
   
  public function findByPK($pk)
  {
   
  $this->title = 'тайтл с файндбая';
  return self::$object;
   
  }
   
}




?>
 

Vano

Новичок
И так ИТОГ:
Этот скрипт может быть как продолжение изучения MVC схемы на практике которое я и сам прошел - http://habrahabr.ru/post/150267/
Что я могу сказать, может кому пригодится, забивайте на эту хрень - сами не напишете хороший актив рекорд, а юзайте готовый типа этого - http://www.phpactiverecord.org/
 

Vano

Новичок
говнокод какой-то
должно быть так: TestModel::findByPK(6);
та может и говнокод) но я пытался сделать чтобы выглядело красиво как в YII, не зная алгоритма. Скорее всего я и не повторил алгоритм, но с виду хотябы работает так же)
 

AmdY

Пью пиво
Команда форума
Vano, ты смешал в всё кучу.
У тебя есть модель.
PHP:
class FooModel extends \Model
{
    public function __construct($attributes = [])
    {
        $this->attributes = $attributes;
    }
}
методы для извлечения данных можешь рассматривать в контексте отдельно от модели, важно лишь то, что полученные данные ты передаёшь в эту модель. эти методы можно реализовывать как внутри класса Model, так и вынести в отельный класс, обозвав его репозиторием или дата мэппером.
PHP:
class Model
{
    public static function find($id)
    {
        $class = get_called_class(); // резолвиш имя класса и таблицы
        $table = $class;
        $data = Db::fetchOne('SELECT * FROM ' . $table); достал данные
        return new $class($data); // отдал данные в модель
    }
}
 

shelestov

я тут часто
В общем суть в том, что я не понимал как вот это $Test = TestModel::model( ) -> findByPK(6); создавало обьект класса TestModel на ряду с вот этим $Test = new TestModel;
Ну так это синглтон с публичным контроллером. ))
Правда объекты всех моделей в yii хранятся в статической переменной в классе CActiveRecord, а не в самом классе модели.
Так же в Yii нужно переопределять метод model в каждой моделе, если писать под 5.3 и выше, можно обойтись без этого:
http://php.net/manual/ru/language.oop5.late-static-bindings.php
http://us2.php.net/manual/ru/function.get-called-class.php
 
Последнее редактирование:

shelestov

я тут часто
не не скажи, сингл это один единственный а за статикой может легко прятаться по обьекту на вызов
Может, но в Yii синглтон. )
PHP:
public static function model($className=__CLASS__)
    {
        if(isset(self::$_models[$className]))
            return self::$_models[$className];
        else
        {
            $model=self::$_models[$className]=new $className(null);
            $model->_md=new CActiveRecordMetaData($model);
            $model->attachBehaviors($model->behaviors());
            return $model;
        }
    }
 

WMix

герр M:)ller
Партнер клуба
даже в этом случае по инстанции на $className
Сингулярность не допускает размножение агентов смитов в программе ;)
 

shelestov

я тут часто
даже в этом случае по инстанции на $className
Да. Это код из CActiveRecord. $models хранит инстанс для каждой вызванной модели.
Т.е. для конкретной модели инстанс один.
Я называл "синглтон с публичным конструктором" именно конечную модель.
Внешне это как бы так и есть.
 

WMix

герр M:)ller
Партнер клуба
а вот еслиб этот метод возвращал всегда один и тотже обьект некий model?
 
Сверху