There is the example of creating and using a service in the official documentation. At start we create some class, then register it in config/services.yml an then we can use it in our code like this:
$result = $this->get('app.myservice')->myMethod($arg);
//(In the [example][1] it is little bit other code:)
//$slug = $this->get('app.slugger')->slugify($post->getTitle());
But WHAT FOR? while I can just do the SAME like this:
use MyServiceNamespace/MyService
//...
$result = (new MyService())->myMethod($arg);
Where is profit of using Services? Is this just syntax sugar?
Nope. Far from syntax sugar.
You need to have a working understanding of what dependency injection means. Perhaps start by skimming through here: http://symfony.com/doc/current/book/service_container.html
Let's suppose your service needs a doctrine repository to do it's job. Which is better?
class MyController
{...
$userManager = $this->get('user.manager');
OR
$userRepository = $this->getDoctrine()->getManager()->getRepository('MyBundle::User');
$userManager = new UserManager($userRepository);
Your choice but once you have worked through the mechanics of how to add a service then you will never look back.
I should also point out that your sluglfy example requires a use statement and ties you code directly to a specific implementation. If you ever need to adjust your slugification then you need to go back and change all the places where it is used.
// These lines make your code more difficult to maintain
use Something\Slugify;
$slugify = new Slugify();
AS Opposed to
$slugify = $this->get('slugify');
'tIn this case, it's not really relevant. But from a simple design concern, services allow to make a better dependency management.
For instance, if you declare a service relaying on another one, then you won't have to instanciate both of them. Symfony will take care of it.
And since your declaration is centralized, any modification on the way you decide to create your service (= declare it), you won't have to change all the references to the services you changed since symfony will take care of the way it's instanciated when needed.
Another point is the scope of services. This information might be checked, but I think symfony instanciate service once (Singleton) which mean a better memory usage.
Related
Autofac provides the OnActivated() method, which provides the capability to run any action after constructing a registered type.
Is possible to use a similar method in MvvmCross? Do you have any ideas to provide the same functionality?
It usually pays to understand the fundamentals of Dependency Injection (DI) instead of relying on particular DI Container features. Ask yourself the question: If I didn't have a DI Container, then how would I solve my problem?
Ironically, it turns out that things are usually much simpler with Pure DI.
If you didn't have a DI Container, then how would you run an action after construction of an object?
The easiest solution is to provide a factory that creates and initialises the object. Assuming the same API and requirements as the Autofac documentation implies, you could do this:
public static Dependency2 CreateDependency2(ITestOutputHelper output, Dependency1 dependency)
{
var d2 = new Dependency2(ITestOutputHelper output, Dependency1 dependency);
d2.Initialize();
return d2;
}
If you still must use another DI Container, most of them enable you to register a factory like the above against the type. I don't know how MvvmCross works, but I'd be surprised if this wasn't possible. If it isn't, you can implement an Adapter over your actual dependency. The Adapter would take care of running the action on the adapted object.
FWIW, if an object isn't in a valid state before you've run some action on it, then encapsulation is broken. The fundamental characteristic of encapsulation is that objects protect their invariants so that they can never be in invalid states. If possible, consider a better API design.
Here is the context :
Each user of my application belongs to a company.
Parameters for each company are defined inside "company.yml" configuration files, all of them sharing the exact same structure.
These parameters are then used to tweak the application behavior.
It may sound trivial, but all I'm looking for is the proper way to load these specific YAML files.
From what I understood so far, using an Extension class isn't possible, since it has no knowledge about current user.
Using a custom service to manage these configurations rather than relying on Symfony's parameters seems more appropriate, but I can't find how to implement validation (using a Configuration class) and caching.
Any help would be greatly appreciated, thanks for your inputs!
Using the Yaml, Processor and Configuration components of Symfony2 should fit your needs.
http://symfony.com/doc/current/components/yaml/introduction.html
http://symfony.com/doc/current/components/config/definition.html
Define your "CompanyConfiguration" class as if you were in the DependencyInjection case
Create a new "CompanyLoader" service
use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Config\Definition\Processor;
$companies = Yaml::parse('company.yml');
$processor = new Processor();
$configuration = new CompanyConfiguration();
$processor->processConfiguration($configuration, $companies);
Now you should be able to use your companies array to do what you want
Have a look at http://symfony.com/doc/current/cookbook/configuration/configuration_organization.html as well as http://symfony.com/doc/current/cookbook/configuration/environments.html. If that's not the correct answer you'll have to be more specific on what your company.yml configuration contains.
I'm using Symfony2 with Doctrine2. I want to achieve the following:
$place = $this->getDoctrine()->getRepository('TETestBundle:Place')->find($id);
And on that place will be the info of the place (common data + texts) on the user language (in session). As I am going to do that hundreds of times, I want to pass it behind the scenes, not as a second parameter. So an English user will view the place info in English and a Spanish user in Spanish.
One possibility is to access the locale of the app from an EntityRepository. I know it's done with services and DI but I can't figure it out!
// PlaceRepository
class PlaceRepository extends EntityRepository
{
public function find($id)
{
// get locale somehow
$locale = $this->get('session')->getLocale();
// do a query with the locale in session
return $this->_em->createQuery(...);
}
}
How would you do it? Could you explain with a bit of detail the steps and new classes I have to create & extend? I plan on releasing this Translation Bundle once it's ready :)
Thanks!
I don't believe that Doctrine is a good approach for accessing session data. There's just too much overhead in the ORM to just pull session data.
Check out the Symfony 2 Cookbook for configuration of PDO-backed sessions.
Rather than setting up a service, I'd consider an approach that used a Doctrine event listener. Just before each lookup, the listener would pick out the correct locale from somewhere (session, config, or any other place you like in the future), inject it into the query, and like magic, your model doesn't have to know those details. Keeps your model's scope clean.
You don't want your model or Repository crossing over into the sessions directly. What if you decide in the future that you want a command-line tool with that Repository? With all that session cruft in there, you'll have a mess.
Doctrine event listeners are magically delicious. They take some experimentation, but they wind up being a very configurable, out-of-the-way solution to this kind of query manipulation.
UPDATE: It looks like what you'd benefit from most is the Doctrine Translatable Extension. It has done all the work for you in terms of registering listeners, providing hooks for how to pass in the appropriate locale (from wherever you're keeping it), and so on. I've used the Gedmo extensions myself (though not this particular one), and have found them all to be of high quality.
I am sort of new to Unity all seems to be fine but I am kind of lost when to use
ResolvedParameter in Unity.
Googled and looked on MSDN but still cannot understand when to use it.
Do you have a simple example that could illustrate it's use.
Thanks a lot for your help
You may wish to configure a Type with constructor parameters of a resolved service and a string. In this case you would use ResolvedParameter.
Container.RegisterType<IRepository, Repository>(
new InjectionConstructor(
new ResolvedParameter<IClassifier>(),
"ConnectionString"));
It's for method injection; see Entering Configuration Information on MSDN. Scroll down to "Dynamically Configuring Constructor, Property, and Method Injection" and note that the ResolvedParameter is actually a parameter to the InjectionMethod constructor.
I've never encountered a need to use it. Constructor injection will solve 95% of your issues, and property injection will solve the other 5%. (Caveat: I've only used Unity on a couple of projects, so I don't claim to be an expert.)
As I see it its to be used when you have a constructor where at least one parameter can not be obtained from the container while the rest can. In such a situation you declare how to resolve each ctor parameter when actually creating a new instance of that type.
Container.RegisterSingleton<IConnectionManager, ConnectionManager>(new InjectionConstructor(new ResolvedParameter<INetworkClientFactory>(), Container.Resolve<IBackoffAlgorithm>(), 10));
In my example, the IConnectionManager instance obtains the first parameter from the container (via ResolvedParameter), the 2nd one via Container.Resolve<>, and the 3rd one is a hard-coded integer.
ResolvedParameter should behave equal to a direct Container.Resolve<> but looks a tad cleaner.
I'm writing an ASP.NET MVC application using NHibernate as my ORM. I'm struggling a bit with the design though, and would like some input.
So, my question is where do I put my business/validation logic (e.g., email address requires #, password >= 8 characters, etc...)?
So, which makes the most sense:
Put it on the domain objects themselves, probably in the property setters?
Introduce a service layer above my domain layer and have validators for each domain object in there?
Maintain two sets of domain objects. One dumb set for NHibernate, and another smart set for the business logic (and some sort of adapting layer in between them).
I guess my main concern with putting all the validation on the domain objects used by NHibernate. It seems inefficient to have unnecessary validation checks every time I pull objects out of the database. To be clear, I think this is a real concern since this application will be very demanding (think millions of rows in some tables).
Update:
I removed a line with incorrect information regarding NHibernate.
To clear up a couple of misconceptions:
a) NHib does not require you to map onto properties. Using access strategies you can easily map onto fields. You can also define your own custom strategy if you prefer to use something other than properties or fields.
b) If you do map onto properties, getters and setters do not need to be public. They can be protected or even private.
Having said that, I totally agree that domain object validation makes no sense when you are retrieving an entity from the database. As a result of this, I would go with services that validate data when the user attempts to update an entity.
My current project is exactly the same as yours. Using MVC for the front end and NHibernate for persistence. Currently, my validation is at a service layer(your option 2). But while I am doing the coding I am having feelings that my code is not as clean as I wish. For example
public class EntityService
{
public void SaveEntity(Entity entity)
{
if( entity.Propter1 == something )
{
throw new InvalidDataException();
}
if( entity.Propter2 == somethingElse )
{
throw new InvalidDataException();
}
...
}
}
This makes me feel that the EntityService is a "God Class". It knows way too much about Entity class and I don't like it. To me, it's feels much better to let the Entity classes to worry about themselves. But I also understand your concern of the NHibernate performance issue. So, my suggestion is to implement the validation logic in Setters and use field for NHibernate mapping.