Why active record sucks
Table of Contents
It is not really Active Record (AR) which sucks but the implied, perhaps just misinterpreted, common usage as an ORM (object relational mapping). To summarize the following blog post in one sentence, so that you may skip reading it:
Active Record may be used to implement ORM, but it should never be used as an ORM.
What is Active Record again?
Active Record (AR), Table Row Gateway, Table Data Gateway ... let's not difference between them, but just consider the concept of plain mapping of a row to an object with properties representing the columns of a table.
Of course you always have some mechanism which enables you to fetch the related contents depending on your ERM (entity relationship model). This may happen with explicit calls to fetch, let's say, the author of a news post, or a more advanced implementation of AR may even construct JOINS in the initial query to fetch all requested related data.
This sounds perfect to map my business objects to the database, or?
The basic model
Considering a very simple DB model AR may work for you. Let's consider the following structure for something like a very simple news system:
+-----------+
| Article |
+-----------+
| id | +--------+
| author_id | ---> | Author |
| title | +--------+
| text | | id |
+-----------+ | name |
| email |
+--------+For such a structure even AR fulfills all basic requirements for an ORM, when you extend the basic classes with some validations, which are not topic of this blog post.
Causing some trouble
Having a model and an easy to use interface which provide full access to the data, and abstracts away the SQL by generating the queries still seems a quite perfect solution - so let's introduce some requirements which are not properly realizable with Active Record. This is - of course - not a complete list, but very basic and quite common requirements for a data model.
Translation, Versioning and Status
A quite common requirement is translation of contents. In this case you want to add some key to your table containing the contents of your application which somehow maps to a language. The logical consequence is, that you get more then one article with the same value in the column 'id' and need to define a multi column index on the columns 'id' and '~language'.
If somebody is able to edit contents, which commonly will be true for articles managed by some web interface, you should introduce content versioning in your application, so that no content is lost, if somebody accidentally deleted some text or somebody abuses his rights to do bad stuff.
Here the same applies as for translation - you need an additional column representing the version and you get a three column primary index for your data.
I am not really sure if there are an AR implementation which handle the case of multi column indexes properly - if you know some please point me to them, but even if it is supported you end up with a messy table containing not normalized data, with duplicate titles, which are not required to store, if they did not change between two versions.
You may also have some other attributes like states ("published", "draft", ...) for your content which will pollute your table even more. State changes on one version of an article / in one row will result in the loss of change histories - and otherwise you might just need to copy the complete the contents of an article, because it has been published by the editor without any changes in an article draft...
Variants
Think of the case you do not only want to show articles on your website, but some other contents, like blog posts which also contain a list of tags or categories, perhaps you want to include project news which also contain some release information...
This will either mess up you basic table by adding optional attributes which destroys the semantic meaning of the table by containing completely different stuff, or you would need to add several new tables which will be aggregated into one list, sorted by some common criteria and handled by different views.
Now think of a online shop, or some other complex website, where you do not only have three types of contents, but hundreds or thousands - you may come up with the idea of serializing the content specific data in some way (XML, PHP specific stuff, JSON, ...), but you are not serious about that, are you? This would lead to a whole bunch of other problems like the requirement for specialized search engines, unnecessary parsing, using semantical information from the DB view...
Relations
A different requirement where AR fails totally used as an ORM are n:m relations with associated metadata. To stay with model introduced above you could imagine that you want to add references to existing articles in a new article you write - of course it should be a potentially finite count of article references. The metadata could be a description why you add this article as a reference, some date and / or link title - a table like this would be the result:
+----------------+
| reference |
+----------------+
| source_id |
| destination_id |
| title |
| description |
| date |
+----------------+In the optimal cases - the AR implementation automagically fetches the right articles for you - you would end up with an article object containing a bunch of objects with the reference metadata, each containing the destination article object.
But, from a business object point of view, there are two things wrong now with your data structure. You normally just some reference objects to render in a defined way in your views, and the articles of course should not be fetched multiple times, if one article references another one multiple times.
You can work with this case, you may be able to handle it properly in your views, but this won't be the data structure you probably would design when not having the database scheme in your mind - and letting the abstraction layer define you business object structure just is the wrong way to go.
Conclusion
The conclusion is simple:
You either destroy your business objects or your DB model.
This "OR" is not a "XOR" - you may even destroy both, just because you used the wrong tool for the right job - ORM per se is nothing bad. The above described examples force you to use hacks of a model which originally were thought to clean up your data storage system and offer a nice model. You may reach the opposite.
Proper ORM
As usually, doing something the proper way, it gets harder. I am sorry for this ;). And as always, there is no magic store, where you may just put your data, without thinking about your application and hope that everything works perfectly...
A trivial model
Let's take a look at one model which can map the above described problems - for now ignoring the relations. This is of course not the ultimate solution, but just an example. I will mention some of its weaknesses later.
Entity Relationship Model: Object Relation MappingThe model is structured in four table clusters.
Content class
The content class is the equivalence to some class definition in your object orientated code. It defines the structure of some content, which has been done in the AR example above by the SQL table. To define the content class for an article you create an entry in the table content_class with a well chosen name and create entries in the table content_class_attribute with the properties of your content class - title and text in the example above. Those attributes are of some attribute type which may be anything from string, text, date, integer up to complex data types like (multi) select boxes, geo information, models, images or something completely different.
Obviously you are then able to automagically create forms using various widgets (combinations) - but this is not really relevant when it comes to the data model.
Instance
Of course you should be able to have a finite count of instances (articles) of your content class (article). Those are stored once , with an optional name and a reference to the defining content class in the table content_object.
The real instances, beside the identifier, are the versions - if you want language and / or status aware - in the table content_object_version. The attributes data, which actually somehow defines the object, is stored content_object_data with the obvious references to the obvious tables. The version and object data tables are using a multi column index on version, language and id here.
Metadata
You see very few essential metadata in the example, like the language, status, creator and the creation date. The last two ones probably would better fir in some abstracted metadata storage extended by tags, ratings or whatever you want to add here. This is not really relevant.
Attributes
As written earlier you can easily generate forms (not only for (X)HTML) from those content class definitions, but you can also easily include descriptions, configurations of data types (with some default configuration options in the table attribute_type), which may define valid value ranges, limit the host for some URL or whatever you imagine.
If an attribute has not been changed in a new version of a content object you may automatically fetch it from earlier versions of the content objects without any real drawbacks, but this may result in more complex queries. It is up to you to find the proper balance for your application - as always.
And the n:m relations?
Until now nothing is defined for the code basis you use. You just may define a common n:m relation with some metadata. In the case of busimess.org, for example, the relation data again is defined by a structure like the one above.
Considerations
This model only eliminates the drawbacks on the DB model side, no possible drawback on the application side, like mentioned above with relations in AR. Implementing this model as a backend in your application you should do the mapping or use some content management framework which already implements a model like this.
Enhancements to the model
eZ Publish, for example does not only versions and translate the content objects, but also the content classes - you may imagine that this makes some of the queries even a bit more complex, but when good caching comes in place here, this shouldn't be such a big deal with common requirements - and if you have very special performance requirements you still may use views, another model or more caching ;). And - as written earlier - this is not meant being the optional model for each use case. Something like this obviously does not exist.
Including model in your application
The earlier mentioned relations between objects are one way to include such a model in your application, if you have data only structured by some graph, as known from computer science. This is true for wikipedia, for example, where the only structure is given by references between articles - hard to brows for the visitor and not a very common access method.
Tree
Far more common are trees which put the data into a hierarchic structure - this can be read as some navigation, or maybe you also want to structure the data not displayed on your website in a tree and only display a subtree.
This can be done easily by using some extra table defining the hierarchic structure using some of the common algorithms to map trees into a database like parent child relations, or nested sets where the nodes relate to some object. You may want to consider being able to connect one object to multiple nodes...
eZ Publish
In eZ Publish you get one tree which contains objects, similar to the ones described above, connected to one or more nodes of the tree (where one is the main node). Additionally you get the possibility to add relations between the objects (so that you don't have a tree any more in theory, but this does not really matter anywhere).
Each object in eZ Publish is connect to at least one node, and nearly everything is such an content object. Even users, for example, are only sub content objects of a subtree which is an instance of the content class user group.
Of course you may also add user content objects to other nodes, you may define permissions on parent content class, define which content class / object may have childdren at all, or which children it may have, for users or groups, or complete sub trees, either by sub tree or section. Going into detail here obviously won't fit any blog post. ;)
Other ORMs
There are complete different ways to define your ORM. You may use an arbitrary table structure and define some random mapping using some XML definitions, or even a mapping in your database. Both ways can make the mapping completely independent from your business objects and your database schema.
Then ... why does AR exist at all?
AR still may be used for accessing the tables in the model described above. If this makes sense again depends on your use case, and - for example - may be useful as an abstraction layer of the used relational database management system.
Also you may try using some AR framework to just do rapid prototyping. But you should know the limited scope of this approach - and hope your boss will not come into your office and request something which may not be implemented using AR - or you can just do a quick hack, of course. ;)
Conclusion
As shown, AR is just a wrapper for database access and not appropriate as an ORM. Used carefully, or with very simple applications it really may proof useful.
But there are other ways to abstract the access to your database like query construction using some object orientated interface, like it is done in the database component in eZ Components. The classes then may create SQL which work with the currently used RDBMS. Another (slow) way is parsing the query given by the user and restructuring for the current relational database management system.
The possibilities for object relational mapping described in this blog post are initially more complicate to use, but also may offer great extensibility, real mapping with future proof concepts. You won't run in the discussed problems. But, as always, higher abstraction cause more complex code and may bring you a performance impact - which could be solved by proper caching.
And, there is no perfect system to solve all your needs, which some people think Active Record was, but you should review your modelling concepts.
Other solutions
There are completely different solutions which may work better with your object structures like CouchDB - something Jan blogged about and is a really cool solution which does not force any relational database structures and still are ACID.
If you liked this blog post, or learned something please consider using flattr to contribute back: .
Trackbacks
Comments
-
Les at Tue, 28 Aug 2007 17:01:46 +0200
This is why I loathe Ruby on Rails; Those that use it have little, if any real experience developing complex or task/user heavy applications, and are dependent on a complete solution.
Link to comment
Ruby on Rails has been touted as a web development framework, and yet it is just not ready for what is required of us developers today's market. To get something done, you have to jump through hoops, and as you say, break something along the way.
I just cannot imagine the -beep- nightmare second generation developers are going to face when it comes to maintaining Ruby on Rails based applications tomorrow. If you want a complete solution, develop your own, otherwise pray that you've chosen wisely! -
Daniel Spiewak at Thu, 30 Aug 2007 21:52:18 +0200
What you've pointed out are really a generic series of problems with any ORM/ERM/whatever-you-want-to-call-it. It's really the same problem in any framework you may choose: it's too generic. You have a specific use case you need to satisfy, and AR is absolutely the wrong tool to accomplish this. For something where you have really crazy requirements or a complex set of non-standard mappings, something like Hibernate will really do much better.
Link to comment
Hibernate is about the most flexible ORM possible. The problem with this of course is an increase in complexity. AR trades flexibility for simplicity. Thus, for 90% of use cases, AR will perform the task and do it in a much more intuitive way than Hibernate. For the remaining 10% of scenarios, AR will fail to work at all, and you'll have to fall back to something more complex. It's just the nature of generic libraries. -
Kore at Thu, 30 Aug 2007 23:22:03 +0200
@Daniel: You are basically right, and this trade off is of course well known.
Link to comment
To boil it down to one single point: I don't think AR fits 90% of the use cases. The issues I described above are so general, that nearly each web application is required to solve it somehow - and I think more developers should be aware of the issues, and that this will results in ugly hacks when AR is used.
As said in the blog post, AR works for very simple projects ... but where you don't need states, versions OR translations - same for the variants... -
Mark Thomas at Fri, 31 Aug 2007 22:01:58 +0200
This article is talking about Active Record the design pattern, not ActiveRecord the Ruby ORM. The Ruby ORM, despite the name, actually provides more capability than the design pattern covers. But Kore is correct--sometimes in Rails you have to bypass AR and roll your own. But this can be done in rails, so it's no reason to loathe it.
Link to comment -
Mor at Sat, 01 Sep 2007 16:55:00 +0200
@Les: You don't really know what you're talking about, do you? I have over 10 years of experience developing complex "user-heavy" applications. I've been using Rails for 6 months building an app used by thousands of people daily and growing. I can truthfully say, since I actually have the requisite experience, that Rails is ready for developers in today's market for a lot of (the majority of) applications without jumping through hoops or breaking something.
Link to comment
There are cases where you will have to jump through hoops, but what framework covers every case out of the box? If you can name one, you're delusional at best. -
Mike Seth at Sun, 02 Sep 2007 16:45:58 +0200
Hi Kore,
Link to comment
I agree and disagree with you at the same time. Here is my detailed followup:
http://blog.mikeseth.com/index.php?/archives/4-ActiveRecord-sucks,-but-Kore-Nordmann-is-wrong.html#extended -
Dante at Sun, 02 Sep 2007 23:57:34 +0200
Hi Kore,
Link to comment
You should really have a look into Ruby on Rails Active Record implementation and put it into use. Or if you prefer its new PHP version Akelos (http://www.akelos.org).
What they have covers more than what the Active Record pattern specifies, but as Thomas said you can do about everything using them.
Can you tell us the hoops you can't jump with one of those?
-
Steve Molitor at Mon, 03 Sep 2007 01:10:02 +0200
Kore,
Link to comment
You might want to make it clear that you are talking about the generic Active Record pattern, not the Rails ORM of the same name. Some people reading this (like Les) might assume you're slamming Rails, but based on your article I assume you have no knowledge of the Rails ActiveRecord library. True, Rails AR is built on the AR pattern, but it adds (in some cases with plugins) all the ORM features missing from the base pattern -- support for versioning, localization, auditing, optimistic locking, mapping tree sructures, yada yada. As best I can tell it can address all of the prolems you mention and more. It's quite sophisticated. To paraphrase your one line summary of your article, Rails AR implements an ORM on top of the AR pattern. Try it, you might like it.
Steve -
Tim Harper at Wed, 17 Oct 2007 05:10:51 +0200
I haven't yet run into a problem that was unsolvable by ActiveRecord - It's not really meant to be an "end all solution" and do everything for you - it's a base starting point, and a really great one.
Link to comment
If you haven't looked into it, you can pass in your own includes (joins auto generated by the models, a really REALLY handy feature), custom joins, custom selects, aggregation, etc.
Then, if ActiveRecord still doesn't cut it for you for those more advanced cases, you can skip straight to the database connection, and use select_all.
I smell FUD -
Daniel Kerr at Sun, 04 Nov 2007 14:50:39 +0100
I have one problem with active record when creating apps.
Link to comment
Some tables require a date_added field. Since all the active record patterns I have seen add quotes around each value how are you soposed to add date/times set to now(). -
Art Hundiak at Mon, 05 Nov 2007 17:34:25 +0100
Daniel Kerr,
Link to comment
Which active record patterns (libraries?) have you looked at? In PHP: propel, Doctrine and the Zend_Db framework all handle dates just fine. Especially since they all rely on prepared statements.
-
Cory Kaufman at Tue, 06 Nov 2007 12:08:02 +0100
I am working on a project with tables structured similar to yours. Was your table structure inspired completely by ezpublish, as mine was, or did you have other inspirations? I'd love to read up on something that isn't quite as complex as ezpublish, to make sure I'm headed in the right direction.
Link to comment -
ggiunta at Fri, 09 Nov 2007 02:01:34 +0100
A good example of the leakiness of the AR mapping can be found in this blog post:
Link to comment
http://www.xml.lt/Blog/2007/10/22/Eager+fetching+and+SELECT+N%2B1+problem
I do not like very much the proposed solution, as it looks quite not general enough, and somehow keeps the data layout filtering to the above layers... -
hello at Fri, 18 Jan 2008 22:27:18 +0100
HELLO!!!
Link to comment -
kicherhexe at Mon, 17 Mar 2008 10:37:34 +0100
1000 bussies to ernie!
Link to comment -
David Griffiths at Mon, 05 May 2008 08:59:32 +0200
Aren't you at risk of being too sweeping? You admit that AR can be useful in some circumstances. Does it cover every circumstance? No. Does anything? No. Are you ideas over-engineered for some circumstances? Yes. So by your own logic, do your ideas suck?
Link to comment
I think you need to be very careful in immediately going for large up-front designs to solve problems you don't have yet. If you need to solve the problems you describe here, then your solutions are very clever. But if you are trying to solve simpler problems, then they are not.
Simple problems should be solved simply. That what ActiveRecord is good at. Whether it is an "ORM" (is there a full, formal definition of what that is, by the way?) or not is irrelevant. -
Sam at Sat, 26 Jul 2008 18:10:13 +0200
@Les. So why do you take a crap on Rails just because the big apps you've worked on would require you to break the "Rails Way" so to say? So what? The creator of Rails has said, in public, that a pure Rails implementation would obviously not be sufficient a Google, Amazon, etc. How many web apps are going to be that big anyway? Many of the people I met building web apps with Rails were doing so for universities that don't have the money to hire a professional Java developers....so they are doing it with Rails!
Link to comment
Are you offended that some young hacker from 37signals is richer than you are? -
dwlnetnl at Sun, 27 Jul 2008 11:11:06 +0200
To all of your ActiveRecord people, please look on this article:
Link to comment
http://www.qcodo.com/documentation/article.php/6
That's build on the 'legacy' ActiveRecord in stead of an fuzzy definition-like mess.
Thank you. -
Snouty Hound at Wed, 13 Aug 2008 22:58:14 +0200
Please see the Wikipedia material on the so-called Object-Relational Impedance Mismatch. SQL is basically a given, but its philosophies are fundamentally incompatible with OOP. In the OOP world, the database is merely a persistence mechanism; in the database world, objects in the process space are just temporary data. Rails (with Mongrel) is basically a combination of three things: a very decent HTTP/object mapper, ActiveRecord, and a bunch of miscellany. The way to get things done in Rails: abandon OOP and ActiveRecord (except for the simplest one-table queries), and write procedure-oriented code that will interface very well with SQL databases.
Link to comment -
dmx at Tue, 07 Oct 2008 16:35:53 +0200
I've got bit of a stunt I use with Active record. I hook it together with database views and ignore the object relational stuff.
Link to comment
All queries get built as database views, or stored procedures, and kept on the DB side, then I can just peel em off with the AR implementation and treat it as a dumb table with nice syntax.
Works a charm and avoids the impedence mismatch. -
Mark at Sat, 25 Oct 2008 05:27:58 +0200
Relying on ORM is a cruch. It enables poor performance application by being greedy in its selection and updating of records.
Link to comment
Let's say I have a record with 50 fields.
I need to access only Firstname, Lastname and Email. WHy select all 50 fields?
I need to update only email... again, why write all 50 fields?
These are just two scenarios where blindly relying on ORM to do the work for you is bad.
-
Aaron at Tue, 18 Nov 2008 19:44:29 +0100
Kore-
Link to comment
I'm not weighing in on ActiveRecord, but saying thanks for your description of the the content problem and a proposed model. It has helped me understand how versioned documents with variable attributes can be efficiently stored in a database, something that you don't see from many applications out there. I'll have to give ezPublish another look.
-
Les at Sun, 25 Jan 2009 14:36:49 +0100
Offended?
Link to comment
Yes and no. No because someone got rich, and yes because RoR was in the beginning touted around the community as the perfect solution and now today it has been proven to be inadequate, a number of times I might add so my earlier comments do in fact stand.
As to the other comment made to my original comment, do you still today believe that RoR is a credable solution? A number of Python frameworks have got a lot more going for them than what RoR has to offer.
RoR is really only suitable for personal sites such as blogs and home businesses where there is very few users and minimum amount of data in use.
Basically, RoR sucks and you can bang on about how great it [RoR] is but facts speak for themselves.
Enough said then. -
Josh Ribakoff at Tue, 17 Feb 2009 03:41:36 +0100
Thanks for the great article, helped explaining the difference between the DA patterns to a client. If any PHPers are reading this they might be interested in the library I'm working on
Link to comment -
JRiddy at Fri, 14 Aug 2009 00:02:54 +0200
Just nit pickin':
Link to comment
"You either destroy your business objects or your DB model."
The sentence that immediately follows this states that this "OR" is not an "XOR." If that's the case, please don't say "either." "Either A or B" is the English equivalent of logical "A xor B." Just plain "or" in English can be ambiguous, but that can be helped. Try this:
"You could destroy your business objects or your DB model, or both."
Okay, I'm a grammar Nazi, but this is the kind of thing that would cause a potentially hard-to-spot logical error if it were in code. I guess I'm just trying to apply the same care to speech as I do to code. ;) -
ToKaM at Tue, 22 Sep 2009 11:34:10 +0200
private static $tanslations = array ();
Link to comment
/**
* @param integer $id
* @param Sql_Language $language
* @param integer $joinOnInit
*
* @return Sql_Translation
*/
public static function getTranslation($id, $language,$joinOnInit=0) {
$id = intval($id);
if(is_numeric($language)){$language=Sql_Language::getLanguage($language);}
if (self::$tanslations [$id][$language->getId()] === null) {
self::$tanslations [$id][$language->getId()] = new Sql_Translation($id, $language);
}
$ret = self::$tanslations [$id][$language->getId()];
$ret->addJoin($joinOnInit);
return $ret;
}
//__construct is private! -
ToKaM at Tue, 22 Sep 2009 11:44:08 +0200
This is an excerpt of my ORM for the class Sql_Translation. I have a multifield primarykey (id|language). The variable $joinOnInit is used to decide in the init() method, which is called when a getter is called for a non-set member variable. the addJoin method is public and it connects the existing $joinOnInit information with an logical or to the binary flag passed as param. here you see an exmaple for the flags for an other class.
Link to comment
const JOIN_COMMENTS = 1;
const JOIN_TRANSLATIONS = 2;
const JOIN_GEONAME = 4;
const JOIN_RATING = 8;
const JOIN_CATEGORIES = 16; -
Kirk Bushell at Sat, 16 Jan 2010 03:01:59 +0100
Les - you say:
Link to comment
RoR is really only suitable for personal sites such as blogs and home businesses where there is very few users and minimum amount of data in use.
Basically, RoR sucks and you can bang on about how great it [RoR] is but facts speak for themselves.
I couldn't disagree more. I haven't built sites that serve billions of page views (how many of us have?) but I have built applications and sites that serve well over 20mil+ visits/month across an application built on ruby on rails. RoR doesn't suck, it's just that the community itself got swept along by it's own enthusiasm, which blindsided them and allowed greener developers to be swept along with it.
RoR, although not the be-all-end-all solution, is still very good for rapid development, which is really what it's all about. It was the first real step in industrializing application development. You can easily add more hardware (and might I add - cheaply), but developer time is always far more expensive. Therefore, the tradeoff is worth it.
Also, I'd like to add to this discussion that there has not been a single, complex query that I've had to create (sometimes collecting data from as many as 7 tables) using RoR's built-in AR functionality.
I'm no RoR evangelist, but I do think it has it's place, and it's also helped PHP salaries go up as more and more devs move to RoR =P -
stizi at Sat, 30 Jan 2010 19:59:06 +0100
@Kirk Bushell
Link to comment
AR lacks of stardard. When queries getting more complex, each of these framework(ROR, Zend, Doctrine...) try to resolve in their own way. Now as developers you have to master each of them in order to use these frameworks. Why NOT just learning one language - SQL? -
alex at Sun, 07 Feb 2010 17:02:58 +0100
@stizi if you want to write sql queries that fits two pages don't ask yourself why you broken your leg when other webdev came to work after you
Link to comment -
and... at Sun, 07 Feb 2010 17:03:25 +0100
@kore you are stupid
Link to comment -
Kirk Bushell at Mon, 15 Feb 2010 03:46:12 +0100
@stizi
Link to comment
You are, obviously - correct. However, why worry about how other frameworks implement things? Different are always going to be different - everyone has their own ideals as to how something should be done. I can guarantee you that if I were to create a framework, it would again be different. There are high-level standards, they're called design patterns. That's about as much as you can hope for :P
SQL is great, and certainly has it's place - I still work with it heavily on various projects. However - writing and testing SQL is slow. If you have a more efficient way of utilizing it, a way that saves your company money - why would you ignore it? -
kostyl at Wed, 03 Mar 2010 19:31:54 +0100
May be you don't understand how to use Active Records, Mappers, Query Objects, Lazy Loaders and other patterns together with little tricks and corrections?
Link to comment -
T at Thu, 08 Apr 2010 16:32:46 +0200
You sir are an idiot. Basically, you're complaining that your car sucks because you can't drive from Europe to Australia.
Link to comment -
beberlei at Sat, 07 Aug 2010 21:08:14 +0200
Thanks kore! your reference example got me inspired to finally take up the rather complex issue of allowing composite primary keys that are foreign keys also and implement it in Doctrine 2:
Link to comment
/**
* @Entity
*/
class DDC117Reference
{
/** @Id @ManyToOne(targetEntity="DDC117Article", inversedBy="references") */
private $source;
/** @Id @ManyToOne(targetEntity="DDC117Article", inversedBy="references") */
private $target;
/** @column(type="string") */
private $description;
public function __construct($source, $target, $description)
{
$this->source = $source;
$this->target = $target;
$this->description = $description;
}
}
$ref = new DDC117Reference($article1, $article2, "Some description");
Fields with bold names are mandatory.
Traits & Active Record on Sun, 24 May 2009 12:58:15 +0200 in Kore Nordmann - PHP / Projects / Politics
Sebastian Deutsch blogs about the use of Traits for implementing Active
Record in PHP. With traits, possibly implemented sometime in the future of
PHP (5.4?), you at least do not destroy your object semantics anymore - even
several problems persist with AR, as discussed earlier.