Thanks to visit codestin.com
Credit goes to github.com

Skip to content

unserializing objects with dependencies #12222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
flip111 opened this issue Oct 13, 2014 · 7 comments
Closed

unserializing objects with dependencies #12222

flip111 opened this issue Oct 13, 2014 · 7 comments

Comments

@flip111
Copy link
Contributor

flip111 commented Oct 13, 2014

Hi,

I was thinking about creating a Form Builder UI. The user could specify the fields and then a FormBuilder class would be created at runtime. Great !
Just then i noticed the FormBuilder can be feeded some classes that can be services too, like the EventDispatcher. So in case you need that one you need the EventDispatcher which was already instantiated by the DIC and not a new one.

After looking around a litlte bit the following resource showed up:
https://www.drupal.org/node/2004282
where @stof points to
#7230

I would like to know if it's feasible to add support for this to the DI component or if it's left to the developer to request services for the unserialized component and figure out how to inject them.

There are some problems with doing it this way. Please consider the general question of injected services into unserialized objects, not just in the context of the FormBuilder, but also as in the linked PR of assetic and other use cases.

  1. All the required services already need to be instantiated while they might not be needed depending on the type of request (a lazy proxy service already helps here).
  2. Depending on business logic different services might need to be injected that can change in runtime.

Code could look like this:

# app/config/config.yml
services:
    my_service:
        class:        Some\Sort\OfClass
        arguments:    [@dependency1]
        calls:
            - [setDependency2, ["@dependency2"]]
<?php
// Some sort of class
class OfClass {
  protected $dependency1;
  protected $dependency2;
  protected $dependency3; // optional

  public function __construct($dependency1) {

  }

  public function setDependency2($dependency2) {

  }
}

// Somewhere else in another file
$fb = $container->wakeup(
  "some serialized FormBuilder string",
  [
    'dependency1' => $runtime_service1, // overwrite
    // dependency 2 --> default dependency
    'dependency3' => $runtime_service3 // supplemented
  ]
);

DIC would then do the following:

  1. unserialize the object
  2. instantiate dependency graph when not available (optional step i guess)
  3. choose different dependencies if specified in the wakeup() method
  4. inject dependencies. Possible implementation: reflection (a la Doctrine)
  5. give back object at runtime.

In addition to my question if this would be a good suggestion to the DIC component in specific, i would like to ask if this would be a good attribute to the symfony code wether or not it will be placed in the DIC component.

In conclusion: it's not that hard to make the ugly way when all the services are available from the DIC, but it might be worthwhile to have this functionality available to everyone.

Thoughts?

@linaori
Copy link
Contributor

linaori commented Oct 18, 2014

I was thinking about creating a Form Builder UI. The user could specify the fields and then a FormBuilder class would be created at runtime. Great !

I understand the idea, but you shouldn't do this. If your namespace, classname or property names change, your object cannot be unserialized. Next to that, it will be a hell of a job to create this possibility in the DIC.

If you want to have users create their own forms, store the setup and build form types based on that setup when the form is needed. This means that over time, your custom layer between the FormBuilder and form setup will be a lot more sturdy. A nice side effect is that you can hook into the building process. It also means that if the symfony forms chance, you just have to place a new bridge in between (or update the old). It also means you could use other frameworks if you please.

@flip111
Copy link
Contributor Author

flip111 commented Oct 21, 2014

Thanks for your input on my concrete use case .. it is helpful. However i would like to set to topic to whether symfony should be able to do dependency injection on runtime too. (of course also keep the compile time DI !!)

The thing is that a lot of symfony and user create objects can have both state and dependencies. And the problem is how to keep the state and have the dependencies at the same time. Because objects are no C structs with data only!!

Now i belief that an object should be able to independently offer different state representations of itself or it's parts (properties). For example i value the __toString() method over passing the object to some kind of service which returns the string for me. This service method would likely just fit to one type (class) of object and thus have high coupling with this type of object (class) and therefor it's better to let this object deal with it. This also comes apparent in the fact that interfaces only define function and no state (where i regard constants as invariant for initialization and not mutable state).

Of course __toString() is not too difficult as it's usually used for identifying an object by a string. But when it comes to serializing/unserializing there is a problem. On the PHP level this is all fine as long as the class has been defined and you can further tweak it by using the __wakeup() and __sleep() methods. But on the framework level there is no way currently to use this functionality together with dependencies.

This is also apperent by the fact that symfony dictates your application architecture for you rather then give you the freedom to choose which architecture you prefer. I noticed this when trying to move to Domain Driven Design and to do domain logging i had to grab the kernel/container from global scope. This was because the models are also not injected with dependencies at runtime.

@linaori
Copy link
Contributor

linaori commented Oct 21, 2014

I don't know about your application setup, but models having dependencies sounds like code smell to me, especially when serializing.

@flip111
Copy link
Contributor Author

flip111 commented Nov 5, 2014

This is a nice example of how a functionality of the application can be serialized and unserialized #12329 this one doesn't seem to have dependencies though

@fabpot
Copy link
Member

fabpot commented Feb 11, 2015

Closing.

@fabpot fabpot closed this as completed Feb 11, 2015
@flip111
Copy link
Contributor Author

flip111 commented Mar 15, 2015

In my opinion the introduction to the service container is ambigious.

Put simply, a Service is any PHP object that performs some sort of "global" task.
global seems ambigious because it's in quotes. This indicates that there are also other tasks (non-global).

Then to continue:
The advantage of thinking about "services" is that you begin to think about separating each piece of functionality in your application into a series of services.
Together with the previous sentence that would imply that all your functionality in your application are global tasks. The rest of the application are don't have functionality, like Data-Transfer-Objects.

By all means if anyone thinks i'm pulling things out of context from each other, please elaborate on the correct context of how this is supposed to read.

The documentation points to a wikipedia page that says:
A service-oriented architecture (SOA) is a design pattern in which application components provide services to other components via a communications protocol, typically over a network.

Two things stand out here in my opinion. First that it talks about components. And i ask myself would any service class already classify as component?

Second that typically this kind of architecture is used over network (as supposed to classes "communicating" to each other on the same machine). For me the wikipedia page relates more to for example the trend of micro-services that are becomming more popular lately.

I saw people in #symonfy @ freenode put every piece of functionality in a service class and prevents the data-objects from modifying themselves. Some sources say this is bad practice "(OOP) Writing lots of "xxxxxManager" classes that contain all of the methods for manipulating the fields of objects that have little or no methods of their own" -- of course i don't want to be a bad programmer (refering to the article title)

I'm going a stretch on my intuition here. What i would like to know the following:

  • Is it desired that symfony dictate the architecture of application specific code? (of course it must dictate it's own architecture!)
  • Each architecture brings it's own tradeoffs. There are reasons mentioned why to promote the service orientated architecture such as Each service can also be more easily tested and configured since it's separated from the other functionality in your application.. More easily tested than opposed to???

I realise any discussion on architecture would be more difficult then let's say an implementation detail of a method. I'm sad the issue was closed so early as i don't see many issues covering the bigger picture of the symfony framework...which is also important for a community driven framework, no?

@xabbuh
Copy link
Member

xabbuh commented Mar 16, 2015

@flip111 Do you mind opening an issue on the docs repository if you think that the documentation should be improved/clarified in a way?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants