CakePHP 3 Rss error - cakephp

i want do a rss, I followed this http://book.cakephp.org/3.0/en/views/helpers/rss.html. But the things not working correctly, because when access the router of the rss, it returns a controller error, saying that controller does not exists. My route is this:
/posts/index.rss
When do this request, it return a error of the controller not found.
The action index.rss is not defined in PostsController
I declared that "app" to accepts rss..My complete config/routes.php
use Cake\Core\Plugin;
use Cake\Routing\Router;
Router::defaultRouteClass('Route');
Router::scope('/', function ($routes) {
Router::extensions(['json', 'xml', 'rss']);
$routes->connect('/', ['controller' => 'Fronts', 'action' => 'index']);
$routes->connect('/contact', ['controller' => 'Fronts', 'action' => 'contact']);
$routes->connect(
'/:controller/:action/:id-:slug',
[],
[
'pass' => ['id', 'slug'],
'id' => '[0-9]+',
'routeClass' => 'DashedRoute'
]
);
$routes->fallbacks('InflectedRoute');
});
Plugin::routes();
I also made the LoadComponent in :: initialize () of the controller
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
}
And my controller
class PostsController extends AppController
{
...
public function index()
{
...
if($this->RequestHandler->isRss()) :
$_rss = $this->Posts->find()->limit(20);
$this->set(compact('_rss'));
return;
endif;
...
}
}
Whats is wrong?
Thankss..!!!

You're defining the extension the wrong way, Router::extensions() is ment to define global extensions for all routes that are being connected after Router::extensions() has been invoked.
So, inside a scope, the call to Router::extensions() is too late, as it's the Router::scope() method, that, when invoked, reads the global extensions and passes them into the scope.
Either invoke Router::extensions() outside of the scope
Router::extensions(['json', 'xml', 'rss']);
Router::scope('/', function ($routes) {
// ...
});
or use RouterBuilder::extensions() inside of the scope (note that this overrides the global extensions that the scope might have been inherited)
Router::scope('/', function (\Cake\Routing\RouteBuilder $routes) {
$routes->extensions(['json', 'xml', 'rss']);
// ...
});
See also Cookbook > Routing > Routing File Extensions

Related

Router::extensions(['json']) has no effect on the ErrorController

My goal is to have exception messages converted to JSON when requested (via headers and/or filename extension). According to JSON exception in cakephp 3, this needs to happen in src/Controller/ErrorController.php. If I simply add $this->RequestHandler->renderAs($this, 'json') to beforeFilter() it works fine, but then again, I should be forcing JSON only when JSON is explicitly requested.
I started by adding Router::extensions(['json']) to the top of my routes.php following this advice.
Then I created a test action /foo/bar.json throwing a new BadRequestException('hello').
Lastly, debugging in src/Controller/ErrorController.php:
public function beforeRender(Event $event)
{
parent::beforeRender($event);
$this->viewBuilder()->setTemplatePath('Error');
debug($this->getRequest());exit;
}
When I request it, I can see that the extension isn't parsed at all:
object(Cake\Http\ServerRequest) {
[protected] params => [
'controller' => 'Foo',
'action' => 'bar.json',
// …
'_ext' => null,
]
Trying $this->getRequest()->is('json') also returns false.
When I add debug(Router::extensions());exit; to the top of config/routes.php, nothing happens. Could this mean the file isn't read at all? Or is that because the exception aborts the execution before it even gets there?
How do I force JSON error messages when explicitly requested?
Relevant code:
config/routes.php:
<?php
use Cake\Core\Plugin;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\Routing\Route\DashedRoute;
use Cake\Http\Middleware\CsrfProtectionMiddleware;
Router::extensions(['json']);
debug(Router::extensions());exit;
Router::defaultRouteClass(DashedRoute::class);
Router::scope('/', function (RouteBuilder $routes) {
$routes->registerMiddleware('csrf', new CsrfProtectionMiddleware());
$routes->applyMiddleware('csrf');
$routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
$routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);
$routes->fallbacks(DashedRoute::class);
});
Router::prefix('abc', function ($routes) {
$routes->fallbacks(DashedRoute::class);
});
Router::prefix('def', function ($routes) {
$routes->fallbacks(DashedRoute::class);
});
Router::prefix('ghi', function ($routes) {
$routes->fallbacks(DashedRoute::class);
});
Router::prefix('api', function ($routes) {
$routes->prefix('jkl', function ($routes) {
$routes->fallbacks(DashedRoute::class);
});
});
Router::prefix('mno', function ($routes) {
$routes->fallbacks(DashedRoute::class);
});
//Plugin::routes();
Use setExtensions() inside a corresponding scope instead of the global call
If using a prefix, configure that exact prefix.
Clear the cache: bin/cake cache clear_all
If done right, there will be no need to additionally configure src/Controller/ErrorController.php like in this answer.
Working code:
Router::prefix('myprefix', function ($routes) {
$routes->setExtensions(['json']);
$routes->fallbacks(DashedRoute::class);
});
That's it. Requests having the .json extension within /myprefix to an action that throws an exception will be returned as JSON.

Is it possible in Cake 3.0 to add a prefix in routing that isn't actually in the url?

What I want to achieve is to keep my baked controllers in src/Controller/, and to extend these for both my admin controllers (in src/Controller/Admin/) and my customer controllers (in src/Controller/Customer/). I have already achieved this for admins with:
Router::prefix('admin', function ($routes) {
$routes->fallbacks('DashedRoute');
});
However, for customers I don't want /customer/ in the URL. Is this possible?
For example, http://example.org/users should use src/Controller/Customer/UsersController.php
I think I solved it:
Router::prefix('admin', function ($routes) {
$routes->fallbacks('DashedRoute');
});
Router::scope('/', function ($routes) {
$routes->connect(
'/:controller/:action/*',
['prefix' => 'customer'],
['routeClass' => 'DashedRoute']
);
$routes->connect(
'/:controller/*',
['prefix' => 'customer'],
['routeClass' => 'DashedRoute']
);
});

Calling a JavaScript method before rendering

I have one-page app where header, footer and top navigation are static and the "pages" are opened with Ajax.
Example:
Element from the main navigation:
Something
JavaScript:
$('body').on('click', '[data-open-dynamic]', function () {
var url = $(this).data('openDynamic');
openDynamic(url);
})
function openDynamic(url)
{
$.ajax({
url: url,
async: true,
success: function (data) {
//some other logic
$('.content').html(data).fadeIn();
}
})
}
The problem is that I need to open these pages from direct URLs also. Now if I try to open domain.com/controllerName/actionName the design is broken as the layout is set to ajax in the controller:
public function initialize()
{
parent::initialize();
$this->layout = 'ajax';
}
I tried to do something with beforeFilter(), beforeRender(), shutdown() but it seems the JavaScript file containing the method openDynamic() is not loaded yet and I can't call it.
public function beforeRender(\Cake\Event\Event $event)
{
parent::beforeRender($event);
$url = $event->subject->request->here; // the URL is correct
echo 'openDynamic("' . $url . '");';
$this->response->stop();
}
Also I'm not sure if the header, footer and navigation will be loaded properly in this way. How can I achieve this?
How about only setting the layout to be ajax if the page is requested via AJAX? You can test this using $this->request->is('ajax'):-
public function beforeRender(\Cake\Event\Event $event)
{
parent::beforeRender($event);
if ($this->request->is('ajax')) {
$this->layout = 'ajax';
}
}
This would be cleaner than mixing JavaScript with PHP in your code.

pass value from jquery to Cakephp controller

I am beginner to CakePHP and trying the send the textbox value during change function to my controller action using ajax.
Can someone help to how to pass the value form jquery to cakephp controller. If there is example code could great.
Let's say you want to send your data to a method called 'ajax_process' in the users controller. Here's how I do it:
in your view .ctp (anywhere)
<?php
echo $this->Form->textarea('text_box',array(
'id' => 'my_text',
));
?>
<div id="ajax_output"></div>
In the same view file - the jquery function to call on an event trigger:
function process_ajax(){
var post_url = '<?php echo $this->Html->url(array('controller' => 'users', 'action' => 'ajax_process')); ?>';
var text_box_value = $('#my_text').val();
$.ajax({
type : 'POST',
url : post_url,
data: {
text : text_box_value
},
dataType : 'html',
async: true,
beforeSend:function(){
$('#ajax_output').html('sending');
},
success : function(data){
$('#ajax_output').html(data);
},
error : function() {
$('#ajax_output').html('<p class="error">Ajax error</p>');
}
});
}
In the UsersController.php
public function ajax_process(){
$this->autoRender = false; //as not to render the layout and view - you dont have to do this
$data = $this->request->data; //the posted data will come as $data['text']
pr($data); //Debugging - print to see the data - this value will be sent back as html to <div id="ajax_output"></div>
}
Disable cake's security for the ajax_process method, in AppController.php:
public function beforeFilter() {
$this->Security->unlockedActions = array('ajax_process');
}
I haven't tested any of this code but it should give you what you need

WkHtmlToPdf Component, problem with Auth

I'm trying to use the WkHtmlToPdf Component, it seems like a nice tool when facing the problem of generating pdf files.
However - I can't get it to work with the Auth Component. The problem is that I always get the login page generated to pdf. I'm logged, the action is allowed in beforeFilter and it still somehow gets into the way of it.
EDIT:
AppController:
var $components = array('Auth', 'Session');
function beforeFilter()
{
$this->Auth->logoutRedirect = array('controller' => 'users', 'action' => 'login');
if (!$this->Auth->user())
{
$this->layout = 'login';
}
}
Controller:
var $components = array('WkHtmlToPdf');
function beforeFilter() // I am logged in, so this shouldn't even be needed
{
$this->Auth->allow('pdf');
}
function pdf()
{
$this->WkHtmlToPdf->createPdf();
}
// this function is required for wkhtmltopdf to retrieve
// the viewdump once it's rendered
function getViewDump($fileName)
{
$this->WkHtmlToPdf->getViewDump($fileName);
}
Any help would be greatly appreciated,
Paul
It turns out, you have to allow the getViewDump method. It doesn't seem to work with Auth, but there is no threat with allowing it for everyone, and it works.
controller:
function beforeFilter()
{
parent::beforeFilter();
$this->Auth->allow('getViewDump');
}

Resources