Symfony: where should i put business logic in models? - php

Suppose I have this models
User.class.php
userTable.class.php
I want to create a method to update the user
Action
class userActions extends sfActions {
public function executeUpdateUser(sfWebRequest $request) {
$user_id = $request->getParameter('id');
// here i want to call function to update the user
// updateUser($id);
}
Where should I put this function updateUser($id) ?
ON user.class.php --> And call it like that User::updateUser($id);
OR ON userTable.class.php --> And call it like that Doctrine_Core::getTable('User')->updateUser($id);

I'd do it this way :
$user = Doctrine_Core::getTable('User')->find($user_id);
$user->updateWithData($data); // ::update() is already an existing method
$user->save();
or
$user = Doctrine_Core::getTable('User')->find($user_id);
$user->updateWithDataAndSave($data);

Related

eloquent: How to load and set model variables, inside the model itself?

Laravel documentation suggests the following way to set up an eloquent model:
$user = user::with($conditions)->first();
What if I want to set up my eloquent model inside the model itself:
$user = new user();
$user->setup($conditions);
// class definition
class user extends Eloquent{
public function setup($conditions){
// load current object with table data
// something like
$this->where($conditions)->first();
// previous line output is dangling, is ok to assign it to $this variable?
}
}
If you're extending from Eloquent model, you may try the following approach. I assume you have a unique id column.
public function setup($conditions)
{
$model = self::with($conditions)->first();
if (! is_null($model)) {
$this->exists = true;
$this->forceFill(self::find($model->id)->toArray());
}
return $this;
}
Hope this solve your issue.

Laravel: Strange behaviour of type-hinted class when used twice in controller

I encountered a strange behaviour which I do not understand when using type-hinting in a Laravel Controller. I have a Profile controller, which should call the same function of a service twice based on different parameters. However, when I call the function the second time, the result of the first call is changed.
Here is my code; Two users' profiles should be displayed on one page:
//use statements are omitted for brevity
class ProfileController extends Controller {
protected $compose_profile_service;
public function __construct(ComposeProfileService $compose_profile_service) {
$this->compose_profile_service = $compose_profile_service;
}
public function compare($user1, $user2) {
$user1_profile = $this->compose_profile_service->composeProfile($user1);
$user2_profile = $this->compose_profile_service->composeProfile($user2);
dd($user1_profile); //Problem: This dd() gives me the profile of user2 instead of user1
}
}
class ComposeProfileService {
public function composeProfile($user) {
//Get some stuff from the DB
$profile_data = $user->profile()->get();
return $profile_data;
}
}
Of course, if I dd() $user1 or $user2 above the respective call of the compose function, the right user is provided.

Laravel 5 Global CRUD Class

Before anyone asks, I've looked into CRUD generators and I know all about the Laravel Resource routes, but that's not exactly what I'm pulling for here.
What I'm looking to do is create one Route with a couple parameters, and one global class that (uses/extends?) the Model controller for simple CRUD operations. We have 20 or so Models and creating a Resource Controller for each table would be more time consuming than finding a way to create a global CRUD class to handle all "api" type calls and any ajax json request like a create / update / destroy statement.
So my question is what is the cleanest and best way to structure a class to handle all CRUD requests for every Model we have without having to have a resource controller for every model? I've tried researching this and can't seem to find any links except ones to CRUD generators and links describing the laravel Resource route.
The easiest way would be to do the following:
Add a route for your resource controller:
Route::resource('crud', 'CrudController', array('except' => array('create', 'edit')));
Create your crud controller
<?php namespace App\Http\Controllers;
use Illuminate\Routing\Controller;
use App\Models\User;
use App\Models\Product;
use Input;
class CrudController extends Controller
{
const MODEL_KEY = 'model';
protected $modelsMapping = [
'user' => User::class,
'product' => Product::class
];
protected function getModel() {
$modelKey = Input::get(static::MODEL_KEY);
if (array_key_exists($modelKey, $this->modelsMapping)) {
return $this->modelsMapping[$modelKey];
}
throw new \InvalidArgumentException('Invalid model');
}
public function index()
{
$model = $this->getModel();
return $model::all();
}
public function store()
{
$model = $this->getModel();
return $model::create(array_except(Input::all(), static::MODEL_KEY));
}
public function show($id)
{
$model = $this->getModel();
return $model::findOrFail($id);
}
public function update($id)
{
$model = $this->getModel();
$object = $model::findOrFail($id);
return $object->update(array_except(Input::all(), static::MODEL_KEY));
}
public function destroy($id)
{
$model = $this->getModel();
return $model::remove($id);
}
}
Use your new controller :) You have to pass the model parameter that will contain the model key - it must be one of the allowed models in the whitelist. E.g. if you want to get a User with id=5 do
GET /crud/5?model=user
Please keep in mind that it's as simple as possible, you might need to make the code more sophisticated to match your needs.
Please also keep in mind that this code has not been tested - let me know if you see any typos or have some other issues. I'll be more than happy to get it running for you.
Unless you want to implement CRUD manually, consider to integrate a ready-made datagrid such as phpGrid.
Check out integration walkthrough: http://phpgrid.com/example/phpgrid-laravel-5-twitter-bootstrap-3-integration/ No models are required and the code is minimum. It can almost do anything.
A basic working CRUD:
// in a controller
public function index()
{
$dg = new \C_DataGrid("SELECT * FROM orders", "orderNumber", "orders");
$dg->enable_edit("FORM", "CRUD");
$dg->display(false);
$grid = $dg -> get_display(true);
return view('dashboard', ['grid' => $grid]);
}
You need one generic class for all CRUD operations and there are many ways to achieve that and one rule for all may not fit but you may try the approach that I'm going to describe now. This is an abstract idea, you need to implement it, so at first, think the URI for all CRUD operations. In this case you must follow a convention and it could be something like this:
example.com/user/{id?} // get all or one by id (if id is available in the URI)
example.com/user/create // Show an empty form
example.com/user/edit/10 // Show a form populated with User model
example.com/user/save // Create a new User
example.com/user/save/10 // Update an existing User
example.com/user/delete/10 // Delete an existing User
In ths case the user could be something else to specify the name of the model for example, example.com/product/create and keeping that on mind, you need to declare routes as given below:
Route::get('/{model}/{id?}', 'CrudController#read');
Route::get('/{model}/create', 'CrudController#create');
Route::get('/{model}/edit/{id}', 'CrudController#edit');
Route::post('/{model}/save/{id?}', 'CrudController#save');
Route::post('/{model}/delete/{id}', 'CrudController#delete');
Now, in your app\Providers\RouteServiceProvider.php file modify the boot method and make it look like this:
public function boot(Router $router)
{
$model = null;
$router->bind('model', function($modelName) use (&$model, &$router)
{
$model = app('\App\User\\'.ucfirst($modelName));
if($model)
{
if($id = $router->input('id'))
{
$model = $model->find($id);
}
return $model ?: abort(404);
}
});
parent::boot($router);
}
Then declare your CrudController as given below:
class CrudController extends Controller
{
protected $request = null;
public function __construct(Request $request)
{
$this->request = $request;
}
public function read($model)
{
return $model->exists ? $model : $model->all();
}
// Show either an empty form or a form
// populated with the given model atts
public function createOrEdit($model)
{
$classNameArray = explode('\\', get_class($model));
$className = strtolower(array_pop($classNameArray));
$view = view($className . '.form');
$view->formAction = "$className/save";
if(is_object($model) && $model->exists)
{
$view->model = $model;
$view->formAction .= "/{$model->id}";
}
return $view;
}
public function save($model)
{
// Validation required so do it
// Make sure each Model has $fillable specified
return $this->model->fill($this->request)->save();
}
public function delete($model)
{
return $this->model->delete();
}
}
Since same form is used to creating and updating a model, use something like this to create a form:
<form action="{{url($formAction)}}" method="POST">
<input
type="text"
class="form-control"
name="first_name" value="{{old('first_name', #$model->first_name)}}"
/>
<input type="Submit" value="Submit" />
{!!csrf_field()!!}
</form>
Remember that, each form should be in a directory corresponding to the model, for user add/edit, form should be in views/user/form.blade.php and for product model use views/product/form.blade.php and so on.
This will work and don't forget to add validation before saving a model and validation could be done inside the model using model events or however you want. This is just an idea but probably not the best way to it.

How to structure view helper with SQL in Zend Framework 2

My Zend Framework 2 Application has a view whereby I display a log of events, in a simple table format. I use several basic View Helpers to manipulate the presentation of the data in the table, but on these existing View Helpers all of the logic is contained to the View Helper itself, e.g:
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
class GetSystemName extends AbstractHelper
{
public function __invoke($val)
{
if ($val == 0){
return 'Something';
}
if ($val == 1){
return 'Something else';
}
}
}
My requirement is to build a function GetUserName to accept user_id and perform a check on the database to display the User's name, as the ID is of no value to the person using the system.
The way I see it I can either:
A) Start a new query from within the View Helper to return what I need or
B) Use a function called getUser() from within the 'User' Module / UserTable class.
The code for B is:
namespace User\Model;
use Zend\Db\TableGateway\TableGateway;
class UserTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway)
{
$this->tableGateway = $tableGateway;
}
//..other functions
public function getUser($id)
{
$id = (int) $id;
$rowset = $this->tableGateway->select(array('id' => $id));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not find row $id");
}
return $row;
}
What is the best option? And how would I implement it?
Apologies if this is a basic questions I am quite new to MVC and Zend.
In the model-view-controller pattern, the view should not be aware of the model layer. Information from the models are injected into the view through the controller.
Having your view helper call the getUser() method in your model breaks this pattern.
So, what do you do?
Have your controller get the user information into the view:
// controller
$userId = $this->params()->fromQuery("userID");
// or from session ID if this is a private profile page
// You might want some validation, too...
$userTable = $this->getServiceLocator()->get("UserTable");
// or whatever you've configured in the service config for this
$user = $userTable->getUser($userId);
// if this is a public profile page, you might want to
// exclude some fields like "password" so they don't
// accidentally get into the view
$view = new ViewModel();
$view->setVariable("user", $user);
return $view;
Then in the view.phtml you just do:
<?php $this->GetSystemName($user->whateverField); ?>

How to pass variable from controller to model - Yii

I am currently trying to pass a variable from the controller to my model. From a previous view I was passed $id in a button.
<a class="btn btn-info" type="button" href="index.php?r=recipient/index&id=<?php echo $data->id; ?>">Manage</a>
From there, I have accessed $id inside my controller and used it. However, now I am creating a function in the model that needs to use that $id. I can't pass it in as a argument because it is the function beforeSave (which updates my database before I've saved a new entry)
This looks like this in the model Recipient.php
// before you save the function here are the things you should do
public function beforeSave()
{
if($this->isNewRecord)
{
// updates the list_id of the individual with the selected ListId
$this->list_id = Recipient::model()->getListId;
}
return parent::beforeSave();
}
Finally, I am trying to create the function getListId in the same model.
public function getListId()
{
// my code here
}
Is there a simple way to pass a variable from the controller to the model to use? Or, is there a way for a function in the model to access a variable passed to the controller?
Add a property to your model and set that property in your controller.
class Model
{
public $var;
... more code ...
}
actionIndex($idList)
{
$model = Model::model()->find(...);
$model->var = $idList;
... more code ...
}

Categories