Zend Form: How to pass parameters into the constructor? - php

I'm trying to test my form. It will be constructing other objects, so I need a way to mock them. I tried passing them into the constructor...
class Form_Event extends Zend_Form
{
public function __construct($options = null, $regionMapper = null)
{
$this->_regionMapper = $regionMapper;
parent::__construct($options);
}
...but I get an exception:
Zend_Form_Exception: Only form elements and groups may be overloaded; variable of type "Mock_Model_RegionMapper_b19e528a" provided
What am I doing wrong?

A quick look at the sourcecode of Zend_Form shows the Exception is thrown in the __set() method. The method is triggered because you are assigning $_regionMapper on the fly when it doesn't exist.
Declare it in the class and it should work fine, e.g.
class Form_Event extends Zend_Form
{
protected $_regionMapper;
public function __construct($options = null, $regionMapper = null)
{
$this->_regionMapper = $regionMapper;
parent::__construct($options);
}
See the chapter on Magic Methods in the PHP Manual.

Zend_Form constructor looks for a specific pattern in method's names in your form. The pattern is setMethodName. the constructor calls the MethodName method and pass the parameter to it.
So you'll have this in your class :
class My_Form extends Zend_Form
{
protected $_myParameters;
public function setParams($myParameters)
{
$this->_myParameters = $myParameters;
}
And you pass the parameters to your form with :
$form = new My_Form( array('params' => $myParameters) );
So instead of params you can use any other names ( of course if it doesn't already exists in Zend_Form ).

Related

SUT parent checks dependencies with get_class

It started when I was performing null checks everywhere to make sure I have the necessary entities for my interactor. Fortunately, I came across this post which points towards not allowing the entities to be in an invalid state do the check in your constructor. Now my Interactors use protected static $request to state explicitly which entities they require, which are then passed in during instantiation. I chose static so the check could be done prior to creating an instance of the Interactor.
abstract class Interactor {
protected static $request = [];
protected $entities = [];
final public function __construct(Entity ...$entities) {
$this->setEntities(...$entities);
$this->checkEntities();
}
final private function setEntities(Entity ...$entities) {
foreach($entities as $entity) {
$this->setEntity($entity);
}
}
final private function setEntity(Entity $entity){
$className = get_class($entity);
if (!in_array($className, static::$request)){
throw new Exception("Not a requested entity");
}
$this->entities[$className] = $entity;
}
final private function checkEntities(){
if (count(static::$request) != count($this->entities))
throw new Exception("Entity mismatch");
foreach(static::$request as $index=>$name) {
if (!array_key_exists($name, $this->entities))
throw new Exception("Missing requested entity ($name)");
if (!is_a($this->entities[$name], $name))
throw new Exception("Not the specified entity");
}
}
final public static function getRequest(){
return array_values(static::$request);
}
}
Ok great, now I just do the check in a single location and I don't need to worry about performing null checks at the beginning of my functions. The problem with the way I am going about it now is that my Interactor is checking the class name against a static class name request array. Thus, when I DI the mocked entities during testing, my parent Interactor throws an exception saying it isn't in the pre approved list.
To demonstrate is the following simplified Chess example:
class Chess extends Interactor {
protected static $request = ['Piece','Engine','Board'];
}
Then we have our Entities:
abstract class Entity {}
class Piece extends Entity {}
class Engine extends Entity {}
class Board extends Entity {}
And finally our test:
class ChessTest extends TestCase {
function setUp(){
$this->piece = $this->getMockBuilder(Piece::class)->getMock();
$this->engine = $this->getMockBuilder(Engine::class)->getMock();
$this->board = $this->getMockBuilder(Board::class)->getMock();
$this->chess = new Chess($this->piece, $this->engine, $this->board);
}
function testCanSetup(){
$this->assertTrue(
is_a($this->chess, Chess::class)
);
}
}
Which throws Exception: Interactor receiving entity not requested (Mock_Piece_faaf8b14)
Of course Mock_Piece_faaf8b14 is not going to be in our static::$request array, so this is destined to throw an exception.
The workaround I have come up with so far is to include in Entity:
public function getClassName(){
return get_called_class();
}
Then in Interactor->setEntity($entity) instead of using get_class($entity) I would use $entity->getClassName() which then becomes trivial to mock.
I thought the way I had created the Interactor was inline with what the previously mentioned post was getting at, only take the entities in the constructor. However, it all feel apart when I injected mocked entities.
1) Is there a way to avoid getClassName() in my entities?
2) Is there something in the entities I can mock that gets called in get_class() instead?
Thank you for your help!
You are checking to see if the name of your class is one of the keys in your $request array. And it isn't. The keys in your array are numerical 0, 1, 2 so you are throwing the exception. I think that you want to use in_array instead.
Though at the same time, this still wouldn't pass with the mock because you are checking to see if the class name is in $request. So the name won't be there at all either and the exception will still be thrown.
If all that your Interactor class is doing is making sure that the correct objects are passed into the constructor why not just use PHP's native type hinting?
Your Chess class becomes:
class Chess {
public function __construct(Piece $piece, Engine $engine, Board $board) { }
}
PHP will make sure that the passed in objects are of the correct type and will allow you to mock them for testing.
You get the type checking that you are looking for without need to use getClassName() at all.

Creating own PHP framework, How to sending parameters to page controller

I'm creating my own framework. It works like this
localhost/controller/action/firstVariable/second/third (And so on...)
My bootstrap look like this:
$request = Util::getInput('request');
$requestList = explode("/",$request);
$modelName = #ucwords($requestList[0]);
$action = #$requestList[1];
$parameters = array_slice($requestList,2);
$controllerName = $modelName.'s'.'Controller';
I'm getting parameters from an url and save them in a variable $parameters. I would like to send them to the current action in my controller the way Laravel 5 is doing.
Example, in Laravel I specify parameters in the url and thats it.
To call them, I need to do a simple step. Just define them:
public function firstAction($first,$second){
}
When I go to an url like:
localhost/Main/firstAction/first/second/
Function of action 'firstAction' will catch those 2 parameters and then basically I can call them inside of the controller and send it to view.
My extends Controller class:
class Controller{
public function __construct($model,$action){
$modelClass = new main();
$reflection = new ReflectionClass($model.'sController');
$reflection->hasMethod($action) ? $this->$action() : die ('Base Controller call error: Method '. $action .' does not exist in Controller '. $model.'sController');
}
public static function renderView($action,$model,$data){
$model = str_replace('sController','',$model);
//include '../application/views/'.$model.'/'.$action.'.php';
$loader = new Twig_Loader_Filesystem('../application/views/'.$model);
$twig = new Twig_Environment($loader);
echo $twig->render($action.'.php', $data);
}
}
class MainsController extends Controller {
private $_data = array();
public function __construct($model,$action){
parent::__construct($model,$action);
}
public function firstAction($first,$second){
echo 'Hoi';
}
}
How can I do it, the good way? I can of course send the variable $parameter to MainController and than call
$this->_data inside of my action but It is not efficient.
I think I need to use arrays to do it, but I have no idea how.
Thank you.
Check out http://php.net/manual/en/function.call-user-func-array.php
P.S.
You do not have to use reflection in order to check if method on that object's instance exist. Single function call can be enough. Check out http://php.net/manual/en/function.is-callable.php
It would be nice if you would use more descriptive names. Now they are confusing.

Call a method after __construct in finished

Basically I have a method which I need to run when the constructor is finished (the method is called persist() and it simply saves a key which was generated during the constructor into the session). It seems simple enough, and it works - at the end of __construct I make the call to $this->persist().
The problem is that this class is subclassed many times. This causes two issues.
One, that I must remember to make the call to persist() at the end of every single subclass's __construct method. Not a huge issue but it doesn't feel very OOP, I feel like I could be dealing with this in the parent class some how and that this would be better.
Two, if a subclass is subclassed (which it is), and the __construct methods chained (i.e. parent::__construct called), the persist() method will be getting fired multiple times, once for each time the class has been subclassed. It only needs to be called once, when all construction is complete. In this scenario it doesn't really break anything because when the persist method is called for the 2nd, 3rd time etc., it simply overwrites what was persisted before. But that isn't the point, because I just feel like there must be a better way and that there are scenarios out there that would not allow for the method to be called multiple times.
Is a factory method which constructs the object and then makes the call to persist on it the only way? I can go down this route but I am just wondering if there is a way to do it without, so that the method from the parent is always called after construction.
Here is some example code:
session_start();
is(!isset($_SESSION["Component"])) $_SESSION["Component"] = [];
abstract Class Component
{
private $id;
protected $key;
function __construct($id = NULL)
{
$this->id = $id;
$this->key = [];
$this->key["something"] = "SomeValue";
$this->persist(); // First call
}
protected function persist()
{
if($this->id !== NULL) $_SESSION["Component"][$this->id] = $this->key;
}
}
Class SomeComponent extends Component
{
function __construct($id = NULL)
{
parent::__construct($id);
$this->key["something-else"] = "SomeOtherValue";
$this->persist(); // Second call
}
}
Class SomeSpecialistComponent extends SomeComponent
{
function __construct($id = NULL, $key = [])
{
parent::__construct($id);
$this->key = array_merge($this->key, $key);
$this->persist(); // Third call
}
}
$my_component = new SomeSpecialistComponent(1, ["example" => true]);
Only trick I found to get something similar (except I wanted to execute things before and not after) is using a parent class with an abstract method as a new constructor :
abstract class RequireThings {
public function __construct() {
$this->constructAndPersist();
$this->persist();
}
abstract function constructAndPersist();
// You could also set this function in your children classes by the way.
public function persist() {
echo ' Then I persist!';
}
}
class UsingPersist extends RequireThings {
public function constructAndPersist() {
echo 'I do my things first.';
}
}
$class = new UsingPersist();
Would output :
I do my things first. Then I persist!
If I got your problem right, it should be enough to avoid problems you are facing.
The main downside of this solution is that you have to use a new function which is supposed to be your new constructor for this type of classes. That's why I set the __constructPersist as abstract, it forces the behavior as wanted.
I would argue in favor of the factory method, mostly because you're doing real work in the constructor. Remove the call where work is being done in the constructors ($this->persist) and place it in the factory:
class ComponentFactory
{
const SOME_COMPONENT = 'component';
const SOME_SPECIALIST_COMPONENT = 'specialist_component';
public static function make($type, $id, $key = null)
{
switch($type) {
case self::SOME_COMPONENT:
$component = new SomeComponent($id);
break;
case self::SOME_SPECIALIST_COMPONENT:
$component = new SomeSpecialistComponent($id, $key);
break;
}
$component->persist();
return $component;
}
}
$component = ComponentFactory::make(ComponentFactory::SOME_COMPONENT, 42);
$specialist = ComponentFactory::make(
ComponentFactory::SOME_SPECIALIST_COMPONENT,
43,
[
'something' => 'SomeValue',
'something-else' => 'SomeOtherValue',
]
);
According to Miško Hevery (author of AngularJS and agile coach at Google) these are the warning signs of doing too much work in the constructor:
new keyword in a constructor or at field declaration
Static method calls in a constructor or at field declaration
Anything more than field assignment in constructors
Object not fully initialized after the constructor finishes (watch
out for initialize methods)
Control flow (conditional or looping logic) in a constructor
CL does complex object graph construction inside a constructor
rather than using a factory or builder
Adding or using an initialization block
just create another function that you'll call before $this->persist and override that in your subclasses instead of the constructor

Prefill a form's widget with URL parameter (symfony)

All is in the title.
I get the URL param :
$log = $request->getParameter('logement');
Widget's statement :
$this->widgetSchema['logement'] = new sfWidgetFormInputText();
And I pass it in the form to prefill my widget 'logement' :
$this->form = new bailForm(array('logement' => $log));
I have read it in symfony's doc, but, when I do this, I have this error :
The "BailForm" form only accepts a "Bail" object.
I have already tried many things found on Internet but, no one works.
EDIT
The ORM is Doctrine
"Logement" is an attribute of "Bail"
EDIT 2
I have tried :
$log = $request->getParameter('logement');
$this->form = new bailForm(null, array('logement' => $log));
I don't have error, but my widget "logement" isn't filled...
One of two ways:
1. If you want to validate Logement
$form = new BailForm(); //BailForm must have Logement validator set
$form->bind(array('logement' => $log) + $otherRequestParameters);
$form->updateObject(); //or save
2. If you just want Logement set on the object
$bail = new Bail();
$bail->Logement = $log;
$form = new BailForm($bail);
Your form is a propel or doctrine form, the first parameter of the constructor has to be a linked object instance. Try this:
$this->form = new bailForm(null, array('logement' => $log));
The forms that are auto-generated based on model classes (in this case, BailForm for Bail), are of type sfFormObject, and thus accept only parameters of type corresponding to the model class.
A naive solution is to declare a custom constructor for type BailForm that takes an array as a single parameter (or an array and an object of type Bail).
This would not be very good practice however, as model forms are designed to work with model classes only. This logement parameter - what is its significance with respect to the Bail object? Maybe if you ask yourself that question, you can come up with a more suitable design that probably incorporates the logement as an attribute of Bail.
class QuestionsForm extends BaseForm
{
private static $email;
public static function setEmail($set) { self::$email = $set; }
public static function getEmail() { return self::$email; }
public function configure()
{
$this->setDefault('email', self::$email);
//$this->setDefault('email', 'testemail');
//rest of the form setup code
}
}
Here is the actions class
class questionsActions extends sfActions
{
public function executeIndex(sfWebRequest $request)
{
$this->email = $this->getRequestParameter('email');
QuestionsForm::setEmail($this->email);
//die(QuestionsForm::getEmail());
$f = new QuestionsForm();
$this->form = $f;

PHP: 'Dynamic' callback from inside/outside a class

we have a problem [cit.]
I need to assign a callback dynamically within a class, in base of a variable param: my goal is to have just one class (and not a main class and many extender sub-class), and inside this class if a value is X, then the funcitonX must be used, if is Y, the functionY.
I know i cant explain well, i hope my example will do:
class plzComplicateMyLife{
public $vehicle;
public $kindVehicle;
public $dynamicFunction;
public function __construct($vehicle, $kindVehicle){
$this->kindVehicle = $kindVehicle;
$this->vehicle = $vehicle;
switch($kindVehicle){
case 'cycle':
$this->dynamicFunction = "isACycle";
break;
case 'car':
$this->dynamicFunction = "isACar";
break;
}
//here come the problem, i need to call the callback store in dynamicFunction.
//i tried:
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//error: Catchable fatal error: Object of class plzComplicateMyLife could not be converted to string in [...]
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//Warning: call_user_func(plzComplicateMyLife::isACar) [function.call-user-func]: First argument is expected to be a valid callback in [...]
//$this->dynamicFunction();
//Fatal error: Call to undefined method plzComplicateMyLife::dynamicFunction() in [...]
//so, how can i do that?
}
public function isACycle($vehicle){
echo 'im a cycle, model: '.$vehicle.'<br />';
}
public function isACar($vehicle){
echo 'im a car, model: '.$vehicle.'<br />';
}
//i know this has no sense, in this example at least.
public function printKind(){
//call_user_func($this->$this->dinamicFunction, $this->vehicle);
//call_user_func("plzComplicateMyLife::".$this->dynamicFunction);
//then?
}
}
$maserati = new plzComplicateMyLife('maserati4', 'car');
//then, maybe, outside the class i'll need to recover the callback:
$maserati->printKind();
EDIT:
As Rob said, polymorphism would be really a good solution.
But the problem is that, in this case, i really must have the same declaration for every class instance, changing only the parameters...e.g:
$maserati = new plzComplicateMyLife('maserati4', 'car');
$ducati = new plzComplicateMyLife('maserati4', 'cycle');
//is good
//becose i cant have:
$maserati = new plzComplicateMyLifeWithACar('maserati4');
$ducati = new plzComplicateMyLifeWithACycle('maserati4');
Polymorphism is the way to go here but for future reference you can also do this:
public function printKind() {
$this->{$this->dynamicFunction}($this->vehicle);
}
In response to your edit, could you not do something like this instead?
abstract class MethodOfTransport {
protected $model;
public function __construct($model) {
$this->model = $model;
}
abstract public function printKind();
public static function create($model, $type) {
$object = new $type($model);
return $object;
}
}
class cycle extends MethodOfTransport {
public function printKind() {
echo 'im a cycle, model: '.$this->model.'<br />';
}
}
class car extends MethodOfTransport {
public function printKind() {
echo 'im a car, model: '.$this->model.'<br />';
}
}
$maserati = MethodOfTransport::create('maserati4', 'car');
$maserati->printKind();
$ducati = MethodOfTransport::create('maserati4', 'cycle');
$ducati->printKind();
In PHP you can use specify a method callback using an array as a callback variable (see here), for example:
array( $object, $methodName );
So you could do this
$callback = array($this, $this->dynamicFunction);
call_user_func($callback, $this->vehicle);
Er, why don't you want to use a simple inheritance structure here? If you want different behaviour depending upon the object modelled, then that's pretty much the canonical description of polymorphism.
If you really do want to plough on with callbacks into the same object, then you'll need to do one of two things:
Drop the $vehicle parameter from your callbacks, make them private or protected, and call into them normally, i.e.
call_user_func( array( $this, 'isACycle' ) );
Mark the callback as static, make them private or protected, and call into them as follows:
call_user_func( array( __CLASS__, 'isACycle' ), $this );
Within the non-static callback, access the object's properties via $this in the normal fashion. Note also that I suggest marking the callback as private or protected, in order to prevent unnecessary outside callers; presumably, you don't want them executing the wrong method for each type.

Categories