Extending sfDoctrineRecord in symfony - symfony1

I've added some functionality to some of my instance classes in my symfony project that I want ALL of my instance classes to have. If I didn't have any qualms about editing the core symfony installation, I would just add my methods directly to the sfDoctrineRecord class. But I don't want to do that, of course, because my changes would break on upgrade, plus my changes wouldn't port well to other projects.
If I want to add certain functionality to all my instance classes in symfony, what's the "right" way to do that?
(P.S. When I say "instance class", I mean something like lib/model/doctrine/Customer.class.php.)

Steps:
Create myDoctrineRecord
abstract class myDoctrineRecord extends sfDoctrineRecord
{
public function commonRecordMethod() { }
}
I place this file in lib/record, but you can put it anywhere that the autoloader will see it.
Set Symfony to use this class in the configureDoctrine callback of your ProjectConfiguration:
public function configureDoctrine(Doctrine_Manager $manager)
{
sfConfig::set('doctrine_model_builder_options', array('baseClassName' => 'myDoctrineRecord'));
}
That's it! Isn't Symfony great? :)

I suppose the proper way would probably be to add a Doctrine_Template to the models in question, however you would need to define it as a behavior for every model in your schema.yml
class MyMethodsTemplate extends Doctrine_Template
{
public function customMethod1(){
$model = $this->getInvoker();
//do stuff with model
}
public function customMethod2(){
$model = $this->getInvoker();
//do stuff with model
}
}
And then in your schema.yml:
ModelName:
actAs:
MyMethodTemplate: ~
# the rest of your definition
After you rebuild you should be able to call:
$model = new ModelName();
$model->customMethod1();
$model->customMethod2();
Of course Doctrine templates and listeners are much more powerful than that. You should take a look at the documentation for decent overview

Related

Binding repositories to routes

I'm using the Repository pattern in a way very close to the one Chris Fidao's used on Implementing Laravel book. Basically I have concrete repository classes that implements its interfaces and gets models injected.
Now I want to take advantage of Laravel's route binding. Since I'm using repositories, I can't bind them to models directly... right? However I didn't get to do this.
I'm using a service provider to bind my concrete repositories to interfaces, like that:
$app->bind('App\Repositories\UserInterface', function ($app) {
return new EloquentUser(new User);
});
How can I bind my routes to repositories interfaces? Seems to be trivial, but I'm a bit lost...
Thank you in advance! :)
You can use a different approach to pass a model to a form without binding a model to a route, for example, assume you have a route which uses UserController and this is the controller:
class UserController extends BaseController {
public function __construct(UserInterface $UserRepo)
{
$this->repo = $UserRepo;
}
public function edit($id)
{
$user = $this->user->find($id);
return View::make('user.edit')->with('user', $user);
}
}
Your form in the user.edit view:
{{ Form::model($user, array('route' => array('user.update', $user->id))) }}
You can use a Repo in your routes the following way. But, do you really need this?
\\the repo is in the Branches folder
use App\Repos\Branches\BranchRepository;
Route::get('branches',function(BranchRepository $branchRepo){
\\using a method of your repo - in this case using getData() method
return $branchRepo->getData();
});

Laravel 4: how to inject another class in a eloquent model

I'm trying to use the built-in laravel's Ioc container to inject a PageManager class inside a Page model and I'm a little lost.
What I'm trying to achieve is something like that:
class Pages extends Eloquent {
public function __construct(PagesManagerInterface $manager, array $attributes = array())
{
parent::__construct($attributes);
$this->manager = new $manager;
}
public function saveToDisk()
{
$this->manager->writeToFile();
}
But I obtain this error:
ErrorException: Argument 1 passed to Pages::__construct() must be an instance of PagesManagerInterface, none given.
I tried to add this in app/start/global.php:
App::bind('Pages',function(){
return new Pages(new PagesManager);
});
But is seems ignored by the framework, and also i don't know how to insert the $attribute array into this declaration.
I'm a little lost so any help is appreciated!
It's not a good idea to overload a model's constructor because new instances can be spawned behind the scenes through various methods, like Model::find().
When that happens, the dependencies you're asking for in your custom constructor aren't being passed in because the Model class isn't aware of them. So, you get that error message.
See the find() method here: http://laravel.com/api/source-class-Illuminate.Database.Eloquent.Model.html#380-397
See this post by Jason Lewis: http://forums.laravel.io/viewtopic.php?pid=47124#p47124
I think that what you need is:
App::bind('PagesManagerInterface',function(){
return new Pages(new PagesManager);
});
This tells Laravel to inject a new Page object everytime it needs an instance of your PagesManagerInterface wich wasn't passed while creating the model.
In Laravel you can use the IoC Container:
public function saveToDisk(){
$managerObject = app()->make('path\to\class\PagesManagerInterface');
$managerObject->writeToFile();
}

Grails - controllers and tight coupling with backend

When you generate controllers in grails, the controllers call methods on the domain layer directly - I quite don't understand this, every bit of me is telling me that this is kind of wrong because you are tightly coupling the backend with the frontend. I think this belongs to the service layer.
Since it would be pretty ugly to create an equivalent set of methods in the service layer for all the methods defined on domain objects, I created this AbstractService to delegate all (missing) method calls from the service layer to the domain layer:
abstract class AbstractService {
def entityType
/**
* By default, this method takes the name of the service that extends this
* class, removes the suffix 'Service' and tries to create the Class object
* from the resulting name. Override at will.
*/
protected Class getEntityType() {
if (!entityType) {
try {
entityType = Class.forName(this.class.name[0..-8], false, Thread.currentThread().contextClassLoader)
} catch (ClassNotFoundException e) {
throw new ClassNotFoundException("Class ${this.class.name[0..-8]} could not be found. Please "
+ "override AbstractService#getEntityType() for ${this.class}.")
}
}
entityType
}
def methodMissing(String name, args) {
try {
if (getEntityType()?.metaClass?.getStaticMetaMethod(name)) {
getEntityType().invokeMethod(name, args)
} else if (args?.last()?.metaClass?.getMetaMethod(name)) {
args.last().invokeMethod(name, args.take(args.size() - 1))
} else {
throw new MissingMethodException(name, this.class, args)
}
} catch (MissingMethodException e) {
throw new MissingMethodException(name, this.class, args)
}
}
}
Then I just extend this service e.g. like this:
class UserService extends AbstractService {
}
And my controllers then can look for example like this:
class UserController {
def userService
def create() {
userService.save(new User(params))
}
def list() {
userService.list(params)
}
// et cetera...
}
Don't you think this is better? Thanks to dependency injection, I can for example rewrite the whole business layer without the need to change the code in the controllers - which is kind of why we use dependency injection, isn't it?
Thanks for your answers, I would like to hear as much opinions as possible.
This model is very used in Java Web applications and all. The Rails (and Grails followed it) community just tried to break the paradigm here, leaving it more simple. I mean, why would you delegate a service class to manipulate an entity, if this entity can simply do the job? If it's natural to the entity to do the job, then don't bring someone else to do it. That way, you avoid the Anemic Model since your objects are not only data holders, but they also know how to operate its own business.
Having said that, there are times when you're better off using a service class to do operations on your entities. For example, if it involves different kind of entities at the same time and so on... So, when it's not "natural" (and you would have to force to make it work) for the entity itself to take care of the operation, then a service class is the way to go. This article based on Rails gives some tips about the use of a service class.
And you are not tightly coupling the controller with the models (you said backend and front end, but I guess that's what you mean). The controller will eventually need to use the model, be it the entity itself or a service class (also Model) manipulating it.
The scaffolded controller code does not really represent ideal application architecture. Keep in mind that the generated scaffold code is just a starting point for generating the CRUD portions of your application.
You are correct that in general, you don't want to put most of your GORM queries in Controllers, since controllers are supposed to be for interacting with the front end. You can certainly either put the query/business logic into Services or put the queries directly into Domain classes. That's why Grails Services support declarative transaction handling.

Do I really add this line for each class in my model using ninject and NHibernate?

I am using NHibernate and ninject in ASP.Net MVC, using this page as a guide. One thing I think is weird is that, in this code (half way down the page)
public class RepositoryModule : NinjectModule
{
public override void Load()
{
const string connectionString = #"Server=localhost; Port=3306; Database=trucktracker; Uid=root; Pwd='your_own_password';";
NHibernateHelper helper = new NHibernateHelper(connectionString);
Bind<ISessionFactory>().ToConstant(helper.SessionFactory).InSingletonScope();
Bind<IUnitOfWork>().To<UnitOfWork>().InRequestScope();
Bind<ISession>().ToProvider(new SessionProvider()).InRequestScope();
Bind<IIntKeyedRepository<Truck>>().To<Repository<Truck>>().InRequestScope();
}
}
I think it's odd that you need to have this line per model:
Bind<IIntKeyedRepository<Truck>>().To<Repository<Truck>>().InRequestScope();
If I have 100 different tables (and thus models) do I really need to add this line in for every class that I have? Is there not a better way where I can just declare this once and use inheritance to pass in the Type in my controller?
Use the Open Generics support:-
Bind(typeof(IIntKeyedRepository<>)).To(typeof(Repository<>)).InRequestScope();

What's the simplest way to intercept a method call for added functionality?

Suppose i have a repository that returns a list of Posts. The repository interface has a GetAll() method which does what it suggests.
Now in keeping with the theory that i shouldn't be putting domain logic in the repository, i want to intercept calls to the concrete GetAll() method such that i can add the following logic to the GetAll() result:
return GetAll().OrderByDescending(p => p.Posted).ToList();
The reason i want to intercept this is because (1) i don't want to have the client remember to call an extension method (OrderByDescending or some useless wrapper of that), i want it called every time and (2) i don't want to have all my concrete implementations have to remember to order the GetAll() result - i want this logic in a single place external to any repository.
What's the easiest way to do this?
I'm already using StructureMap so if i can intercept with this it might be a low cost option. But i don't think SM intercepts method calls, just the creation of the object instance?
Do i need to go to a proxy or mixin pattern? Do i need to go all-in with Castle Dynamic Proxy? Or is there another method i should consider or perhaps a combination?
I'm really interested in a concrete suggestion to my particular example above. I'm novice to AOP so please be gentle.
Went with the DynamicProxy option. It was easier to use than i thought.
All it took was the using Castle.DynamicProxy; reference...
A bit of IInterceptor...
public class PostRepoInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
if (invocation.Method.Name.Equals("GetAll", StringComparison.InvariantCultureIgnoreCase))
invocation.ReturnValue = this.GetModifiedGetAllResult(invocation.ReturnValue);
}
private object GetModifiedGetAllResult(object getAllResult)
{
return Post.GetOrderedPosts((IList<Post>)getAllResult);
}
}
Two new lines in StructureMap config:
public RepoRegistry()
{
var pg = new ProxyGenerator();
For<IPostRepository>()
.EnrichAllWith(z => pg.CreateInterfaceProxyWithTarget<IPostRepository>(z, new PostRepoInterceptor()));
}
..and it's done. GetAll() now behaves how i want. I can still use the interfaces the way i'm familar and i've kept it all DRY and decoupled for DDD.
Thanks to Sam and Andre.
AFAIK, StructureMap only intercepts object construction, so using it it's not going to work.
I don't know Castle, but I think that the idea - here - is to apply Decorator pattern, so you could also do it by yourself without recurring to a third party library by following the steps described in the previous link.
That's how I'd do it, since I'm not a big fan of AOP.
HTH
No, it can not change the return value. However, you can access the target inside aspect to change target's property. Assuming you has already Repository defined, here is the code to add post processing aspect to change target property.
IRepository<decimal> Rep = new Repository();
IRepository<decimal> tpRep = (IRepository<decimal>)ObjectProxyFactory.CreateProxy(Rep,
new String[] { "GetAll" },
null,
new Decoration((x, y) =>
{
Console.WriteLine("Entering " + x.GetType().ToString());
if (x.GetType().ToString() == "ThirdPartyHR.Repository")
{
List<decimal> decimals = ((Repository)x).RepList;
IEnumerable<decimal> query = decimals.OrderByDescending(num => num, new SpecialComparer()).ToList<decimal>();
((Repository)x).RepList = (List<decimal>)query;
}
}, null));
tpRep.GetAll();
List<decimal> lstRep = Rep.RepList;
If needed, I can send you complete working code. And, if possible, please reply to me from the article "Add Aspects to Object Using Dynamic Decorator" since I don't automatically get the message here.
There is an article Add Aspects to Object Using Dynamic Decorator.
It describes an approach to adding aspects to object at runtime instead of adding aspects to class at design time. Looks like that is what you want.

Resources