I'm working with repositories lately and I'm trying to solve some default actions or needed behaviour in the main repository which is named AbstractRepository.
The AbstractRepository looks like this:
class AbstractRepository
{
protected $session;
protected $loggedUser;
public function __construct(Session $session)
{
$this->session = $session->current();
$this->loggedUser = $session->currentUser();
}
}
In every repository I want to be able to use these properties, but then I must call parent::__construct() in every repository to execute the constructor.
Is there any way I am able to let laravel's container handle this, instead of calling the parent constructor in every repository?
So I could just do it like this:
class CommentRepository extends AbstractRepository implements ICommentRepository
{
public function like($commentId)
{
$entry = Like::where('comment_id', $commentId)->where('user_id', $this->loggedUser->id);
}
}
If the class that extends another (abstract) class doesn't override the parent constructor the constructor of the parent class will be automatically called.
So if you had something like this:
class CommentRepository extends AbstractRepository implements ICommentRepository
{
public function __construct(Session $session){
$this->foo = 'bar';
}
}
You would have to add parent::__construct() if you wanted the constructor in AbstractRespository to be called.
public function __construct(Session $session){
parent::__construct($session);
$this->foo = 'bar';
}
However if your constructor method just looks like this, you can delete it completely:
public function __construct(Session $session){
parent::__construct($session);
}
Related
I have a base class and I want to have one of its methods called after the extending class is constructed. Ideally this should happen without changing the extended class constructor:
class BaseClass {
protected function doSomethingAfterConstruct() {}
}
class ExtendedClass extends BaseClass {
public function __construct() {
// some custom constructor code
}
}
I could just call $this->doSomethingAfterConstruct() at the end of the ExtendedClass constructor or by calling parent::__construct, but I am looking for a solution where I can implement this behavior by only changing the baseclass.
If it would be not __constructor, but ordinary method, then you can use __call magic method to proxy calls to child class:
All child methods should be non-public visibility, to trigger magic method
class BaseClass {
public function __call($name, $arguments) {
$return = $this->{$name}(...$arguments);
$this->doSomethingAfterMethod();
return $return;
}
protected function doSomethingAfterMethod() {}
}
class ExtendedClass extends BaseClass {
private function randomMethod() {
// some custom method code
}
}
I'm wondering if this is the correct way to extend and use classes with Symfonies autowiring.
For example, I have a BaseClass that instantiates and auto wires the entity manager.
class BaseClass
{
protected $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
protected function someMethodIWantToUse(Entity $something)
{
// Do something there
$this->entityManager->persist($something);
$this->entityManager->flush();
}
}
Then I have a subclass that extends the BaseClass and needs access that method. So I let it autowire again and pass it to the parent constructor.
class SubClass extends BaseClass
{
private $handler;
public function __construct(EntityManagerInterface $em, SomeHandler $handler)
{
parent::__construct($em);
$this->handler = $handler;
}
public function SubClassMethod()
{
// Get some data or do something
$entity = SomeEntityIGot();
$this->someMethodIWantToUse($entity);
}
}
Now I'm wondering if this is actually the correct way to do this or there's something I'm missing and the parent class should be able to autowire the entitymanager by itself?
To summarize the comments, yes your way is correct. Depending on your use case there are alternatives.
This are the ways you can go about it:
1. Extending Class and using Constructor Injection (what you do)
class BaseClass {
protected $some;
public function __construct(SomeInterface $some)
{
$this->some = $some;
}
}
class SubClass extends BaseClass {
private $other;
public function __construct(SomeInterface $some, OtherInterface $other)
{
parent::__construct($some);
$this->other = $other;
}
}
2. Setter Injection
class BaseClass {
protected $some;
public function __construct(SomeInterface $some)
{
$this->some = $some;
}
}
class SubClass extends BaseClass {
private $other;
public function setOther(OtherInterface $other)
{
$this->other = $other;
}
}
Now setOther won't automatically be called, you have to "manually" call it by either specifying a calls property in your services.yaml file, as described here: https://symfony.com/doc/current/service_container/calls.html. This would then look something like this:
// services.yaml
App\SubClass:
calls:
- [setOther, ['#other']]
Or
// services.yaml
app.sub_class:
class: App\SubClass
calls:
- [setOther, ['#other']]
assuming, an implementation of OtherInterface is available as #other in the service container.
A more elegant solution if you're using autowiring, simply add a #required annotation to the function as described here: https://symfony.com/doc/current/service_container/autowiring.html#autowiring-calls, which would look like this:
/**
* #required
*/
public function setOther(OtherInterface $other)
{
$this->other = $other;
}
3. Property Injection
class BaseClass {
protected $some;
public function __construct(SomeInterface $some)
{
$this->some = $some;
}
}
class SubClass extends BaseClass {
public $other;
}
As with the Setter Injection, you'll need to tell Symfony to populate this property, by specifying it in your services.yaml file like this:
// services.yaml
App\SubClass:
properties:
other: '#other'
Or
// services.yaml
app.sub_class:
class: App\SubClass
properties:
other: '#other'
assuming, an implementation of OtherInterface is available as #other in the service container.
Conclusion:
Since there are different ways to solve this, it's up to you to determine the correct way for your use case. I personally go with either option 1 (Constructor Injection) or option 2 (Setter Injection) using the annotation. Both of them allow you to use typehints and thus allowing your IDE to help you write clean code.
In 90% of cases, I'd go with option 1, as then it's clear for every one reading your code, what services are available with one glance at the __constructor function.
One use case for Setter Injection would be a base class offering all the setXXX functions but then sub classes not needing all of them. You could have a constructor in each sub class, requesting the needed services and then calling the setXXX methods of the base class.
Note: this is kind of an edge case and you probably won't run into this.
You can find a list of advantages and disadvantages of each method directly in the Symfony documentation about the Service Container -> Types of Injection
This way too :
class BaseClass
{
protected Environment $twig;
#[Required]
public function setTwig(Environment $twig): void
{ $this->twig = $twig; }
}
class ChildClass extends BaseClass
{
public function __construct(
private EntityManagerInterface $entityManager
) { }
public function test()
{
$this->twig->render(......);
}
}
I have to different classes in my Slim PHP framework, named OrderController & AddressController. I want to access some function of AddressController inside OrderController to reduce code redundancy.
But can't get a way to do it, I got how to do it in pure PHP setup, but how to do it in Slim PHP framework?
The PHP way to do this is as follows:
class A {
private $xxx;
public function __construct() {
$this->xxx = 'Hello';
}
public function getXXX() {
return $this->xxx;
}
}
class B {
private $a;
public function __construct(A $a) {
$this->a = $a;
}
function getXXXOfA() {
return $this->a->getXXX();
}
}
$a = new A();
$b = new B($a);
$b->getXXXOfA();
How to achieve this dependancy injection in Slim?
Slim PHP Framework
Note: I am using Slim PHP v3
2 solutions come into mind:
-1-
You could also try to have the common functionality in a separate Trait.
-2-
I won't do the
new SecondController($container)
inside the constructor of the FirstController unless you need it at every controller-hit.
I like lazy loading, so it will load only when needed.
If your AddressController and OrderController has same parent class, than move these methods to parent:
class AddressContoller extends Controller {
public function test() {
$this->methodFromParent();
}
}
If not, create new object of that class and call method. Method must be public
class AddressContoller extends Controller {
public function test() {
$order = new OrderController();
$order->publicMethodInOrderClass();
}
}
If your OrderController wants to call a method foo from AccessController, you should think about moving foo somewhere else. That's an good indicator for wrong SRP
There are two possibilities
foo belongs to/is relevant for every Controller and has something to do with controlling: Just move it to the parent class.
foo is relevant to only a few classes: Move it to the class, it belongs to. This could be an helper class, some domain model class, or something else. Maybe you have to intruduce a new class to do this.
After a lot of reseach I finally manage to get a solution! Posting it here so if anyone in future might get help from it:
class FirstController
{
protected $container;
protected $db;
protected $view;
protected $second;
// constructor receives container instance
public function __construct(\Interop\Container\ContainerInterface $container) {
$this->second = new SecondController($container);
$this->container = $container;
$this->db = $this->container->db;
$this->view = $this->container->view;
}
public function LocalFunction(){
$this->second->otherFunction();
//call the functions in other classes as above
}
}
I am trying to figure out how to import a large number of PHP class functions on the fly. For example...
class Entity
{
public function __construct($type)
{
require_once $type."_functions.php"
}
// ...
}
$person = new Entity("human");
$person->sayhi();
$cow = new Entity("cow");
$cow->sayhi();
human_functions.php:
class Entity redefines Entity
{
public function sayhi()
{
echo "Hello world!";
}
}
cow_functions.php:
class Entity redefines Entity
{
public function sayhi()
{
echo "Moo!";
}
}
I have found a few possibilities like classkit_method_redefine() and runkit_method_redefine() (which are "experimental", and they cannot modify the currently running class anyway). I am on PHP 5.3.3 right now, so I can't use Traits (Not sure if that is what I am looking for anyways). I have had success redefining the handler variable like this:
// Example 2:
class OtherEntity { /* Code Here */ }
class Entity
{
public function __construct($type)
{
global $foo;
unset($foo);
$foo = new OtherEntity();
}
}
$foo = new Entity();
But, this feels like a very hacky method. More importantly, if I don't name every instance of the class $foo, then it will not work. Are there any workarounds for what I am trying to do?
Note: I am aware that I can extend a class, but in my case when the Entity class is initiated, there is no safe way to know in advance what subclass it would need to be initiated with. Perhaps there is a method I could write, such as:
public function changeClass
{
this->class = OtherEntity;
}
Thanks for your help!
Here's an idea of a possible solution you could try. Let the Cow and Human classes extend the Entity class. However, the Entity class would use a factory to instantiate the objects based on if the value was safe. Let's look at this in more detail:
/*
* Class Entity should not be able to be instantiated.
* It should contain a factory to instantiate the
* appropriate entity and an abstract function declaring
* the method that each entity will need to implement.
*/
abstract class Entity {
public static function factory($type) {
return (is_subclass_of($type, "Entity")) ? new $type() : FALSE;
}
abstract public function sayHi();
}
/*
* Human class extends Entity and implements the
* abstract method from Entity.
*/
class Human extends Entity {
public function sayHi() {
echo "Hello World!";
}
}
/*
* Cow class extends Entity and implements the
* abstract method from Entity.
*/
class Cow extends Entity {
public function sayHi() {
echo "Moo!";
}
}
Now to use this method, call the factory method and if all works well, it'll instantiate the proper class which will extend Entity.
$person = Entity::factory("Human");
$person->sayHi();
$cow = Entity::factory("Cow");
$cow->sayHi();
Using, is_subclass_of() will keep you safe because if the passed in value is not a class that extends Entity, you'll be returned a value of FALSE.
If you'd like to see the above code in action, copy the above php code and test it out on phpfiddle.org.
One thing you can do is create Human and Cow as subclasses of Entity. When you do new Entity("Human"), you can store a newly created Human object inside the Entity instance.
Then you can use __call to redirect method calls to the "child element".
class Entity{
private $child;
public function __construct($type){
$this->child = new $type;
}
public function __call($func, $params=array()){
$method = method_exists($this, $func)
? [$this, $func] : [$this->child, $func];
return call_user_func_array($method, $params);
}
}
class Human extends Entity{
public function __construct(){}
public function sayhi(){
echo "Hello world!";
}
}
class Cow extends Entity{
public function __construct(){}
public function sayhi(){
echo "Moo!";
}
}
$person = new Entity("Human");
$person->sayhi();
$cow = new Entity("Cow");
$cow->sayhi();
The only downside is that $person and $cow are both Entity objects.
I want to do something like the following:
class SomeOtherClass {}
class Test
{
public $member = new SomeOtherClass();
}
The only problem is that I do not want to use a constructor, because the 'Test' class should extend another class and should not override the constructor.
Is this actually possible in PHP?
You can extend parent constructor in Test like this:
class Test extends SomeClass
{
public $member;
function __construct() {
$this->member = new SomeOtherClass();
parent::__construct();
}
}