MissingRouteException in test of Table Object - cakephp

I have a TableObject that sends an email in the afterSave-Event to notify the admin of a change. After the switch from cakephp-3 to cakephp-4 the test for this fails with this error message:
Cake\Routing\Exception\MissingRouteException: A route matching ... could not be found.
The exception occurs on a line in the email template where I build a link like this:
$this->Url->build([
'prefix' => 'Partner',
'controller' => 'orders',
'action' => 'view',
$order->id,
]);
I believe that the routes are not set up in the context of a test for a Tableobject and therefore the reverse routing is not working. (I only get the error when running the test, not when the email is sent in the app).
Is there a way I can load all routes in the test?

Since 4.x the routes are not auto loaded anymore.
You need to add
$this->loadRoutes();
into your setUp() or before the test run to actively load them now.

Related

Cakephp 2.6 how do I return to the main application after entering a plugin

I am using Luis Dias' Report Manager Plugin to generate some quick reports for an application I am developing. From my application dashboard I enter the plugin using the following:
<td style="text-align:center">
<button style="height:75px; width:175px; background-color:BurlyWood; font-size:20px; font-family:Verdana"
onclick="window.location.href='<?php echo Router::url(array('controller'=>'report_manager'
,'action'=>'reports'))?>'">Report Management</button>
I'd really like to open the Report Generator Wizard in a new window but that's a different issue..
Once I am done with the report generator I'd like to return to my dashboard in my application. However, I am now in the Plugin's domain and can't figure out a command to "route" me back to the calling application.
Thanks in advance
Mike
To 'escape' from a plugin when routing you need to pass plugin => false in the route array. For example:-
$this->Html->url([
'controller' => 'pages',
'action' => 'view',
1,
'plugin' => false
]);
If you don't pass the plugin attribute it assumes you want to remain in the context of the current plugin. You need to be careful with this wherever you use links where plugins are in use.

CakePHP Auth Module Tutorial--Why is it requesting user/login for these pages?

I have a custom routing setup (which might be cause of issue). As follows:
Router::connect('/o/*', array('controller' => 'open', 'action' => 'openinsert'));
Router::connect('/c/*', array('controller' => 'click', 'action' => 'clickinsert'));
Under UsersController, I have tried:
public function beforeFilter() {
parent::beforeFilter();
//$this->Auth->allow('add');
$this->Auth->allow('o/*');
$this->Auth->allow('clickinsert');
$this->Auth->allow('open');
}
clickinsert and openinsert are both apart of controller 'ClickController' and 'OpenController' respectively.
Nothing from above works. Is is possible to do what I'm wanting to do w/their default auth setup? Or will I need to make some major changes?
AuthComponent::allow
This method:
Takes a list of actions in the current controller for which authentication is not required, or no parameters to allow all actions.
It doesn't accept urls.
In particular this:
$this->Auth->allow('o/*');
Is neither the wildcard ( nothing or '*' depending on the version of CakePHP used) nor the name of an action, and this:
$this->Auth->allow('open');
Is apparently passing the name of a controller so neither of those method calls would do anything.
There's some confusion here
According to these two routes:
Router::connect('/o/*', array('controller' => 'open' <-
Router::connect('/c/*', array('controller' => 'click', <-
They point to two different controllers.
Under UsersController, I have tried:
Anything you put in your users controller is irrelevant for requests that don't use it. Either put the allow calls in the before filter for each controller - or put them in the beforeFilter for your App controller (which all controllers inherit from).

CakePHP add default routing extension

I've got a JSON REST api working for my application at a URL like: website.com/model/data.json using the CakePHP REST Simple Setup.
But I'd like it to also work the same even if I don't use the .json extension (in other words the response from website.com/model/data.json should be the same as website.com/model/data).
Is there any way to set an implied/default extension for a given controller function such that this would work?
FWIW: I'm using CakePHP 2.3.
To set up a route in CakePHP, add the following to your routes.php file:
Router::connect(
'/model/data',
array('controller' => 'model', 'action' => 'data', 'ext' => 'json')
);
See http://book.cakephp.org/2.0/en/development/routing.html for more details on routing.

Outputting a hyperlink from a controller in cakePHP

I'm just getting started with cakePHP, and things aren't going so well so far.
I have a controller that handles confirming user emails. On registration the user is sent an email with a confirmcode in a link. Depending on the confirm code they give, the controller gives different text responses. One of these responses includes a hyperlink in order to log in.
I'm trying to use the Html helper, but although I've loaded it in $helpers at the top of the class, I an only make it work if I then use App::import, and then instantiate it.
It all seems overkill to simply make a hyperlink! How many times do I have to load the same class?
Wherever I look on the web it keeps telling me it's a bad idea to use a helper in a controller, but how else am I supposed to get the link made?
So I have
var $helpers = array('Html');
at the top of the controller, and:
if (isset($this->User->id)) { // Check the user's entered it right
// Do some stuff to remember the user has confirmed
// This is to load the html helper - supposedly bad form, but how else do I make the link?
App::import('Helper', 'Html');
$html = new HtmlHelper();
$this->set('message', __("Your email address has been confirmed.", TRUE)." ".$html->link(__("Please log in", TRUE), array('controller' => "users", 'action' => "login" )));
} else {
$this->set('message', __("Please check your mail for the correct URL to confirm your account", TRUE));
}
in the controller's confirm method and
<div>
<?php echo $message;?>
</div>
in the view to output the resulting message
Surely I'm going wrong somewhere - can anyone explain how?
You're not supposed to use Helpers in the Controller. As #Lincoln pointed out, you should construct the link in the View. You may construct the URL in the Controller, since a URL is basically data, but a link is a very medium-specific (HTML) implementation of a URL.
Either way, you'll need to create a full URL (including host) if you want to send it in an Email. The most universal way is to use Router::url:
$fullUrl = Router::url(array('controller' => ...), true); // 'true' for full URL
Do this in either the Controller or the View. For creating a link, use this in the View:
echo $html->link('Title', $fullUrl);
The idea is that all the data you need to render the page is sent to the view with set, then any conditional logic or formatting is done in the view with helpers, so send whole query results when appropriate (suppose you need to alter a link to include the user's screen name, you'll have it handy).
in controller action
$this->set('user', $this->User);
in view (this is slightly different depending on if your in <= 1.2 or 1.3
if ($user->id) //available because of Controller->set
{
//1.2
$link = $html->link(__("Please log in", TRUE), array('controller' => "users", 'action' => "login" ));
//1.3
$link = $this->Html->link(__("Please log in", TRUE), array('controller' => "users", 'action' => "login" ));
echo __("Your email address has been confirmed.", TRUE)." $link";
}
else
{
$this->set('message', __("Please check your mail for the correct URL to confirm your account", TRUE));
}
What you are trying to do should be done with the SessionComponent. $this->Session->setFlash('your message here');
and in your layout with the session helper put $this->Session->flash();
About your wanting urls in the controller, Router::url is correct as deceze said, but there is no use for it there as you should not be building html in a controller.
what you want to do it use the session::setFlash() method above and then redirect them using
$this->redirect(array('controller' => "users", 'action' => "login" ));

CakePhp - render a view + afterFilter

The problem is i want to call the index function, i need it to render the view and then the
afterFilter to redirect again to the index function and do the same.. Like a loop, the problem is it doesnt render it, ive tried using $this->render('index') but it doesnt work and also other things..
PS: I didnt include all the code that i have in index, because its pointless, doesnt render with or without it, just included the things i needed for the view.
function afterFilter()
{
if ($this->params['action'] == 'index')
{
sleep(3);
$this->redirect(array('action'=>'index',$id), null, true);
}
}
THE FUNCTION
function index($ido = 0)
{
$this->set('Operator', $this->Operator->read(null, $ido));
$this->set('ido', $ido);
}
THE VIEW = INDEX.CTP
<legend>Operator StandBy Window</legend>
<?php
?>
</fieldset>
<?php echo $html->link('LogIn', array('controller' => 'operators', 'action' => 'add')); ?>
<?php echo $html->link('LogOut', array('controller' => 'operators', 'action' => 'logout',$ido)); ?>
a function that constantly checks my database for a change, if a change occurs ill redirect, if not i need to have that constant loop of 'checking the database' and 'rendering the view'.
This is not possible entirely on the server with PHP, and especially not with CakePHP's template system. PHP just "makes pages" on the server and sends them to the browser and a linear fashion. If you loop on the server, the content of your page will just repeat itself:
Normal content
Normal content
Normal content
<redirect>
To redirect the client, you need to output headers. The headers need to be output before anything else. If you've already looped a few times and content has already been sent to the client, you can't redirect anymore.
There are two ways:
You just output one page at a time showing the current status, with a meta tag that'll refresh the page every x seconds. This can be rather expensive and annoying though.
Use AJAX and possibly Comet to update the information on the page dynamically in the browser.

Resources