Hi!
I`m currently working on PHP5-based extranet system which makes intensive use of enterprise patterns. Some problems encountered during developement cause serious haeadaches, but we`re going forward :)
I`m not 100% happy with architecture decisions we`ve made in the process and therefore I came here to ask if maybe someone has better ideas than we did.
Whole system is built on Data Mapper + Unit of Work + Identity Map + Lazy Load base. Everything worked well until we started testing if lazy loading is as lazy as it is supposed to be. We've used __set and __get magic methods to automate loading data to ghost object when something tried to access data inside. Yesterday was magic-methods-removal-day, because we realized post-factum that using magic method sets a flag blocking usage of another magic methods within that call. With high encapsulation we were screwed - there was no way to assure not having chained magic method calls (which still was far from being infinite recurrency). __get returning null in such situations without any warning caused many acts of disbelief in power of debugger among the developers :] Yes, I know it`s all in comments to manual page. NOW I know that :]
Back to the architecture problem...
Inside mappers we have standard find($ID) methods returning ghosts of real objects, which are filled at later time. Currently this mechanism is implemented almost exacly as in Martin Fowler's sample code - by adding notifyRead/notifyWrite in first line of public setters and getters. This works nicely, collections of object also don`t cause problems because they are not instantiated before we really need the elements.
We also use separate methods for finding objects using criteria different than just ID in database. So, some objects have findByName($name) or findActive() methods which work very similiar to find($ID) method, but use different queries. The problem with this methods is the same thing which helps us very much in different parts of application - Lazy Load.
Sample code: $company = CompanyMapper::find(1); // we have ghost inside $company //some other operations, but we don`t touch $company $company2 = CompanyMapper::findByName('Big Ltd.');
Now let`s assume, that company with ID=1 has name Big Ltd. We have two independent copies of the same object what kinda sucks :] The problem is that both finding methods return ghosts and the second one doesn`t know his ID yet. If there would be only ID-based searching than Identity Map would detect it and caused returning the same instance, but it`s not...
Unfortunately, we cannot afford to loose lazy load for those searching methods which use something different than ID. Our current solution is putting every ghost object inside handler object, because it allows us to switch object inside without rest of application noticing. This however requires many classes with nothing more than bunch of methods which transfer calls to another objects. We are working on piece of code, which will use Reflection to autogenerate these classes, but still it`s not very nice solution imho.
Long story short - what`s the best way to be able to load business objects as ghosts using different criteria without problem with multiple instances of the same object in the application.
rashid
ps. wow.. that was looong... :D
-- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php