I have a small application developed with Laravel, and I would like to share a variable (a result from a remote service, cached ) across all the controllers.
I read about ViewComposer, but they only work is a view is rendered (makes sense), and my app has many json responses.
I know that I could traditionally extend my controllers from a BaseController, but I wonder if anybody knows a way to do that without relying on inheritance.
Put that result into an object that's responsible for the caching, that you can DI that class into the controller - either in the constructor, or the specific route methods.
( If you're using laravel's caching service, then you can inject that with no extra work. )
super basic example:
class CachedResult {
public function result() {
return 'woo! caching';
}
}
...
// in your controller...
public function someJsonRoute(CachedResult $result) {
$result->result();
}
...
// in your AppServiceProvider's register method
$this->app->singleton(CachedResult::class, function() { return new CachedResult; });
You can declare the variable and/or function for the remote service in the base controller.
And in a controller that extends the base controller, you could use it like this:
$this->varName;
Related
I want to develop a website and an App for Android and Apple. An App will fetch the data via API from our domain.
Let say on our website, it will show a list of products or create user account; In the controller, I could use internal API request which will then fetch the data via MySQL rather than using MySQL query method directly on it own. Is this common practice or bad practice?
This is example of dingo/api internal request (Laravel):
Route::api(['version' => 'v1', 'prefix' => 'api'], function () {
Route::get('users', function () {
// fetch from database
return User:all();
});
});
In the Controller
class UsersController
{
public function showUsers()
{
$users = API::get('users');
return View::make('users-list')->with('users', $users);
}
}
In this example they have an API route setup for get method at users and API::get('users'); will make an internal request to that end point and return you what ever that method returns
Yes I would consider this common practice. I personally even think it's good practice to consume your own API internally. It definitely helps keeping your code DRY (Dont Repeat Yourself).
Of course it causes a bit of an overhead compared to a direct method call, but I doubt it will be noticeable. Anyways, for your consideration, an alternative would be to keep the API controllers very very flat and have most of your logic somewhere else (in the Model, a Repository or a Service Layer). I recommend doing that anyways. This would mean that you could easily do the same thing in your in your "normal" controller as you do in the API controller because it's basically just a (few) call(s) to another class.
Here's an example to illustrate what I mean
Let's say your users endpoint is a bit more complicated (This includes some eager loading and filtering)
public function index(){
return User::has('profile')
->with('profile', 'city')
->active()
->get();
}
Now of course it still isn't a lot of code and you could easily do the same in the other controller as well. But imagine you wanted to add a new relationship to eager load. You would need to change your code in two places. (If you would forget one you probably wouldn't even notice it...)
One solution to this problem is creating a repository. I won't go into the details on how to implement this pattern (there are a lot resources about this on the internet) but basically in the end you'd have a class like this:
class UserRepository {
public function getAll(){
return User::has('profile')
->with('profile', 'city')
->active()
->get();
}
}
(Ideally you would also have an interface defining your repository...)
Then use dependency injection to make an instance of the class available in your controller: (Again this is not complete you'd need a few more things to set up DI)
public function __construct(UserRepository $repo){
$this->user = $repo;
}
public function index(){
return $this->user->getAll();
}
And in your other controller(s) you could use the exact same call getAll().
Good Morning everyone. Recently i've read an article about mvc pattern saying that most of the php frameworks out there implemented the mvc pattern wrong.
php master mvc pattern part 1
php master mvc pattern part 2
Well after reading this and looking over that implementation a question appeared.
How on earth would call in the view the method called in model? What i'm trying to say is this.
This is a piece of code from the article.
<?php
$model = $_GET['model'];
$view = $_GET['view'];
$controller = $_GET['controller'];
$action = $_GET['action'];
if (!(empty($model) || empty($view) || empty($controller) || empty($action))) {
$m = new $model();
$c = new $controller($m, $action);
$v = new $view($m);
echo $v->output();
}
let's say we've written a small implementation of this design pattern after reading the article and we have the following code:
<?php
class Index extends Controller
{
public function __construct(IndexModel $model, $action)
{
$this->model = $model;
}
public function someAction($id)
{
$this->model->getData($id);
}
}
class Index extends View
{
public function __construct(IndexModel $model, $action)
{
$this->model = $model;
}
public function someAction()
{
$this->model->getData();
}
}
class Index extends Model
{
public function __construct()
{
//Some Code Here
}
public function someAction()
{
// Inserting Data into database.
}
}
As you can see we are calling the same method both in controller and in view to get the data from the database. But if i know correctly the view should take care of the controller's job so the $id wouldn't be right to parse it again in the view or something like that. Then how this can be solved?
There's no 1:1 correlation between controllers and parts of the model (note: not "models" but parts of _the model_). Just because you have an "index controller" doesn't mean you need an "index model" and "index view".
The M, V and C are not constructed together. The controller is constructed, and then it decides which model method to load/construct/invoke and which view should respond to the request.
There's discussion about whether the controller should invoke the view, or whether the model should "update" the view. Since web requests are ephemeral and there's no "constant" view, the latter makes little sense in PHP; it's more appropriate for the original SmallTalk or Obj-C or similar environments.
The first code snippet has terrible use of empty (see here) and, again, should not construct all parts together.
MVC should be approached like this:
The model is the app. It's not just a "data handler" or "data store", it is the core app. Everything the app does, business logic wise, is "the model". This includes sending email notifications, database maintenance work and such auxiliary things, they're all in the model.
The view is responsible for producing output of various forms. The view should be able to interact with the model to get the data it needs to do its job. Data should not be "pushed into" the view, the view should be able to "pull" the data it needs; otherwise something external to the view needs to know what data the view needs, which means the view logic is not self contained in the view anymore.
The controller is just the little bit of glue that's left to invoke the correct model method and view in response to the incoming request.
I typically structure these parts like this:
The model consists of various parts, including data storage handlers, "primitives" (classes that model individual business objects) and "services". The "services" contain all the "actions" your app can do and form the model API. Whenever you want to "do" something in the app like "register a user" or "fetch all records for date range X through Y", there's one specialized method for it in the service API. Just looking at this service API you should be able to enumerate all the things your app "does".
There's one object which is either a "dispatcher" or a "service locator" or simply a dependency injection container that simplifies instantiation of these service classes and allows someone to call them. The controller gets one of these and so does the view.
There's a router which does some "rough routing" based on the URL, invoking a controller method. The controller further looks at the details of the request and decides to call a model method and/or to respond with a view.
The view may decide the best way to present some data based on the specifics of the request, e.g. whether to respond with an HTML page or a JSON data blob. Yay for RESTful services.
In rough pseudo code:
$r = new Router;
$r->route($_GET, $_POST, $_SERVER); // or something like that
This dispatches to something like:
class FooController {
public function __construct(ServiceLocator $services) { ... }
public function bar(Request $request) {
$request->assertIsPost();
$this->services->locate('Baz')->froogleTheWibbles($request->getPostParams());
(new BarView($this->services))->displayWibbles($request);
}
}
class BarView {
public function __construct(ServiceLocator $services) { ... }
public function displayWibbles(Request $request) {
switch ($request->accepts()) {
case 'html' :
$this->loadTemplate(...);
...
case 'json' :
echo json_encode($this->services->locate('Baz')->getWibbles());
}
}
}
And the model does whatever it needs to do...
class Baz {
public function froogleTheWibbles(array $data) {
foreach ($data as $wibbleData) {
$wibble = new Wibble($wibbleData);
$this->wibbleStore->save($wibble);
}
...
}
}
There is no "one answer" for MVC, the important part is that the model contains everything your app "does" independent of input and output, the view can produce the right output as requested as independently as possible and the controller is just the little bit of glue that handles input conditions. There are various ways in which this can be realized. The important design principle should be the realization that the view and controller are interchangeable to fit different conditions (web page, JSON API, XML API, SOAP API, CLI invocation, ZeroMQ node etc.), but "the model" is not.
Currently I'm using a view-helper to help my debugging process. Basically I call this function and it checks if 1: I'm logged in as a developer by checking a Zend_Session_Namespace variable and 2: if the application is run in debug_mode using Zend_Registry. If both of them are true I show a number of different debug variables and any parameters I give the helper as input.
Originally this function was only intended to check that I got the right info in the objects assigned to the view, but I quickly discovered that it was useful in other places as well. At the moment the function works in controllers using $this->view, and I guess I could technically use something along new Zend_View(); or Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); to get a view-object in my models, but that is just plain ugly even if it's only for debugging.
So my question is: How can I rebuild this helper into a global function (usable in models, views and Controllers) and still be able to use the Zend_Session_Namespace and Zend_Registry objects, while (as far as possible) maintaining the MVC structure.
I think if you made a static class or a singleton class, you could have all of the desired functionality without breaking your MVC structure at all.
Consider the following simple class with one static function:
<?php
class My_DebugHelper
{
public static function dump()
{
$ns = new Zend_Session_Namespace('the_namespace'); // the namespace you refer to with the developer flag
$debug_mode = Zend_Registry::get('debug_mode');
if (!isset($ns->isDeveloper) || !$ns->isDeveloper || !$debug_mode) {
return;
}
foreach(func_get_args() as $arg) {
Zend_Debug::dump($arg);
}
}
protected function __construct() {}
protected function __clone() {}
}
This code gives you:
The ability to call from anywhere in your application (model, controller, helper, view etc)
All of the protections to prevent it from being executed when called out of context
A simple base that you can expand upon
Depending on your needs, at least one thing you could do is make it static so it could store some of the information rather than access it each call, or add additional methods or specialized parameters so you could pass a Zend_View object to it if necessary and have data injected into the view.
You could call it from anywhere in your application and pass one or more values to dump:
My_DebugHelper::dump($someVar, $this->view, $model->getCustId());
I'm not sure how/what your view helper displays data currently, but hopefully that will help you merge your view helper into the generic class that you can call anywhere.
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.
EDIT: Previous title, because no one was reading the question: "If I'm making AJAX calls in an MVC framework, is it common to have 'getter' controller methods over the model?"
It's all in the title: If I want to make an AJAX call to delete a user, that DB code clearly lives in the model $this->userModel->delete($id).
If I'm making all of the CRUD calls via AJAX, do I just have passthrough controller methods to expose those model calls to a URL?
function delete($id) {
$this->userModel->delete($id);
}
etc? This seems silly, but it also makes sense... but it also makes me feel like I'm missing something. Is this the most common pattern?
Thanks!
When it comes down to Ajax under the MVC Framework I usually tend to have each function with a specified keyword such as fetch / set.
something like this
class Users extends Controller
{
public function Fetch($id){}
public function Create(){}
public function Update($id){}
public function Remove($id){}
}
To answer your question: yes
The task of the controller is the decision maker, so that you would perform authentication checks etc within the controller for security purposes.
Think of it this way, you would not use the same controller for changing records in your administration as you would within your users front-end, but you would use the same models.
the models should be used in more places than just the front end, so you would not place a session check, input validation in the model methods as you would perform different checks depending on the location the action is taking place.
Your frontend controller would have something along the lines of:
public function Fetch($id)
{
if($this->session->get_userdata("auth_level") & USER_AUTH_LEVEL_READ)
{
//Show data
}
}
where as your administration would have:
public function Fetch($id)
{
if($this->session->get_userdata("auth_level") & IS_ADMINISTRATOR)
{
//Show data
}
}
if you place the very same check in your models then you would have generate several models that would do return the same data regardless of the location.