Hi The master CakePHP! I want to ask something.
I think the probem is so simple, Is it possible to generate a url in cakephp application like this? (This is google mail like url - http://mail.google.com/a/domain.com)
http://www.domain.com/a/[something]/[member]/[controller]/[action]
Where [something] is a dynamic variable, [member] is a prefix, [controller] and [action] is usual cakephp url element.
so I want to shift the usual CakePHP url to the right, or insert /a/something/ in the initial url.
In addition, [something] should be read from the controller action
thanks, your help would be very valuable to me and will really help me
QUESTION v2:
I have tried to add this routing into routes.php
Router::connect('/:code/:something/:controller/:action',
array(),
array('code'=>'a','pass'=>array('something'))
);
when i try to access a http://domain.local/a/pte/users/view, it's work, but it display an error when i try to access http://domain.local/a/pte/users
QUESTION v3:
So the simple question is:
How do I have a url like google (example above) without breaking the
default CakePHP routing?
QUESTION v4: (Thank's for #Rui)
I tried to create this routing:
Router::connect('/:code/:something/:prefix/:controller/*',
array(),
array('code'=>'a','pass'=>array('something'))
);
It's ok when i try to access
http://domain.local/a/pte/member/users (The result is cake render member_index view, It's a great progress :-) ),
but there are several issue:
when i try to access http://domain.local/a/pte/users (without prefix member, i decided to display index function) it's failed (display an error AController did not defined)
When i create a link
echo $html->link('test link',array('code'=>'a','something'=>'pte','member'=>true,'controller'=>'users','action'=>'another_view'));
it generate a link like this
http://domain.local/member/users/another_view/code:a/something:pte
Please try in /app/config/routes.php:
<?php
Router::connect('/a/:something/:member/:controller/:action/*');
?>
And the action should be:
<?php
public function action($something = null, $member = null) {
/* action code */
}
?>
Hope it helps.
Related
I have a problem and i have no idea what's wrong.
I have build a basic authentication system, simple one. but what i noticed is that the URL- from the side bar is different from the one that is generatet from cakephp for example:
http://localhost/sitename/users
is the url that displays on toolbar.
When i do:
echo Router::url($this->here, true );
the result is:
http://localhost/sitename/sitename/users
The site still works, but time after time generates an error such as:
http://localhost/sitename/sitename/users/
Missing Controller
Error: SitenameController could not be found.
Error: Create the class SitenameController below in file: app\Controller\SitenameController.php
<?php class SitenameController extends AppController {
}
So i dont know what is causing the problem...
If someone, anyone could help me i would very appruciate it...
Thank you very much.
Your app is in a subdirectory so you should use
Router::url(null, true);
If the $url param is null the method will find the address to the actual controller/action. Read more here.
From the book:
$this->request->here contains the full address to the current request.
The full address includes the subdirectory as well. So if you use Router::url() with the $full param set to true it "duplicates" the subdirectory.
I'm trying to get the Mailchimp datasource from Springest working, and I'm having issues. I had to modify some code to get rid of CakePHP errors. Now it happens without errors, but there is no actual API request made to Mailchimp.
The Model, Datasource and Controller function code is exactly the same as in the download from Springest.
The code in my database.php file is:
public $mailchimp = array(
'datasource' => 'MailchimpSubscriber',
'apiKey' => '<my mailchimp API key>',
'defaultListId' => '<my list identifier>',
'baseUrl' => 'http://us1.api.mailchimp.com/1.2/'
);
I am running CakePHP 2.1.0 on XAMPP on my Macbook Pro.
Anybody got any clues?
==UPDATE==
I've uploaded a stripped-out controller here: https://gist.github.com/3011716
Here is the code for my view:
<h2>Subscribe to Mailchimp</h2>
<?php
echo $this->Form->create('People', array('action' => 'subscribe'));
echo $this->Form->input('id');
echo $this->Form->input('emailaddress');
echo $this->Form->input('FNAME');
echo $this->Form->input('LNAME');
echo $this->Form->input('GENDER');
echo $this->Form->end('Submit');
?>
Thanks for trying out our Mailchimp Datasource. One of the problems might be that is was written for CakePHP 1.2+ and that a lot of stuff has changed in CakePHP since the 2.0 release.
Note that we're still using Cake 1.3 with the datasource and experience no errors whatsoever.
Did you check out the migration guide from CakePHP 1.3 to 2.0? Right at the bottom there's some mentioning of changes done to DataSources, so the error might be related to that.
We'll try to take it for a spin in Cake 2.0 and see what goes wrong, but in the mean time, this might be helpful.
==UPDATE==
Yup, it was CakePHP 2.0 that was not compatible. I've ported the datasource to support CakePHP 2.0, please check the updated repository.
== SECOND UPDATE==
You've made one error in your view: because you've created the form with $this->Form->create('People', array('action' => 'subscribe')); the data of the form will be in the $this->data array with key People whereas it should have the key MailchimpSubscriber. Because there's no key with that name in your $this->data the MailchimpSubscriber model will ignore the save action. You'll need to change your submission form in such a way that the submitted data has the right model name as key.
Another note: you're now loading the MailchimpSubscriber model twice. The first time in the $uses array in the controller and the second time through the $this->loadModel() method in the controller action. I would only use the latter.
I've been using routing with "slug" as a named parameter, for example:
Router::connect('/category/:slug', array('controller'=>'categories', 'action'=>'view'), array('pass'=>array('slug'), 'slug'=>'[a-z0-9\-]+'));
I've now stumbled across a problem because I want to restrict the above route to logged in users only, so I've put this in the beforeFilter() function of my CategoriesController:
if(!$this->Auth->loggedIn()) {
$this->Auth->deny('view');
}
Now if I go to /category/my-category (while logged out) I'll be redirected to my application's login page, unfortunately after I log in I'm redirected to /categories/view/my-category/slug:my-category
This is due to line 317 of AuthComponent.php, where we have:
$this->Session->write('Auth.redirect', Router::reverse($request));
So it seems when I do Router::reverse($request) on the above route it doesn't work properly (because it thinks "my-category" should be both a passed and a named parameter).
Is this a problem with the way I've set up this route, or is it a bug with CakePHP? Surely Router::reverse($request) should always return the URL we're currently at?
Any advice appreciated...
I'm not 100% sure if it is a bug or not, but until we find out a work-around could be to manually set the new loginRedirect in your category controller like so:
if(!$this->Auth->loggedIn()) {
$this->Auth->deny('view');
$this->Auth->loginRedirect = '/categories/' . $this->request->params['slug'];
}
Note, check that $this->request->params['slug'] is the right var to use, not 100% off the top of my head.
I am a 3+ years old in cakephp and facing a somewhat strange issue
with submitting a form to plugin controller's action (i am using
plugin first time). After trying different known things i am posting
this one.
Going straight into the matter here is the form in my "forum" plugin's search_controller.php's "index" view:
echo $form->create("Search", array('url'=>array('controller' =>
'search', 'action' => 'index','plugin'=>'forum'),
'id'=>'searchFormMain'));
<input type="text" name="data[Search][keyword]" style="width:357px; margin-left:9px;"><p><span id="searchButton"><input
type="image" src="/img/button_search.jpg" style="height:40px;width:
136px;border:0;" class="handcursor"></span></p>
</form>
As i am submitting this form to "index" action of search controller of
forum plugin, the following code does print nothing:
public function index($type='') {
if(!empty($this->data)) {
pr($this->data);
die;
}
}
While if i try the same code within beforeFilter of the same
controller i.e. search_controller.php it works well and prints as
follows:
Array
(
[Search] => Array
(
[keyword] => Hello Forum
)
)
And finally here is the beforeFilter code (of search_controller.php):
public function beforeFilter() {
parent::beforeFilter();
if(!empty($this->data)) {
pr($this->data);
}
}
Fyi, it does not matter if i comment out "parent::beforeFilter();" or
even disable $uses of my controller (if they look doubtful to you)
the result is same i.e. the control is not going in to "index" action
in the case of form submit while is working fine in the case of page
call. The url/action to page is http://localhost.rfdf.org/forum/search/index.
If i call the url directly it loads the form fine but when i submit it, it
never gets into the "index" action of the controller thus no view
rendered.
If i try the same set of code out of "forum" plugin environment i.e. in normal application it works just fine
I have been trying to find a way out of this for last 3+ hours now but
no success. I would appreciate any help in solving this puzzle.
I got it, finally!
It was Securty compontent dropping the request into the blackHole whenever it failed to find a security token with the form data. I learned that "Security" component "interferes" with $form->create() method and places a token as a hidden field with each $form->create() call. On the form submit, just after beforeFilter and right before getting into the controller "action" it checks for this token and simply dies everything on a validation failure. Unfortunately there is no error message or entry to cake log.
In my case i had been creating my own custom tag and not with the help of $form->create method so no token was being generated which lead to all the pain.
I resolved it by placing
$this->Security->validatePost = false;
at the end of beforeFilter.
Thanks everyone!
Have you tried putting an else into that if(!empty($this->data)) and doing a pr() as it could be that your post is not empty.
Either that or the format of your url array is not correct.
From ln759, http://api.cakephp.org/view_source/router/#line-757
$defaults = $params = array('plugin' => null, 'controller' => null, 'action' => 'index');
So I guess you need plugin first?
Are you using ACL or any of the like? In the beforeFilter, do a pr of the request. See which action is being requested to make sure that the request is correct
In my controller, I check a condition to see if the user is allowed to do something. If the check fails, I want to send a 403 back to the browser. How do I do that in Cakephp?
EDIT - This question is quite old and covers different versions of the CakePHP framework. Following is a summary of which version each answer applies to. Don't forget to vote on the solution that helps most.
CakePHP 3.x and 4.x - using response object (Roberto's answer)
CakePHP 2.x - using exceptions (Brad Koch's answer) [preferred solution]
CakePHP 2.x - setting header only (Asa Ayers' answer)
CakePHP 1.x - using error handler (my other answer)
CakePHP 1.x - setting header only (this answer)
EDIT #2 - A more detailed answer for CakePHP 2.x has been added by Mark37.
EDIT #3 - Added solution for CakePHP. (May 2018: CakePHP 3.5 did some function renaming, solution by Roberto is still valid.)
By looking at the relevant API code from the previous comment, it seems you can call Controller::header($status) to output a header without redirection. In your case, the proper usage is most likely:
$this->header('HTTP/1.1 403 Forbidden');
$this->response->statusCode(403);
Will set the status code when Cake is ready to send the response. CakeResponse::send() expects to send the status code and message, so in my tests I think my using header() was getting overwritten. using $this->header('HTTP/1.1 400 Bad Request') doesn't work either because Cake expects any call to $this->header to be split on a colon ex: $this->header('Location: ...')
Notes concerning CakePHP 3.x seem to be missing, so to make this thread complete:
For CakePHP 3.x and 4.x use:
$response = $this->response->withStatus(403);
return $response;
For versions before CakePHP 3.3.x you can use the same style as CakePHP 2.x:
$this->response->statusCode('code');
Note that using the PHP function directly also works (http_response_code(403); die();), though using the response object seems like the intended method.
In CakePHP 2, the preferred method is to throw an exception:
throw new ForbiddenException();
I'm adding in my two cents here because I don't feel like any of these answers covered this topic as thoroughly as I would have liked (at least for Cake 2.x).
If you want to throw an error status, use the Exception classes (as mentioned in other answers):
throw new BadRequestException(); // 400 Bad Request
// Or customize the code...
throw new BadRequestException('Custom error message', 405); // 405 Method Not Allowed
Fun fact: Cake will automatically do some magical error rendering even for RESTful calls via the ExceptionRenderer class. Even more fun of a fact is that it's based on the Status Code, not the fact that an Exception might have been thrown, so if you set the status code to > 400 on your own you will likely get error messages even if you didn't want them.
If you want to return a specific status code for a REST JSON/XML endpoint, take advantage of the new CakeResponse object, but also make sure that you add the special _serialize variable or you'll end up with a 'view not found' error as cake will attempt to find a view to render your JSON/XML. (This is by design - see the JsonView/XmlView class.)
$this->response->setStatus(201); // 201 Created
$this->set('_serialize', array()); // Value must be something other than null
And lastly, if you want to send a non-200 status for a regularly rendered page, you can just use the setStatus() method with nothing else as mentioned in a previous answer:
$this->response->setStatus(201);
UPDATE:
$this->response->setStatus('code');
is no longer available. Use
$this->response->statusCode('code');
Upon revisiting this question, and reading Adriano's comment on my previous answer (regarding redirecting the user to a friendly page), I have come up with a new solution.
Within a controller you can call $this->cakeError('error404') to generate a friendly 404 page. This can can be customised (as with other errors) by creating file at 'app/views/errors/error404.ctp'.
After having a closer look at the code for cakeError, my recommendation is to try extending Cake's ErrorHandler by creating a file at 'app/error.php' or (possibly more preferable) 'app/app_error.php'.
The code for your error403 (mimicking the error404 code) could read as follows:
class AppError extends ErrorHandler {
function error403($params) {
extract($params, EXTR_OVERWRITE);
$this->error(array(
'code' => '403',
'name' => 'Forbidden',
'message' => sprintf(__("Access was forbidden to the requested address %s on this server.", true), $url, $message)));
$this->_stop();
}
}
You should also be able to provide a custom view for this error by creating 'app/views/errors/error403.ctp'. Here is a modified version of the error404 view:
<h2><?php echo $name; ?></h2>
<p class="error">
<strong>Error: </strong>
<?php echo sprintf(__("Access was forbidden to the requested address %s on this server.", true), "<strong>'{$message}'</strong>")?>
</p>
It has changed again since CakePHP 3.6:
Use now
$this->setResponse($this->response->withStatus(403) );
return $this->response; // use this line also
instead of
$response = $this->response->withStatus(403);
https://api.cakephp.org/3.7/class-Cake.Controller.Controller.html#_setResponse
Perhaps something in this section of the cakephp manual can help you.
redirect(string $url, integer $status,
boolean $exit)
The flow control method you’ll use
most often is redirect(). This method
takes its first parameter in the form
of a CakePHP-relative URL. When a user
has successfully placed an order, you
might wish to redirect them to a
receipt screen. The second parameter
of redirect() allows you to define an
HTTP status code to accompany the
redirect. You may want to use 301
(moved permanently) or 303 (see
other), depending on the nature of the
redirect.
The method will issue an exit() after
the redirect unless you set the third
parameter to false.
You can use cakephp response for custom message:
$this->response->header('HTTP/1.0 201', 'custom message');
$this->response->send();
Core PHP link code works in cakePHP.
header('HTTP/1.1 403 Forbidden');