Initialise view variables for new record - php

In my MVC, I populate forms with data from the model using an array. I am using PDO and fetch associative array this gives an array of fields that I can use to populate the view.
When the user requests a new record, the array is empty and unless I explicitly test the value of every variable before use, the script falls over with a non-existant index.
My approach previously was, for new records, to setup an empty array and pass this to the view. This is fine for simple forms, but when the view needs to use 10-15 variables this is a bit tedious.
What is the preferred method of doing this?
Should my view test every field before use, or should I create the empty array. If so, should the empty array be created in the controller or the model?
As an example, If the user wants to edit an existing record, the controller passes the ID number to the model and asks it for an array of current values for the record.
The controller passes this array to the view which then incorporates the values into a form for editing.
In contrast, when the controller receives a request for a new record, it knows there is no point in asking the model for the record because its new. It can't just call the view because the passed array does not contain the keys required by the form.
My current approach to this is to initialise an array of empty keys but this seems tedious, time wasting and prone to error as it needs to be maintained if the model changes.
eg:
$this->view->class['Code']=NULL;
$this->view->class['Description']=NULL;
$this->view->class['Image']=NULL;
$this->view->class['Judge']=NULL;
$this->view->class['Entries']=NULL;
$this->view->class['Absentees']=NULL;
etc
There has to be a better way?

This is kind of a band-aid for poor MVC design, but you could use a function like this,
function idx(&$array, $index = 0, $default = null) {
return isset($array[$index]) ? $array[$index] : $default
}
In the view if you normal did $class['Description']
you would now use idx($class, 'Description')
You should not have to pass each attribute of your model individually. Instead, just pass the entire model object and access it from the view. Example:
$this->view->entry = $myModelInstance; where $myModelInstance is an instance of Entry or whatever class has the Code, Description, Image, Judges, etc attributes.
Then in the view, use something like $entry->Description

In my opinion setting propper defaults is a model issue.
Imagine a class like this:
class Car {
protected $color;
protected $vendor;
public function __construct($color, $vendor) {
$this->color = $color;
$this->vendor = $vendor;
}
public static function getDefault() {
return new Car('unknown', 'unknown');
}
}
However. You told that you use arrays. You'll find a similar way for arrays. I would suggest to write a function like getDefaultWhatever() and place it in model part of code.

Related

What is the proper way to save form data in Laravel (using an injected model)?

I'm trying to setup a simple form to save, but want to be sure we are using best practices, like DI.
In the controller file, I have
public function store()
{
//get form data
$data = Input::all();
$newclient = new Client($data);
$newclient->save();
return Redirect::route('clients.index');
}
But that really isn't dependency injection. (right?) I injected the model like this
public function __construct(\Client $clientmodel)
{
$this->clientmodel=$clientmodel;
}
How would I save the form data on the store function properly, using dependency injection?
Looking at the __constructor in Illuminate\Database\Eloquent\Model you can see it uses fill() to assign the passed in values.
public function __construct(array $attributes = array())
{
$this->bootIfNotBooted();
$this->syncOriginal();
$this->fill($attributes);
}
So you can just use fill() to do the same after the class has been instantiated:
$this->clientmodel->fill($data)
$this->clientmodel->save();
Or if you want to just save it anyways, you can use create():
$this->clientmodel->create($data);
If you are always creating a new object then you can use the Eloquent Model's create method like so:
public function store()
{
//get form data
$data = Input::all();
$this->clientmodel->create($data);
return Redirect::route('clients.index');
}
If it's possible that sometimes this route will be handling updates of an existing Client record then you should take a look at the firstOrCreate and firstOrNew methods.
What you did is just a good practice. That'd save you a lot of codes. However, there are more remainders.
Always iterate over each input to check which input is absent. Well, in your case, it's a simple form. But if it's an API, clients send various inputs and you need to know what to expect. Sometimes when an input is absent, it can cause serious problems like assigning the value of an undefined input to a model.
Always check whether an input is valid. Make sure every input is up to your standard. You can make various validations to make it happen.
Other than the above two points, you've walked pretty far on the right track.

How should PHP classes interact with the MySQL database?

The other day, while developing my PHP project and implementing the User class, i started to wonder how this class should interact with the MySQL database the project is using.
Let me start with an example: let's say I have a getName() method, inside the User class, that returns the user's real name. What's the more fitting way to implement that method?
I came up with 2 solutions:
I put the DB query inside the getName() and only get what I need like this:
public function getName() {
// MySQL query code here
}
I create a load() method inside the User class that load all the user data inside the class structure and then the getName() is something like this:
private $name;
// Load all user data inside the class' structure
public function load() {
$this->name = // MySQL query here
}
public function getName() {
return $this->name;
}
I thought, not sure if mistakenly or not, that the first way is more efficient because i only get the data I need, while the second way is more OOP but less efficient.
So, here's the question: what is the better way? Why? Are there better ways?
Either way, consider storing/caching the results of that so you do not make a query every time you use getName on that object.
Also, consider not wrrying about all that by using a ORM/DBAL Solution like propel or doctrine.
Also check out Lazy Loading and the Active Record Pattern
Run your query just in time and only run it once (unless you know the value might change), try something like the following:
class User {
protected $data;
function getName()
{
if (!isset($data['name'])) {
// if you can load more than just $this->data['name'] in one query
// you probably should.
$this->data['name'] = // query here
}
return $this->data['name'];
}
}
Aside from the question being kinda broad (as there are countless patterns), the second way you mentioned is better IMO, and to add to it I would also suggest supplying ID as a parameter which you could then use to build a single query to fetch the user by ID and then manually assign all properties (from the fetched row).

Php Yii: parameter passing to action vs load model in action

I'm trying to optimize my code, and i can't decide on what to use, and whichever is the best practice.
I have a view say view1.php, that is rendered by an action. Now view1 contains a model $model that was passed on to the view by its action; now i'm using the $model again to use it in another different action like below:
view1.php:
$studyDetails = $this->actionStudyDetails($model);
and in the StudyDetails action, i'm going to use the $model,
StudyController.php:
public function actionStudyDetails($model){
//do some processing of the model here and return an object
}
My question is, is it a good idea to pass an entire object that's already been loaded, supposing the model is very large? in terms of optimization , or probably best practice?
or should i just pass the id or primary key say $model->id? and then load the model after; making my action like this:
StudyController.php:
public function actionStudyDetails($id){
$model = $this->loadModel($id);
//do some processing of the model here and return an object
}
Should i pass the entire object unto the action or is it best to just reload the model once inside the action? Thanks, i hope i explained it well
I much prefer loading that single row the database. It's an optimization I wouldn't worry about until it becomes an issue.
You can store the model in your controller to prevent running the same query multiple times:
// Store model to not repeat query.
private $model;
protected function loadModel( $id = null )
{
if($this->model===null)
{
if($id!==null)
$this->model=SomeModel::model()->findByPk($id);
}
return $this->model;
}
It's a trick I learned here.

Hide columns when serializing via toArray()

I have a simple problem where I often return CRUD type Ajax requests with array serialized versions of Doctrine 1.2 models. I'd love to be able to simply return the toArray() method after the execute() result, however, this will display data about my models that I don't wish to expose. A simple example is on my user model the password and salt get displayed. While I realize those are already hashed values, it's something I'd rather not return as a JSON response.
I've poured over the Doctrine 1.2 manual, but did not find anything that offered the type of functionality I'm looking for. I realize I can iterate over the result to manually unset() the columns I wish to hide, but I'm hoping a more native solution is out there that I've overlooked.
Why don't you build your own toArray() ?
If you want to do that, you will have to extends the sfDoctrineRecord class that inherit from all Base* class. It is describe in the doc.
You have to put the configureDoctrine() inside config/ProjectConfiguration.class.php.
Then you will have a class like that:
class myDoctrineRecord extends sfDoctrineRecord
{
}
So you can easily add your custom toArray() here:
class myDoctrineRecord extends sfDoctrineRecord
{
public function toArray($deep = true, $prefixKey = false, array $excludeFields = array())
{
// do every thing like the original toArray
// but when a column match one entry in $excludeFields, don't add it
}
}
So, when using the toArray() method with an array of fields for the third parameters, they will be excluded from the result.

MVC pattern (need view object in model)

I'm using the MVC pattern in my application.
Now I need the view object in a model.
I don't want to add the view as a parameter for my function in the model (since I need it in other functions as well). And I don't want to keep on passing it.
Should a add the view as an attribute for the constructor of the model?
Is there another way? Shouldn't I be needing the view object in the model in the first place?
What would be the preferred way of doing it?
Example:
Controller
function someAction()
{
$somemodel->add();
}
Model
class SomeModel()
{
function add()
{
if ($view->user) {
// do stuff
$this->mail();
} else {
// do other stuff
}
}
function mail()
{
Mailer::send($view->user->email, $this->getitems(), $view->layout);
}
function getitems()
{
return Items::getitems($view->user);
}
}
If you're really doing MVC, then you won't need the view in the model, because only the controller should have access to the view.
Looking at the code you've provided, I can tell one thing: the add() method should not reference $view in any way (even for accessing its properties). Instead, the model should be provided with the $view->user value from the controller. The same goes for the mail() method.
Consider fixing those issues. Otherwise, you'll get into something worse later on.
The model should be separate from the view. So, as mkArtak said, the controller should be the only thing that communicates with the view. Which then passes only the necessary information to the model.
As for the model, it should really only deal with the information that it understands.
i.e. if you had a Car model... you don't want to build it dependent on it's factory. If you did, you would have to change your code if you wanted to build it in different factory.
The controller is where you 'bake' everything prepare for render. By bake I mean you consider any passed in $_REQUEST params, make model API calls to get the data you need, and set template variables to be rendered. Your action, at the end of this process should make a call to a template (view) you choose in order to render the 'baked' template variables.

Categories