Как лучше всего построить мою модель? - PullRequest
1 голос
/ 07 июля 2010

В настоящее время я перестраиваю приложение администратора и ищу ваши рекомендации для лучшей практики! Извините, если у меня нет правильной терминологии, но как мне поступить следующим образом?

Возьмем пример «пользователей» - обычно мы можем создать класс со свойствами, такими как «имя», «имя пользователя», «пароль» и т. Д., И создать несколько методов, таких как getUser($user_ID), getAllUsers() и т. Д. В в конце мы получаем массив / массивы пар имя-значение, например; array('name' => 'Joe Bloggs', 'username' => 'joe_90', 'password' => '123456', etc).

Проблема в том, что я хочу, чтобы этот объект знал больше о каждом из его свойств.

Рассмотрим "имя пользователя" - в дополнение к знанию его значения я хочу, чтобы объект знал такие вещи, как; какая текстовая метка должна отображаться рядом с элементом управления в форме, какое регулярное выражение я должен использовать при проверке, какое сообщение об ошибке подходит? Эти вещи, кажется, принадлежат модели.

Чем больше я работаю над проблемой, тем больше я вижу и другие вещи; какой элемент HTML следует использовать для отображения этого свойства, каковы минимальные / максимальные значения для таких свойств, как 'registration_date'?

Я предполагал, что класс будет выглядеть примерно так (упрощенно):

class User {
    ...etc...
    private static $model = array();
    ...etc...
    function __construct(){
        ...etc...
        $this->model['username']['value'] = NULL; // A default value used for new objects.
        $this->model['username']['label'] = dictionary::lookup('username'); // Displayed on the HTML form. Actual string comes from a translation database.
        $this->model['username']['regex'] = '/^[0-9a-z_]{4,64}$/i'; // Used for both client-side validation and backend validation/sanitising;
        $this->model['username']['HTML'] = 'text'; // Which type of HTML control should be used to interact with this property.
        ...etc...
        $this->model['registration_date']['value'] = 'now'; // Default value
        $this->model['registration_date']['label'] = dictionary::lookup('registration_date');
        $this->model['registration_date']['minimum'] = '2007-06-05'; // These values could be set by a permissions/override object.
        $this->model['registration_date']['maximum'] = '+1 week';
        $this->model['registration_date']['HTML'] = 'datepicker';
        ...etc...
    }
    ...etc...
    function getUser($user_ID){
        ...etc...
        // getUser pulls the real data from the database and overwrites the default value for that property.
        return $this->model;
    }
}

По сути, я хочу, чтобы эта информация находилась в одном месте, чтобы мне не приходилось дублировать код для разметки HTML, процедур проверки и т. Д. Идея состоит в том, что я могу передать пользовательский массив в помощник формы HTML и иметь он автоматически создает форму, элементы управления и проверку JavaScript.

Затем я мог бы использовать тот же объект в бэкэнде с общим методом set($data = array(), $model = array()), чтобы избежать использования отдельных методов, таких как setUsername($username), setRegistrationDate($registration_date) и т. Д. *

  • Кажется ли это разумным подходом?
  • Как бы вы назвали значение, метку, регулярное выражение и т. Д.? Свойства свойств? Атрибуты
  • Использование $this->model в getUser() означает, что объектная модель перезаписана, тогда как было бы лучше сохранить модель в качестве прототипа и иметь getUser() наследовать свойства.
  • Мне не хватает какого-то отраслевого стандартного способа сделать это? (Я прошел через все фреймворки - пример моделей всегда отсутствует !!!)
  • Как масштабируется, когда, например, я хочу отображать пользовательские типы с помощью SELECT со значениями из другой модели?

Спасибо!

Обновление

С тех пор я узнал, что в Java есть аннотации классов - http://en.wikipedia.org/wiki/Java_annotations - которые, похоже, более или менее соответствуют тому, что я просил. Я нашел этот пост - http://interfacelab.com/metadataattributes-in-php - есть ли у кого-нибудь понимание программирования, как это?

Ответы [ 4 ]

3 голосов
/ 07 июля 2010

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

Ваша модель может быть непосредственно Active Record , возможно шлюз данных строки таблицы или «POPO», обычный старый объект PHP (другими словами, класс, который не реализует какой-либо конкретный шаблон).такие вещи, как проверка и т. д., могут быть помещены в класс модели.Вы должны иметь возможность работать со своими пользователями как с объектами пользователя, а не как с ассоциативными массивами - это главное.

Кажется ли это разумным подходом

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

Как бы я подошел к этому (предложение)

Я бы хотелПользовательский объект, который представляет одного пользователя.Должна быть возможность создать пустого пользователя или создать его из массива (чтобы, например, было легко создать его из результата базы данных).Пользовательский объект также должен быть способен сам себя проверять, например, вы можете дать ему метод isValid, который при вызове проверит все значения на достоверность.

Кроме того, у меня был бы класс репозитория пользователей (или, возможно, просто некоторые статические методы класса User), который можно было бы использовать для извлечения пользователей из базы данных и их сохранения.Этот репозиторий будет напрямую возвращать пользовательские объекты при извлечении и принимать пользовательские объекты в качестве параметров для сохранения.

Что касается форм, вы, вероятно, могли бы иметь класс формы, который принимает пользовательский объект.Затем он может автоматически получать значения от пользователя и использовать его для проверки себя.

Я написал немного по этой теме здесь: http://codeutopia.net/blog/2009/02/28/creating-a-simple-abstract-model-to-reduce-boilerplate-code/, а также некоторые другие сообщения, связанные в концетот.

Надеюсь, это поможет.Я просто хотел бы напомнить, что мой подход тоже не идеален =)

2 голосов
/ 07 июля 2010

Абстрактный ответ для вас, который, возможно, совсем не поможет, но я рад получить отрицательные голоса, как это стоит сказать:)

Вы имеете здесь дело с двумя разными моделями,в каком-то мире мы называем их Классом и Экземпляром, в других мы говорим о Классах и Индивидуумах, а в других мирах мы различаем операторы A-Box и T-Box.

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

User a Class .
username a Property;
  domain User;
  range String .
registration_date a Property;
  domain User;
  range Date .

это ваши данные класса, операторы T-Box, чертежи, как вы описываете юниверс, который является вашим приложением - это не описание«вещи» в вашей вселенной, скорее вы используете это для описания вещей в вашей вселенной, данных вашего экземпляра… так что тогда у вас есть:

user1 a User ;
  username "bob";
  registration_date "2010-07-02" .

, который является вашим экземпляром, индивидуальным, данными A-Boxвещи в вашей вселенной.

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

username a Property;
  domain User;
  range String;
  title "Username";
  validation [ type Regex; value '/^[0-9a-z_]{4,64}$/i' ] .

Смысл всего этого в том, чтобы помочь вам проанализировать другие ответы, которые вы получите - вы заметите, что вВаше предположение, что вы объединили эти два разных набора данных вместе, и, в некотором смысле, это хорошо - из этого, мы надеемся, вы увидите, что обычно классы в PHP играют роль классов (неудивительно) и каждого объекта (или экземпляраclass) содержит данные отдельного экземпляра - однако вы начали объединять эти две части своей вселенной, чтобы попытаться создать один большой набор классов для повторного использования вне предоставленных языковых конструкций PHP.

Отсюдау вас есть два пути, вы можете либо сложить в строку и следовать структуре языка, чтобы сделать ваш код частично пригодным для повторного использования, и следовать предлагаемым шаблонам, таким как MVC (что, если вы не сделали, вам хорошо), или вы можете перейти культрасовременный мир, в котором описываются эти миры, и мы создаем рамки для понимания данныхНаши вселенные и все, что в них есть, но это абстрактное место, где в данный момент трудно быть продуктивным, хотя в долгосрочной перспективе это путь в будущее.

Несмотря на это, я надеюсь, что в некотором родеэто поможет вам понять другие ответы.

Всего наилучшего!

1 голос
/ 07 июля 2010

Посмотрев на ваш вопрос, ответы и ваши ответы;Я мог бы помочь немного больше здесь (хотя трудно охватить все в одном ответе).

Я вижу, что вы хотите здесь сделать, и, честно говоря, именно так начинается большинство фреймворков.из;делая набор классов для обработки всего, затем, когда они становятся более многократно используемыми, они часто используют проверенные и протестированные шаблоны, пока, наконец, не получат то, что я бы сказал, «просто еще один фреймворк», все они делают почти одно и то же,во многом таким же образом, и стремятся быть максимально пригодными для повторного использования - как правило, единственное различие между ними заключается в стилях кодирования и качестве - то, что они делают, в значительной степени одинаково для всех.

Я верю вамЗдесь мы расскажем вам о небольшом количестве анти-паттернов в вашем дизайне. Вы сосредоточены на том, чтобы сделать большой кусок кода для повторного использования, проверки, презентации и т. д. - но то, что вы на самом деле делаете (иконечно, без обид) делает рабочий код приложения очень специфичным для домена, и не только это, но и дизайн, который вы иллюстрируете, сделает практически невозможным расширение, изменение слоев (например, создание мобильной версии), обмен технологиями (например, swap dbпоставщики) и еще дальше, потому что у вас есть презентация и приложение (d) данные, смешанные воедино, любой дизайнер, работающий с этим приложением, должен будет работать над ним и изменять код приложения - ударить в то время, когда у вас есть две версии приложения и вы столкнулись с большой беспорядочной проблемой.

Как и в большинстве задач программирования, вы можете решить эту проблему, выполнив три вещи:

  1. проектирование модели предметной области.
  2. указание и проектирование интерфейсов, а не беспокойство ореализация.
  3. разделение сквозных задач

Разработка модели предметной области - очень важная часть OO-программирования на основе классов, если вы никогда не делали этого раньше, то сейчас идеальное время, не имеет значения, делаете ли вы это на языке моделирования, таком как UML, или просто в простом тексте, идея состоит в том, чтобы определить все сущности в вашем домене, при обсуждении этого легко перейти к написанию книги, но давайте продолжимэто просто.Ваша доменная модель включает в себя все сущности в домене вашего приложения, каждая сущность - это вещь, например, пользователь, адрес, статья, продукт и т. Д., Каждая сущность обычно определяется как класс (который является образцом этой сущности) и каждый классимеет свойства (например, username, register_date и т. д.).

Class User {
  public $username;
  public $register_date;
}

Часто мы можем хранить их как POPO, однако их часто лучше рассматривать как объекты переноса (часто называемые объектами передачи данных, объектами значений) - простойКлассовая схема объекта в вашем домене - обычно мы стараемся сохранять их переносимыми, чтобы они могли быть реализованы на любом языке, передаваться между приложениями, сериализироваться и отправляться в другие приложения и т. П. - это на самом деле не обязательноничто не является обязательным - но оно затрагивает разделение интересов в том смысле, что оно обычно было бы голым, не подразумевало бы никакой функциональности, просто план хранения значений.Резкий контраст с бизнес-объектами и служебными классами, которые на самом деле «делают» вещи, являются реализациями функциональности, а не просто держателями значений.

Не обманывайте себя, и наследование, и композиция также играют свою роль в модели предметной областиПользователь может иметь несколько адресов, каждый адрес может быть адресом нескольких разных пользователей.BillingAddress может расширять обычный адрес и добавлять дополнительные свойства и так далее.(в сторону: что такое пользователь? у вас есть пользователь? у вас есть человек с 1- * учетными записями пользователей?).

После того, как вы получили модель вашего домена, следующим шагом, как правило, является сопоставление того или иного уровня персистентности (обычно с базой данных) двумя распространенными способами сделать это (четко определенным образом) с помощью ORM (например,как доктрина, которая в симфонии, если я правильно помню), и другой способ - использовать шаблон DAO - я оставлю эту часть там, но обычно это отдельная часть системы, слои DAO у вас есть преимущество в том, что вы указываете все методы, доступные для работы со слоем постоянства для каждой сущности, при этом сохраняя реализацию абстрагированной, таким образом вы можете менять поставщиков базы данных без изменения кода приложения (или, как говорят многие бизнес-правила).

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

Чтобы проиллюстрировать интерфейсы, вы можете просто определитьИнтерфейс для всех ваших сущностей, который выглядит примерно так:

Interface Validatable {
  function isValid();
}

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

Class User implements Validatable {
  public function isValid()
  {
    // custom validation here
    return $boolean;
  }
}

Теперь вы этого не делаетевам нужно беспокоиться о создании какого-то сложного способа проверки объектов, вы можете просто вызвать isValid () для любой сущности и выяснить, действителен ли он или нет.

Самое важное, на что нужно обратить внимание, - это определить интерфейс,мы разделили некоторые проблемы, поскольку никакой другой части приложения не нужно ничего делать для проверки объекта, все, что им нужно знать, это то, что это Validatable и вызывать метод isValid ().

Тем не менее, мы столкнулись с некоторыми проблемами в том, что каждый объект (экземпляр класса) теперь имеет свои собственные правила проверки и модель.Возможно, имеет смысл абстрагироваться от этого, один простой способ сделать это состоит в том, чтобы сделать метод проверки статическим, чтобы вы могли определить:

Class User {
  public static function validate(User $user)
  {
    // custom validation here
    return $boolean;
  }
}

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

Или, возможно, вы перемещаете проверку в свою собственную библиотеку?Класс Validate с его собственными методами, или, может быть, вы просто добавляете его в слой DAO, потому что вам нужно только проверять что-то, когда вы сохраняете его, или, возможно, вам нужно проверять, когда вы получаете данные и когда вы сохраняете их - как вы в конечном итоге делаетеэто ваш призыв, и нет «лучшего пути».

Третье соображение, которое я уже затронул, - это разделение интересов - должен ли слой постоянства заботиться о том, как представлены вещи, которые он сохраняет?должна ли бизнес-логика заботиться о том, как вещи представлены?должна ли организация заботиться о том, где и как она отображается?или уровень представления должен заботиться, как вещи представлены?Точно так же мы можем спросить, будет ли когда-либо только один уровень представления?на одном языке?Как насчет того, как метка появляется в предложении, конечно, отдельные пользователи и адреса имеют смысл, но вы не можете просто + s, чтобы показать списки, потому что пользователи правы, а адреса неправильны;) - также у нас есть рабочие соображения, как я хочуновый дизайнер должен изменить код приложения, просто чтобы изменить представление «учетной записи пользователя» на «учетную запись пользователя», даже если я хочу изменить код приложения в классах, когда запрашивается это изменение?

Наконец, и просто для того, чтобы бросить все, что я сказал - вы должны спросить себя, какую работу я пытаюсь сделать здесь?я создаю большое многократно используемое приложение с потенциально большим количеством разработчиков и длинным жизненным циклом здесь - или достаточно простого php-скрипта для каждого представления и действия (тот, который читает $ _GET / $ _ POST, проверяет, сохраняет в db, затем отображает то, что долженили перенаправляет туда, куда следует) - во многих, если не во всех случаях, это все, что нужно.

Помните, что PHP вызывается, когда на веб-сервер делается запрос, а затем отправляет ответ [конец], вот и все, что происходит между тем, когда ваш домен, ваша работа, клиент и пользователь обычно не ' Это не важно, и вы можете подытожить, что вы пытаетесь сделать, просто: создайте сценарий, чтобы ответить на этот запрос как можно быстрее, с ожидаемыми результатами. Вот и все не должно быть сложнее.

Быть тупым, делать все, что я упомянул и многое другое - это отличная вещь, вы будете учиться много, лучше понимать свою работу и т. Д., Но если вы просто хотите получить работу за дверью и ее легко поддерживать простым код в конце, просто создайте один сценарий для каждого просмотра и один для каждого действия с нечетным повторно используемым битом (например, обработчик http, класс db, класс электронной почты и т. д.).

0 голосов
/ 07 июля 2010

Вы работаете в архитектуре Model-View-Controller (MVC).

M хранит только данные.Нет отображаемой информации, просто набрал пары ключ-значение.

C обрабатывает логику манипулирования этой информацией.Это изменяет M в ответ на пользовательский ввод.

V - это часть, которая обрабатывает отображение вещей.Это должно быть что-то вроде шаблонов Smarty, а не огромное количество необработанного PHP для генерации HTML.

Использование всего этого «в одном месте» - неправильный подход.У вас не будет дублированного кода с MVC - каждая часть - это отдельный шаг.Это улучшает повторное использование кода, удобочитаемость и удобство обслуживания.

...