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;
Related
I'm attempting to fetch, convert and save a value in a models' constructor in Laravel 5.2. The reason being that it's saved in the database as hex, and I need to convert it to binary pretty often, and would like to do it once and save the result in a class attribute. But I can't seem to be able to fetch the value from $this in the constructor.
Here's a excerpt of what I'm working with, guid is a field in my table.
class Person extends Model {
private $bGuid = null;
public function __construct(array $attributes = []) {
parent::__construct($attributes);
$this->ad = Adldap::getProvider('default');
$this->bGuid = hex2bin($this->guid);
}
public function getName(){
$query = $this->ad->search()->select('cn')->findBy('objectGUID', $this->bGuid);
return $query['attributes']['cn'][0];
}
}
The $this->ad attribute executes as expected, but $this->bGuid does not. Some debugging shows that $this->guid when referenced in the constructor returns null. While if referenced in the getName() method directly works just fine.
My intermediate solution is creating a new function and just call $this->getbGuid(), thus making me a bit more satisfied with the DRY-ness, but it still has to convert it each time it is called.
I would appreciate it if anyone could tell me what's going wrong, so I could improve the code :)
Try to override another method from Model: newFromBuilder().
This is the one that is executed once the data is retrieved from the DB, not the __construct() one:
class Person extends Model {
private $bGuid = null;
public function newFromBuilder($attributes = [], $connection = null)
{
$model = parent::newFromBuilder($attributes, $connection);
$model->bGuid = hex2bin($model->guid);
return $model;
}
}
Note, that inside the overridden method you refer to the object as $model (instead of $this), and it has to return the $model object at the end.
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.
Whenever I use $model->attributes=$_POST['Users'] ,it saves Data from User form.
When I use $model->setAttributes($_POST['Users']),it also saves Data from User form.
So please can anyone clarify the difference between the two codes ?
With $this->setAttributes() you can assign unsafe attributes, using $this->attributes you cant.
Assigning unsafe attributes:
$this->setAttributes($_POST['Model'], false);
More info in: http://www.yiiframework.com/doc/api/1.1/CModel/#setAttributes-detail
As stated in the Yii wiki, you can use any of these. With $model->attributes you set the variable directly. With $model->setAttributes() you set the variable through a so called 'setter method'.
http://www.yiiframework.com/wiki/167/understanding-virtual-attributes-and-get-set-methods/#hh1
I would use the setter method instead of directly calling the variable, as you can add a line in your setter method, and it would apply to all of its calls, and it would save you from a lot of headache in the future.
Example:
class Model {
public $attributes;
public function setAttributes($attributes) {
$this->attributes = $attributes;
}
public function getAttributes() {
return $this->attributes;
}
}
$model = new Model();
$model->setAttributes("Foo");
echo $model->getAttributes();
$model->setAttributes("Bar");
echo $model->getAttributes();
So, now if you would like to make an additional operation on the attribute, you could add it to the setAttributes() method, and instead of changing two lines of code, you could change only one.
Example:
class Model {
public $attributes;
public function setAttributes($attributes) {
$this->attributes = $attributes . "-Bar";
}
public function getAttributes() {
return $this->attributes;
}
}
$model = new Model();
$model->setAttributes("Foo");
echo $model->getAttributes();
$model->setAttributes("Bar");
echo $model->getAttributes();
Now scale this up to a level, when it would be inconvenient to change thousands of lines of code, instead of changing a couple of setter methods.
There is absolutely no difference.
When you try to assign a property that is not defined as a PHP class property (such as attributes here) on a component, Yii by convention calls the similarly-named setter method setAttributes instead. If no such method exists an exception is thrown. Since a Yii model is a component and models do not have an attributes property, the setter method is called even when you use the first form.
All of this is also explained in detail in the manual.
$model->attributes=$_POST['Users']// means setting value of property directly while
$model->setAttributes($_POST['Users']) //is method or function which is indirectly set value of $model->attributes property;
Lets take an example
class Model{
public $attributes;
public function setAttributes($att){
$this->attributes=$att;
}
}
//Now the value of $attributes can be set by two way
$model = new Model();
$model->attributes=$value; // 1st way
$model->setAttributes($value); //2nd way
There is no difference. array_merge used to merge attributes, if set later
I'm currently improving my own MVC and I can't find a nice solution for the following scenario:
In most of my models I'm working with a few (already validated by another model) user-based inputs and need to pass them from the controller (where I basically tell the models what to do with the input) to the various models of course. At the moment I'm putting every single user input into a property:
foreach($this->properties as $property => $empty)
{
if(isset($_POST[$property]))
{
$this->properties[$property] = htmlspecialchars(trim($_POST[$property]));
}
}
Eventually when I need a new model to do something, I call it like this:
new view('calendar',$data,$this->properties);
And finally in the model I receive the input / variables by putting them in the models properties…
class validation
{
public function __construct($values)
{
foreach($values as $property => $value)
{
$this->{$property} = $value;
}
}
}
That way I never have to think about where a variable comes from (after the user input has been validated, I don't really care anymore) and can always write a for me clean to read version of $this->user_input
But I somehow have the feeling that this is not the easiest way and propably not a good one either. What bothers me the most is that when writing a new class/model, I always have to tell the model to take the input into their own property and I always have to pass parameters when calling a new class.
Is there some way where I can just inherit these variables from the user when a new class is getting called without having the controller to be a parent class - or would this actually make sense to make the controller a parent? I think it would be confusing when another controller uses the model.
Ok the big thing to remember here, is that your controller "has a" variable container (holding all your properties), as opposed to the controller being (or "is a") a variable container. So first thing, you should be using composition, and not inheritance.
The following snippets below are commented to explain in more detail. Some notes:
The InputData instance could be created above the controller level (say, in a different controller, so that is can be shared among many controllers) which answers the main part of your question. The key point is you're only writing it once, and you can safely say once it's in there, it's good to go
You can include all validation methods inside the InputData, as the role of InputData is to house/store the data safely - which in my opinion a good level of abtraction, or in other words "it's responsible for input data, if something is wrong with the input data, I know where to look"
Finally, for a little extra shine, I added some bit operations so when adding values through the input_data->add, they could be validated against multiple types (for example something could be added which needs to be validated as both a number and a post code).
index.php
require_once( "Controller.php" );
$controller = new Controller();
$controller->print_current_user();
Controller.php
<?
require_once( "Input_Data.php" );
class Controller
{
// Variables
private $input_data;
// Models
// private $model_user;
public function __construct()
{
$this->input_data = new Input_Data();
//$this->model_user = new Model_User();
// Process input (might not happen in the constructor,
// in fact, it might happen higher up, so it can be shared
// Possibly looping over GET / POST data
// for each one, add it to the inputData
$_GET[ 'name' ] = 'Chris';
$_GET[ 'country' ] = 'Australia';
// example iteration 1
$this->input_data->add( 'name', $_GET[ 'name' ], Input_Data::TYPE_VALIDATE_NAME | Input_Data::TYPE_VALIDATE_TEXT );
// example iteration 2
$this->input_data->add( 'country', $_GET[ 'country' ], Input_Data::TYPE_VALIDATE_COUNTRY );
}
// later on in controller, model needs to find the user by name
public function print_current_user()
{
// Example Usage to Model:
// $this->$model_user->get_by_name( $this->input_data->get( 'name' ) );
//
// For now, we'll settle with just printing it out
echo $this->input_data->get( 'name' );
}
}
?>
Input Data
<?
class Input_Data
{
const TYPE_VALIDATE_TEXT = 0;
const TYPE_VALIDATE_NAME = 1;
const TYPE_VALIDATE_EMAIL = 2;
const TYPE_VALIDATE_ADDRESS = 4;
const TYPE_VALIDATE_COUNTRY = 8;
protected $data;
public function __construct() {
$this->data = array();
}
public function add( $name, $value, $type )
{
if( $type & TYPE_VALIDATE_TEXT )
{
// validate input as text
// if valid, flag as such, to be inserted
// or alternatively return a safe version
// depending on your application, an empty string
}
if( $type & TYPE_VALIDATE_NAME )
{
// validate input as name
}
if( $type & TYPE_VALIDATE_EMAIL )
{
// validate input as email
}
if( $type & TYPE_VALIDATE_ADDRESS )
{
// validate input as address
}
if( $type & TYPE_VALIDATE_COUNTRY )
{
// validate input as country
}
// If its valid or is now santised
// insert into the $data variable
// if( $valid ) {
$this->data[ $name ] = $value;
// }
// data[ name ] now contains a safe value that can be accessed
}
public function get( $name )
{
// do checking to ensure it exists
// then return it
return $this->data[ $name ];
}
}
?>
Depending on your needs, it may make sense to store the user inputs in a property of a singleton class (e.g. a UserRequest class):
class UserRequest extends Singleton
{
protected $userProperties;
public function getUserProperties()
{
return $this->userProperties;
}
...other methods...
}
In your bootstrap or routing class, when you capture the user inputs, save them in your Request instance, and then have all controllers extend a base class that reads this property:
class baseController
{
protected $userProperties;
public function __construct()
{
$this->userProperties = Request::getInstance()->getUserProperties();
}
}
Then all controllers will have access to it, and you only have to capture it once.
I think a better solution is to store all the inputs in an object lets just call it data. Each of the models can have a data property. After the controller has completed input validation you can pass the object to the first model and store it there. At that point you can freely pass the object around from model to model. If you're changing values in data you should later update the controllers object with a method call like $this->data = $Model->GetData(); or whatever.
With the MVC paradigm it's not sensible to have models accessing properties of the controller. The controller should basically be initiating all communications ie the controller passes the data to the model who does operations on it, then the controller requests that data and puts it in the view. It would not be good practice to have the controller holding the data and the model operating on it directly.
What bothers me the most is that when writing a new class/model, I always have to tell the model to take the input into their own property and I always have to pass parameters when calling a new class.
So let's say you have two problems here:
Repetition to define properties per each class definition.
Passing parameters for each class creation.
In the most bare and basic sense, you can not circumvent both. If you won't tell the class (at least somehow) which properties it represents, it wouldn't know. Somewhat similar for the second point, if the data is not set to the class, it won't work.
So as it is technically not possible to prevent these two at all, the question is how to make it more comfortable and reduce repetition - if possible.
One route to go would be to just take all these objects to be of the same type. I mean actually those are just some improved arrays, aren't they?
So you can create yourself a base-class you can extend from that contains all the needed code, like importing an array, defining the properties.
So you only need to write the code once and create as many objects and different "types" as you want.
Some example, let's create one such object that has a base-class that does it's job:
class TestModel extends SelfDefinedVariableObjectBase
{
protected $properties = ['bar' => 'hello world'];
}
That's it.Object defined. Now let's use it:
// $_POST['bar'] = '<h1>test</h1> let\'s throw some HTML in';
$foo = new TestModel($_POST);
echo $foo->bar, "\n";
This does import some data from $_POST that is matching with the objects properties (similar to what you have). However the output is the same:
<h1>test</h1> let's throw some HTML in
You might now want that. So therefore you can create some decorators for example, here one that works with a callback function:
class VariableObjectCallbackDecorator
{
private $subject;
private $callback;
public function __construct(VariableObjectBase $object, callable $callback) {
$this->subject = $object;
$this->callback = $callback;
}
public function __get($name) {
return call_user_func($this->callback, $this->subject->__get($name));
}
}
Let's use it with the test-object from the previous example:
$bar = new VariableObjectCallbackDecorator($foo, 'htmlspecialchars');
echo $bar->bar, "\n";
And now this time the output is:
<h1>test</h1> let's throw some HTML in
Hope this is helpful. You can find the code here: Demo
would this actually make sense to make the controller a parent?
Yes, that is probably exactly how I would do it. Then you can use protected for the properties you want to share/inherit.
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 ).