How can I use dynamic entity names in a controller action, in Zend framework 2 using Doctrine 2?
For eg.
public function indexAction()
{
return new ViewModel(array(
'albums' => $this->getEntityManager()->getRepository('Album\Entity\[dynamic_entity_name]')->findAll()
));
}
Also, in first place, can I even USE multiple entities in a single controller, like my case here?
The root of doing something like this is, I basically have two modes in my application, live and test, where the users can save data in either mode (something like sandbox and live modes of a payment gateway back-end).
I need to have two different tables, one for each mode; say for e.g., payment_test and payment_live tables for the payments that user makes.
So in my controller, based on the current mode (test or live) that user is using, the data should be retrieved from / saved to the respective entities (PAYMENT_LIVE or PAYMENT_TEST).
I believe checking conditions for the current mode at all the places is a bad bad idea, hence I will just set it in some CURRENT_MODE CONSTANT once, and then use it for using the entity name dynamically, something like:
public function indexAction()
{
return new ViewModel(array(
'payments' => $this->getEntityManager()->getRepository('Payment\Entity\Payment_'.CURRENT_MODE.')->findAll()
));
}
which will use Payment_live entity for live mode and Payment_test entity for test mode, based on value of CURRENT_MODE = "live" or "test".
Any thoughts how should I go about implementing this?
My first thought was: Why having two tables and not just an identifier to query the mode for. A field insire you table payments called payment_modus (could be a boolean for live true/false) or something.
Other than that, of course you can have multiple repositories in one controller.
$repo = 'Payment\Entity\Payment_'.$this->getCurrentMode();
$em->getRepository($repo);
Kinda difficult to answer since i don't really understand where your problem actually lies.
Related
I need to extensively use statuses in mt project. I need them for my users (active, suspended, etc), an entity (active, pending_activation, inactive) and for my subscriptions(active, on_grace_period, not_subscribed, never_subscribed).
So far I thought that the best way is to store them in the DB but i have a feeling it's much easier to have them in the other 3 options.
I also thought that i can store them in my Eloquent Model as constants. For example my subscription model would look like this:
// SubscriptionModel
const SUBSCRIBED_ACTIVE = 1;
const SUBSCRIBED_ON_GRACE_PERIOD = 2;
const NOT_SUBSCRIBED = 3;
const NEVER_SUBSCRIBED = 4;
and retrieving them, for example in a blade view:
// subscription/index.blade.php
#if($user->subscription->status == /App/SubscriptionModel::SUBSCRIBED_ACTIVE)
<div>You are subscribed. Thank you</div>
#elseif($user->subscription->status == /App/SubscriptionModel::NEVER_SUBSCRIBED)
<div>You need to create a subscription before being granted full access!</div>
#elseif(...)
// and so on
How about doing the same but using the config folder and adding a file called status.php. Accessing it in the view would be like:
#if($user->subscription->status == Config::get('status.subscription.SUBSCRIBED_ACTIVE'))
<div>You are subscribed. Thank you</div>
#elseif(...)
// etc
Is there a better way?
Also, how about the other part of the equation, meaning the status stored in the DB. Should I only have a status column for the subscription table and store what the app dictates or even bettter create a separate table subscription_statuses and have a foreign_key subscription_status_id in the subscriptions table?
I tend to create a specific model for statuses, that acts as an enum. So if I have an Event model, I may have a corresponding EventStatus model that looks like this:
class EventStatus
{
public const CANCELLED = 'EventCancelled';
public const POSTPONED = 'EventPostponed';
public const RESCHEDULED = 'EventRescheduled';
public const SCHEDULED = 'EventScheduled';
}
I can then do checks like this:
$event->status === EventStatus::CANCELLED;
And I’ll usually add convenience methods to my models too:
class Event extends Model
{
public function isCancelled(): bool
{
return $this->status === EventStatus::CANCELLED;
}
}
For the “human-friendly” strings, I’ll then have a language file that has the text strings:
<?php // resources/lang/en/event_status.php
return [
EventStatus::CANCELLED => 'Cancelled',
EventStatus::POSTPONED => 'Postponed',
EventStatus::RESCHEDULED => 'Rescheduled',
EventStatus::SCHEDULED => 'Scheduled',
];
In my applications I do similar to #Martin Bean except I don't create separate classes for status, I store that inside the existent class/Model.
I'm going to call user, subscription and entity a entity.
Entity have a status that exists in it's Model and table in the database.
Each Model have constants of possible values of status like ACTIVE, INACTIVE, PENDING, etc, and those may vary for each Model.
Create methods for dealing with it like getStatusLabel(), listStatus(), isActive(), isX(), etc.
Those isActive/X() are only created if really necessary, maybe a Model have 4 status but you only do comparisons against one specific, so I'd create only one isX() for that status.
Example
class User
{
const STATUS_ACTIVE = 1;
const STATUS_SUSPENDED = 2;
const STATUS_INACTIVE = 3;
/**
* Return list of status codes and labels
* #return array
*/
public static function listStatus()
{
return [
self::STATUS_ACTIVE => 'Active',
self::STATUS_SUSPENDED => 'Suspended',
self::STATUS_INACTIVE => 'Inactive'
]
}
/**
* Returns label of actual status
* #param string
*/
public function statusLabel()
{
$list = self::listStatus();
// little validation here just in case someone mess things
// up and there's a ghost status saved in DB
return isset($list[$this->status])
? $list[$this->status]
: $this->status;
}
/**
* Some actions will happen only if it's active, so I have
* this method for making things easier.
* Other status doesn't have a specific method because
* I usually don't compare agains them
* #return Boolean
*/
public function isActive()
{
return $this->status == self::STATUS_ACTIVE;
}
}
I do not agree with the other answers. Your status information should be stored in the database. A well designed database should be clear and usable without the application. What happens if you decide to use this database to power something like a mobile application as well? You will be taking some of the information away from the database and storing it only in Laravel, meaning you would have to duplicate that list of statuses in your mobile application too, and maintain it across the two.
This kind of information should be stored in the database.
Option 1
If your users can only ever have one status, then you should use an enum field with the values subscribed, subscribed-grace, not-subscribed, never-subscribed
This is just as simple in your views:
#if($user->subscription->status == 'subscribed'
Option 2
If however, you might have multiple statuses, then you should almost certainly have a separate field for each status, and use a TINYINT to store a 1 or 0.
Separate status table?
I cannot see a good reason to use a separate status table unless you anticipate you might add many more statuses, and even if you are adding more, you can just add new values to the enum or add a new field depending on which option would suit.
A status table would be ideal if you plan to use the statuses for many other tables in the database besides users.
The only other reason for a seperate status table would be if you decided to change the meaning of a particular status. This would mean you could rename the status in the status table, but the users would still be linked to it via it's primary key. Changing the meaning of a status with the previous two methods would involve changes to the structure.
It really comes down to how you anticipate you will use them, but there is no reason not to keep them in the database.
There are advantages and disadvantages to each method. It's good to be aware of each.
Table - Pros and cons (AJReading's method):
Adding and maintaining a table SEEMS tedious
Just having another table and model can make our code feel more cluttered (not saying it's a good reason not to use just saying it's kinda true)
It gets awkward when we have application logic dependent upon something in the database (things in the database feel like they should be variable, when we base application logic on them they're required)
Now we have migrations, but before them these used to be the bane of developers existence (they would make switching between servers an awful chore because you had to remember to add new statuses or your app would crash)...you would have had to do this with any database change but still these were the ones I'd have to do the most frequently
Good for data integrity
Using constants: Pros/cons (Martin Bean's method):
Avoids the disadvantages above
These are easy to reference in your code and base logic on
You don't have to create a new model or table even (he does in his example, but you could also just put them in the Events model)
They're great for values that will ONLY be used behind the scenes
They reduce the amount of queries
They just don't feel like as much work. They seem easier to refactor.
Con: they get kinda awkward when you get into labeling them, retrieving all of them, getting descriptions, etc. The translation solution is a good one but if you don't use translations in your app then this is a bit awkward as well.
Ultimately they're breaking the ORM flow you have going. If all your other models extend Eloquent then this breaks the mold a bit.
There's no real agreement on how to best do this. A lot of people use a different method each time.
Like AJReading said, if you need to use the database alone for another aspect of the project it won't work
I use the constant method but sometimes I'd think my code might be cleaner and simpler if I'd used tables. It's a hard call. I'd like there to be a well documented solution for the constant method to at least create consistency but I haven't seen one yet. Either way I don't think there's a right or wrong answer. Pick one and go with it!
For decisions of this nature, ask yourself this:
"Will there ever be an instance of my application where it would make
sense for these constants to have different values?"
e.g. a test environment, some sort of clone, some not yet defined but possible future version...
If the answer to that question is "yes", then it should probably go in application config.
If it is unlikely, (or daft) to have the values change, they belong to, and should go in the model.
I suggest in this case there would be no sensible reason to ever have a version of the application with different values, so I'd put it in the model.
I have a couple quick conceptual questions about saving models in PHP's Yii framework. I've run into this code a couple of times $model->save() (for example if($model->save())....
but I've never quite understood what it means.
Also, I read in the MVC Tips/Handbook that we should try to save our models in the model and not the controller - could someone explain why that is? I have a friend who has told me that it doesn't matter - but, I'd like to understand the rule behind it.
Thank you for you help!
What does $model->save() do?
Just check the source, it's on github. Apply logic, and the answer is pretty predictable.
As the docs clearly state: the BaseActiveRecord represents a data object. It could be a row returned from a MySQL query, or a processed form being sent by a client, or a MongoDB document, or whatever.
Calling save on that object either inserts the data into the DB you chose, or attempts to update that record. Depending on the insert/update call being successful, it returns a boolean (true if save succeeded, false if it failed).
It's pretty intuitive, really. If you want to learn more about the tools/frameworks you are using, common sense dictates you check out their online documentation. Yii's docs seem to me to be pretty comprehensive and easy to navigate: check them here.
Why save models in the Model?
Well that's easy, but it requires some disambiguation. The term "model" is often used to refer to the data containers. The objects on which you call save in this case. They are data models, true enough, and they are used to carry data back and forth throughout your application. In Yii, what some call models are called "ActiveRecords".
In the acronym MVC (as you know Model View Controller), the Model part actually covers a lot more than mere data containers. That "Model" (with a capital M) refers to the Model layer, also known as the logic or business layer. It's the part of your application that actually will contain the bulk of the code. It's there where the more complex computation is handled, it's the layer where you'll connect and query the DB. And it's this layer that has methods that the controller will call. These methods will then return data models (lower-case m) containing the data or the result of the computation that the controller will then pass on to the view.
If you want to know what logic/jobs/classes make up the Model layer, simply ask yourself this simple question: "What doesn't this bit of do?" If it doesn't handle the raw request, and it doesn't present the data to the user (those are the jobs of the controller and the view respectively), it's part of the Model layer, with the exception of a router component, dispatcher and all that that ties an MVC framework together, of course.
Controller actions (the methods in a controller, obviously) should, therefore be quite small. All they really do, 9/10 times, is pour the request data (form submissions and the like) into a model, and call one or more methods on a service (which is part of the Model layer). These methods will receive the models created in the controller as arguments, and set to work with them.
The controller can perform some basic validation, but the Model layer will dot the i's and cross the t's.
Once the Model layer has done its job, it's back to the controller which has only two things left to do: Did the Model layer return data that it expects or not? If so, pass it on to the view. If not (an exception was thrown or nothing was returned) -> handle the error/exception and, if required, redirect the user.
So in short: The Model layer is the bulk of your code, and it communicates with the controller (and internally) through data models. The Model layer never communicates with the view directly, nor does it redirect the user or handles raw input like $_POST data.
Here's a couple of links to posts of mine where I explain this even further, complete with graphs and what not. They are code-review answers, so ignore the bits that deal with the code itself, but the background information may be relevant to you:
CodeReview: How to put XML results in the MVC pattern?
CodeReview: PHP MVC: how to do $_POST the right way
As I understand in your case $model variable it's instance of BaseActiveRecord class.
So when you call:
$model->save();
Yii run mechanism to insert/update data in data storage.
The save() method return true or false, which does mean model saved or not.
So when you write:
if ($model->save()) {
//some code will be here
}
you check saved model or not.
This tutorial describe how Yii implements MVC practices.
It will insert a new row into the table that the model represents.
i.e. If I have a model called $user that represents a table called users, then calling $user->save(); will insert a new row into the users table.
if($model->save())
Would be the same as:
//Attempt to insert row
$inserted = $model->save();
//If insert is successful.
if($inserted){
//Do this
}
Note that many frameworks will also allow you to update a table row via the save function. In those cases, a where condition is attached or the primary key of the row is passed in.
$model->save() are using for insert and update data in database.
I have two Models:
Server (belongs to a Slave)
Slave (hasMany Servers)
In a Controller I need to get an array with information about a Server/Slave (and some additional informations, like business logic that can't be in Controller).. I thought to create a function in Server Model to build the array, and every field that I need from Slave I would just to call a function like this:
Model Server:
// I created this function for code easier to maintain
function getSlaveId($server_id){
$this->id = $server_id;
return $this->field('slave_id');
}
// Return the array that I need, with informations from Server and Slave
function getArrayByServerId($server_id){
$slave_id = $this->getSlaveId($server_id);
return array(
'slave_name' => $this->Slave->getName($slave_id)
// some other information that some did not even pull from some table..
);
}
as you can see, I created a function to pull a field from Server, because if one day that changes, I'll have to change only in one place .. the same goes for the Slave whose I'm thinking of using a function to pull each field too ..
So, the question is: should I to get Slave's info with a function for each field or there is another better way to do? (I need almost whole Slave's table info, except some fields..)
You could use the Containable behaviour which will pull the necessary information without complex logic like this. Using the behaviour you could make the request like:
$this->Server->find('first', array('conditions'=>array(...), 'contain'=>array('Slave')));
This way you don't make your models unnecessary fat (healthy are they :)) and you will take what is required. With containable you can get specific fields too.
I have a practical doubt ,
I am using OO php , and i am new to it. I am using zend framework to be clear.
I am writing controllers(class) and actions(methods) with in it say PatientMapper.php which has all single mysql table related actions and Patient.php which has all setter and getter functions.
I get a doubt that when should i write a new controller.
Should i write a controller for all the actions on a single mysql table .
or a single controller for all actions related to a module.
As opposed to the previous answers, I would say that your controller should not be related to your DB.
Controllers don't handle business logic, your models do.
Besides that, you can write a controller for each entities.
User is an entity, which can be wrapped in a controller, even if it depends on several tables.
If your controller is getting bigger and bigger, you can switch to module (Zend Framework terminology) and create an User module, which has an Account controller, etc...
I think you should write controller for single mysql table, because if your application will grow up you can end with few thousand line controllers.
A controller groups actions that conceptually belong together somehow. The controller might use one specific model class (which is not necessarily a database accessing class) only, but it may also use many of them.
Important is, that the controller should not contain the logic of the model classes. The sole responsibility of a controller is to receive and delegate the input for a specific interaction you allow users to do with your application to the model. And in webbased MVC, it is usually also responsible to update the View according to the result of the operation.
The most important distinction one has to understand in MVC is that M should be able to live on it's own while V and C belong together. V and C form just the UI to your application and they should not do anything beside that. Basically, your M is your application, while your VC just sits on top of it. Should really be M|VC imho
With that said, if you feel your application can get away with a single Controller, then use a single appController. But once you find yourself adding actions that could conceptually fit into a separate controller, then add a new controller. If your application is a simple CRUD app, then have one controller per database table. If it does something else, then give it something that fits the scenario.
IMHO I would suggest a action for each mysql table related action
for maintainability. These would be ligtweight actions that just call your model for that table
#gordon - Yeah my application is a CRUD application. SO i need to create a model for each table..This is the most accepted way rite. And yeah i am bit clear abt controllers..
i have a page where in i need data from 3 tables. So i will need to call all 3 model methods to get the data rite...
I have a small doubt...i use code like this at the beginning of the beginning of class .and this was written by other developer....i am using it.. i am finding it difficult to use joins ,bcos this is locking the DB..any help on how to use joins over here
protected $_dbTable;
public function setDbTable($dbTable)
{
if (is_string($dbTable)) {
$dbTable = new $dbTable();
}
if (!$dbTable instanceof Zend_Db_Table_Abstract) {
throw new Exception('Invalid table data gateway provided');
}
$this->_dbTable = $dbTable;
return $this;
}
public function getDbTable()
{
if (null === $this->_dbTable) {
$this->setDbTable('Application_Model_DbTable_Appointment');
}
return $this->_dbTable;
}
this is the select part..not able to use join
$select = $this->getDbTable()->select()
->from("patient_appointment",array('pa_pd_patient_id',
'DATE_FORMAT(pa_datetime,"%h:%i %p") as pa_time','pa_datetime','pa_um_id'
,'pa_created_date','pa_mode','pa_type'))
->where('date(pa_datetime) = ?', $date)
->where('pa_pd_patient_id = ?', $patientId)
->order('time(pa_datetime)');
$resultSet = $this->getDbTable()->fetchAll($select);
I want to add a user in users table via link like '/index/adduser/id/7' .
Question
Should I validate user input inside 'adduserAction' function inside controller or somewhere inside model file? I've put files containing database related functions inside 'models' directory. Suppose a user is added to a table via 'id'. This id is sent via 'get'. And finally its added to table by 'AddUser' function (inside model file). Then I should validate this 'id' inside 'adduserAction' or 'AddUser'.? Scalability-wise, would it be better to do it inside 'AddUser'?
There's a popular believe / paradigm that states:
Thin controllers, fat models.
What this means, is that your controller should only be responsible for doing the bare minimum to make sure actions change the state of models and serve the right view in return. With this in mind, the validation should occur in your models. But... hold on for a minute. Models aren't necceseraly 1 tiered layers.
I believe among .NET programmers the following setup (or something similar) is a pretty common practice (if the scale of the project validates it):
Controller
-> ServiceLayer
-> Repository
-> DataObject
And I'm starting too like this setup more and more. Moreover, I believe this setup is very doable in a Zend Framework environment too.
The term Model is somewhat of a vague term. In the above you could consider the three last layers as your Model layer. What the three layers represent is the following:
ServiceLayer:
Responsible for business logic. In other words: retrieving Dataobjects (Models) from the repository, tying Models together, AND validating Models before storing them, mailing a user, etc..
Repository:
Some type of persistence mechanism (like a Database), that serves DataObjects to the service layer, and stores DataObjects back in the persistence mechanism (after the service layer validated them)
DataObject:
You might consider this the actual Models. Preferably DataObjects have common interfaces (independant of the Repository that is), so that Repositories are interchangeable. In other words, when the repository changes from a database to an XML file from some webservice, the DataObject still has the same interface the service layer and ultimately the view can work with.
Hope this makes sense. This is basically my understanding of a more layered MVC setup right now. If anybody feels I have things mixed up please feel free to correct me.
Please keep in mind though, that not all projects dignify such a layered setup. In smaller projects you could perhaps do with just a 1 layered Model layer. In that case, validating should still be the Model's responsiblity. The controller should be thin (just for tying Model state and Views together through actions).
I would say put the validation in your model. You can then keep your validation rules in a central location. How should your controller know the exact length of a valid user name? That is model territory. Your controller can ask the model if a user name length is correct or not sure, but the rule itself needs to be in your model. In my controller I would do something like this:
$model = new Model;
$model->loadFromArray(something to get post);
if (!$model->isValid()) { forward back to form }
$model->save();
the ideal solution is to use validation inside your forms - i.e. appending it to your zend_form_elements - see http://framework.zend.com/manual/en/zend.form.elements.html
I'd do it in the Controller, not the Model. IMHO that's the better place because then the sanitized data is secure to use in the controller already. That's a good thing for comparing things, etc., even before the data is actually saved.
I know it's already answered, but I remember the "younger me" combing the web for some choice resources on sites like this and would like to share my research and what I do here. I do the following:
I use forms to do input validation
and filtering Do my validation inside
models
I have a validation method
which proxies the form validation
method.
This validation method can called upon
internally by model methods or externally
by the controller or view.
Here's a quick example:
//UserModel
class Default_Model_User
{
protected $_form;
public function getForm()
{
if(!isset($this->_form)) {
$this->_form = new Default_Model_Form_User();
}
}
public function validate($data)
{
if($result = $this->getForm()->isValid($data)) {
// if you have custom validation conditions outside of the form, then you
// can do the validation here also.
if($data['controller_entered'] == 'some value') {
$result = false;
}
}
return $result;
}
public function saveUser($data)
{
if($result = $this->validate($data)) {
// do something.
}
return $result;
}
}
If you haven't read it already, be sure to check out the Surviving The Deepend book freely available on the following URL:
http://www.survivethedeepend.com/zendframeworkbook/en/1.0
This chapter is specific to your dilema:
http://www.survivethedeepend.com/zendframeworkbook/en/1.0/implementing.the.domain.model.entries.and.authors#id1491270
You will no doubt run into other issues as you progress through... It may help to check out the comments on my blog post regarding the model layer where I cover this issue: http://www.rvdavid.net/my-zend-framework-model-layer-part-service-part-orm/
Hope this helps someone out.