cakephp calling controller action from model - cakephp

I have a shopping cart site and on successful purchase I need to send a mail with all product details in the order as attachment. I have used fat model skinny controller approach and all my functions are in model. I have a controller action which will give the order details by passing order id along with view. Using dompdf I can convert this html to pdf and can create a file. So for creating attachment I can use the same function by passing some parameter. My mail sending code is in model. From here I need to call the controller action and need to get the pdf file name that just created. I know calling controller action from model is against MVC architecture. But how can I achieve this functionality ?

'fat' models is a good thing to do, however, try not to put things in a Model that should not be in a Model. In MVC, Models should handle all things related to data.
Fat models
The 'fat' Model concept is to reduce the amount of code in your Controller, by moving data related code to the Model. for example:
In stead of this; (in your Controller):
public function view($id)
{
$this->request->data = $this->SomeModel->find('first', array(
'fields' => array(
// list of fields to retrieve
),
'conditions' => array(
// conditions
),
// etc.
);
}
Move the find instructions to a method inside your model and use this:
public function view($id)
{
$this->request->data = $this->SomeModel->someMethod($id);
}
Other locations to put your code
Code that is not related to data, can also be moved outside your Controller (to make it 'skinny'). CakePHP offers other locations to move your code to, for example inside a Component
Then inside your Controller;
this:
public function view($id)
{
$this->request->data = $this->SomeModel->someMethod($id);
// use functionality of a component
$this->SomeComponent->doSomething();
}
Triggering functionality via Events
To keep code and logic outside your controller, CakePHP 2.x now offers an 'Event' system. This allows you to execute code if a certain event happens. You can pass additional information through the events (the event will become a 'communication channel' that passes through your application).
Sending e-mails for certain events is a good example. The CakePHP also uses sending mails to illustrate the Event system in CakePHP; this is probably what you are looking for:
Dispatching Events - send emails

Make your model method return the data so you have it in the controller and pass it to the other model function together with your pdf related data.

Related

How to use: $this->Auth->user('id') in a model? Cakephp 3.0

I've been working on the skinny controller fat model way. Before, I used this in my controller:
$this
->find('all')
->contain(['Declarator'])
->where(['user_id' => $this->Auth->user('id')])
->order(['Declarations.created' => 'DESC']);
However, $this->Auth->user('id'), doesn't work in a model.
What other way is there to get the id from the authenticated user in a model?
What other way is there to get the id from the authenticated user in a model?
Simply pass it to a model method:
public function someModelMethod($userId, array $postData) {
// Do something here, move your code from the controller here
return $something;
}
public function someControllerAction() {
$this->set('data', $this->Model->someModelMethod(
$this->Auth->user('id'),
$this->request->data
);
}
Cake doesn't have a layer that would take the business logic so most of the time it's put in the model layer. Cake also doesn't use dependency injection so passing whole instances around like the auth object is sometimes cumbersome. Also I don't think the auth object itself should intersect with the model layer. We want to avoid tight coupling. To simplify this (also for testing) it is much easier to just pass the required values to the methods.
Mayby it's not a good idea, but in cake's model You can get users id using $_SESSION['Auth']['User']['id']
Or just use Cake\Routing\Router; at the top of your Table class and then, You can get access to session using:
Router::getRequest()->getSession()->read('Auth.User.id');
In CakePHP 2.x it's done as stated below. I'm quite sure that, even though it's not in the docs, it may be done the same way.
// Use anywhere
AuthComponent::user('id')
// From inside a controller
$this->Auth->user('id');
Source: http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-user
Docs for version 3.x: http://book.cakephp.org/3.0/en/controllers/components/authentication.html#accessing-the-logged-in-user

CakePHP: Flexible redirection for views and controllers

I have views that are called from different views. The customers edit view can be called from the customers list, the customers search, from within an order and so on. Some of this views are simple views other contains forms to add, edit or delete data. After the user has done what he had to to on that form he should be redirected to the calling form or to another form.
Using $this->referer() wouldn't work as some navigations have to go like this:
list order --> edit order --> delete order --> list order.
I would be fine with defining the redirection for every call so I've tried to use query strings and add ?redirectTarget=<wherever> to every link or redirection. For that I've made a controller function
in AppController.php
public function getRedirectTarget() {
if ($this->request->query('redirectTarget')) {
return $this->request->query('redirectTarget');
} else {
return array(
'controller' => 'pages',
'action' => 'home'
);
}
}
This works for forms as I can use getRedirectTarget() in my controllers but I cannot access that function from within a view to build a link. (At leas I sholdn't do that Can you call a controller function from a view in CakePHP? ) In the example from the top I have to pass the information from the order list to the edit view to build a link and to the underlying controller for the form action.
Now I have different aproaches in my mind but with none of them I'm realy happy. I'm not shure which way to go.
Is there something in CakePhp I haven't found yet?
using $this->requestAction?
changing everything to forms and buttons and doing all redirections in the controllers?
Is there a way to create a variable for every view?
As this seems to me like a comon requirement and I'm pretty new to CakePHP I'm asking for your advice.
Using requestAction should be the best way.
In the views, you can have something like
$redirect = $this->requestAction('/mycontroller/requestAction');
$url = $this->Html->link('Continue', $redirect));

How to add queries in model in Cakephp 2.x and call that function in controller

I want to add my save, update, find queries in model and call those functions in controller, rather than adding the queries in controller.
I'm not sure what's you precisely want to acheive, but I first of all hope you know that CakePHP has implemented save, update and find functions for your models. If not, look at the docs, e.g. here: http://book.cakephp.org/2.0/en/models/saving-your-data.html
If you want to add functions with custom queries to your model, you can simply add them as a normal function in your model, e.g.:
MODEL
public function myMethod(){
// Fetch data
return $this->query("SELECT * FROM pictures LIMIT 2;");
}
CONTROLLER
public function index(){
// Get data from model-method
$data = $this->ModelName->myMethod();
// Send data to view
$this->set(compact('data'));
}
In your model classes you don't have to refer to your model in your code:
In your controller: $this->ModelName->function()
In your model: $this->function()
Has the same meaning.

CakePHP 2.x: Send $this->Session->data array to another view/controller

Looking for the most efficient way to do the following:
Details:
1 controller:
Reports
2 views:
create_report
view_report
create_report has a form where information is collected that will be used in the view_report view.
I know the data entered in the form is available within the create_report view via the $this->session->data element.
Looking for Help on This:
What I need to do is send that same info ($this->session->data) from the create_report view to the view_report view (through the controller, I assume).
What I have so far:
Just a link:
echo $this->Html->link('View Report', array('controller' => 'reports', 'action' => 'view_report'));
But this only takes the user to the view_report view. It doesn't send the info in $this->session->data to that view.
I am thinking it has something to do with the Js helper, but I wasn't able to find any posts dealing directly with this situation for CakePHP 2.x.
You could bypass data processing by controller action create_report and send them directly to report view and do validation there if needed. Just alter form creation in create_report.ctp view.
$this->Form->create('Report', array('action' => 'view_report'));
Data will be submited directly to view_report action and available in $this->request->data
If you have data stored in the session as you say, then you can access it directly from your view_report view, or any other view for that matter. To do this you can use the Session Helper.
$this->Session->read('whatever');
To use this approach, make sure you have the Session Helper loaded. More information on it here.
Or you could pass your session data to the view by using $this->set in your controller as you would any other data.
If you want, for debugging sake, to see the contents of your current session, you can dump the session from your view ...
var_dump($this->Session);
this way can be used as well, in this case you can send to any controller's any action
$this->Form->create('Report', array('url' => '/my_contoller/my_action'));

Putting ajax and non-ajax actions in the same controller in CakePHP

I've run into a problem in my CakePHP app as a result of adding some ajax actions.
My table is called orders so obviously my controller is called OrdersController and the model is called Order
It is my understanding of CakePHP's best practices that if I am going to run any logic on the Order model, that it should be done in the OrdersController. This is fine for the basic CRUD stuff but now that some of my views need to send ajax requests to manipulate Order data I have a problem.
The problem is that for ajax to work properly, I have to put this at the beginning of the OrdersController
var $layout = 'ajax'; // uses an empty layout
var $autoRender=false; // renders nothing by default
Then, to stop the security component interfering with my Ajax form submissions, I also need this:
public function beforeFilter() {
parent::beforeFilter();
$this->Security->csrfUseOnce = false;
$this->Security->csrfExpires = '+1 hour';
}
None of this would be a problem if the controller was only being used for Ajax requests, but the problem is that it's being used for regular Cake actions too.
Is the answer that I should have two controllers? One for regular actions and one for ajax actions? This doesn't seem to be mentioned in the Cake docs and it doesn't seem like a very efficient way of doing things.
I know I can change the layout and possibly the auto-render setting on a per-action basis, but I don't see how it's possible to do this with the csrf settings, which need to be in the beforeFilter.
No need for a separate controller. Use cakes request handler. In your controller method, you can test if it's an Ajax request.
if ($this->request->is('ajax')) {
//set to Ajax layout and security settings, etc
You'll need to include the request handler component at the top of your controller:
public $components = array('RequestHandler');
See this page in the cook book For more info: http://book.cakephp.org/2.0/en/core-libraries/components/request-handling.html

Resources