= Models = Models make up the data access layer of Maveric. Maveric implements ORM and the Active Record design pattern, and is heavily influenced by the Ruby on Rails implementation. Models should extend the {{{Model}}} class to take advantage of these built-in features. Each model should correspond to a database table, and each instance of that model will correspond to a row in that table. == Basic Example == Let's say we have a table called 'users', with the following structure: ||'''id'''||'''username'''||'''password'''|| All we need to do to create our User model is create a file called {{{User.php}}} in the {{{models/}}} directory, and create a class that extends {{{Model}}}: {{{ #!php username; // echos "john" }}} == Creating Tables == Every table with a corresponding model must have a primary, auto-increment key named {{{id}}}. There is special handling for columns named {{{created}}} and {{{updated}}} and there are general rules for foreign key names, but other than that, any other columns you create will simply be accessible as object properties. Tables should generally be the plural form of whatever data they store. For example, a table of users would be {{{users}}}. A table storing order data would probably be called {{{orders}}}. If you need to deviate from this convention, you can explicitly set the name for the table like so: {{{ #!php _id", which would point to the table's primary {{{id}}} field. For example, if we had a table of comments that linked to their respective authors (in the users table), by convention you should name the foreign key field {{{user_id}}}. Foreign keys are also subject to special handling, and should be integers. == Relationships to Other Models == Very commonly, a table will have relationships to other tables. On a blog, users, for example, may have created many comments on many different posts, which may each have many different tags. Here we see several relationships: {{{ __User__ / \ / \ has_many has_many / \ / \ \/ \/ Comments <-has_many- Posts / /\ / \ has_many has_many \ / \/_ __/ Tags }}} A User object has between zero and infinity Comment objects, and between zero and infinity Post objects associated with it. A Post has between zero and infinity Comments associated with it. A Post is also associated with zero, one, or many Tags, which, in turn, are associated with zero, one, or many Posts. The reciprocal of {{{has_many}}} is the {{{belongs_to}}} relationship. A Comment "belongs to" a User in the sense that a User created it. A Comment "belongs to" a Post in the sense that the Comment only makes sense in the context of that Post. The relationship between Posts and Tags is fully reciprocal, that is, you cannot easily decide one "owns" another. All of the relationships are trivially easy to implement in Maveric. === has_one, has_many, & belongs_to === A brief example: {{{ #!php Recent Comments }}} As you can see, by defining only the relationship in the class, we can then access the parent, or child, object(s) by name through the original object. These related objects are only loaded when needed, so you don't need to worry about a loop causing infinite database queries. These relationships can be defined simply, as array entries, or more carefully, as array key-value pairs. ==== has_many ==== When an object can "own" zero to multiple child objects, {{{has_many}}} is the correct relationship. An example is the User object, above, which {{{has_many}}} Posts and Comments. In the example above, the child model was named Comment, the table was "comments", and the comments table had a foreign key named "user_id", so all we needed to do was add 'comments' to the {{{$has_many}}} array. But what if the comments table's foreign key field was named "author_id"? This is certainly possible. There are two ways we can handle this: {{{ #!php array( 'model' => 'user' ) ); } }}} By defining the {{{Comment->author}}} property, Maveric will look for an {{{author_id}}} field, instead of the usual {{{user_id}}} field, but associate it with a User object. We can use this method to rename a related object, which is useful if two objects of the same type may be related, but for different reasons. (For example, an author and an editor.) In this case, the name of the author of the comment could be referenced by {{{$comment->author->username}}}. We could also change the {{{foreign_key}}} property: {{{ #!php array( 'foreign_key' => 'author_id' ) ); } }}} This method just tells Maveric to look for a different column name, but keep the name 'user' and type User for the related object. In this case, the name of the comment author would be in {{{$comment->user->username}}}. In either case, we will need to modify the User model slightly to tell Maveric to check the right field: {{{ #!php array( 'foreign_key' => 'author_id' ) ); } }}} Finally, what if the comment foreign key is called {{{user_id}}}, but we want to refer to the {{{author}}} property? Then we '''only''' need to modify the Comment model: {{{ #!php array( 'model'=>'user', 'foreign_key'=>'user_id' ) ); } }}} ==== has_one ==== {{{has_one}}} is identical to {{{has_many}}}, except that instead of a (possibly empty) array of objects, you get a single object. When adding values to the {{{$has_one}}} array, they should be singular. {{{ #!php profile}}} will give you access to the associated Profile object. (And {{{$profile->user}}} would give us access to the user, again.) ==== has_one or belongs_to ==== What's the difference between {{{has_one}}} and {{{belongs_to}}}? Practically, the location of the foreign key. If a table has a foreign key, the model should have a {{{$belongs_to}}} entry. If the foreign key is in another table, then the model should have a {{{$has_one}}} entry. === has_and_belongs_to_many === {{{has_and_belongs_to_many}}} describes a many-to-many relationship, where the other relationships are one-to-one or one-to-many. Neither object could be said to properly "own" the other, and neither table has a foreign key for the other. In this case, you'll be using a join table. Let's look at the tables for Posts and Tags, from the blog example: posts: ||'''id'''||'''user_id'''||'''title'''||'''body'''||'''created'''|| tags: ||'''id'''||'''tag'''|| Since we have a many-to-many relationship, we'll be adding a join table: posts_tags: ||'''post_id'''||'''tag_id'''|| If the join table is named like {{{_}}}, where the tables are listed in alphabetical order, then we can be very lazy when building the models: {{{ #!php array( 'through' => 'p_t_join', 'key' => 'tag', 'foreign_key' => 'post' ) ); } // models/Post.php class Post extends Model { protected $has_and_belongs_to_many = array( 'tags' => array( 'through' => 'p_t_join', 'key' => 'post', 'foreign_key' => 'tag' ) ); } }}} Notice how the values of {{{key}}} and {{{foreign_key}}} depend on the current model.