I have the following model where I'm overriding the constructor of the base class
:
class Tasks extends BaseTasks {
public function __construct($currentUser, $taskId, $startTime) {
parent::__construct();
//........
//set all parameters to their respective fields
//........
}
When I manually create a task using: $task= new Task('test_user',1,'10:15');
everything works fine.
The problem is when I fetch all tasks from the database:
$tasks = TasksQuery::create()->find();
I get the errors:
Warning: Missing argument 1 for Tasks::__construct(), called in...
Warning: Missing argument 2 for Tasks::__construct(), called in...
Warning: Missing argument 3 for Tasks::__construct(), called in...
The stack trace shows that Propel in calling the constructor then populateObject to return the tasks objects with data:
Call Stack:
//...other function calls
0.1254 19326792 14. call_user_func(array (0 => 'TasksPeer', 1 => 'populateObject'), array (0 => '98', 1 => '2013-07-16 15:25:00', 2 => 'daily',...other params...) /library/propel1_6/formatter/PropelObjectFormatter.php:87
0.1254 19326824 15. BaseTasksPeer::populateObject($row = array (0 => '98', 1 => '2013-07-16 15:25:00', ...other params...) /library/propel1_6/formatter/PropelObjectFormatter.php:87
0.1254 19330456 16. Tasks->__construct($currentUser = ???, $taskId = ???, $startTime = ???) /models/om/BaseTasksPeer.php:485
Now if I decided to use value object in the constructor instead of the primitive data types like:
class Tasks extends BaseTasks {
public function __construct(User $currentUser, $taskId, StartTime $startTime) {
parent::__construct();
//........
//set all parameters to their respective fields
//........
}
The call to the constructor will fail with a fatal error!! Is there a way to solve this?
The Base class calls the constructor, but without arguments. In Order to avoid the warning, make the arguments optional
public function __construct($currentUser = null, $taskId = null, $startTime = null) {
...
}
Instead of null you can, of course, use appropriate values as your application demands.
Short answer: there's no definitive solution for that (constructor DI).
I ended up using the setter DI, calling the setters when I need, first time from the controller, then everywhere I need. But then your controller code will be plagued with setter calls... anyway, I'll show you:
//actions.class.php
...
$current_user = $this->getUser();
$item = ItemQuery::findPk($id); // you can't override every find* method...
$item
->setUser($current_user); // setter DI here
->archiveIn($current_user->getOfficeId()) // custom method, see below
->save();
...
//Item.php
//you need to define getUser() and setUser() methods in this class
...
public function archiveIn($office_id) {
$this
->setOfficeId($office_id)
->setArchivedBy($this->getUser()->getUsername()); // get the injected user
return $this; // keep method chainability
}
...