I have set up the RSS Helper (with CakePHP 1.3.4) and all is working - I can access my feeds by /news/feed.rss - as exampled at http://book.cakephp.org/view/1461/Creating-an-RSS-feed-with-the-RssHelper
But I want to be able to do this conditionally, in sudo, something like:
if (!empty($var)) {
switch ($var) {
case one :
$xml = $this->method->find('$var conditions...');
... use RSS Helper to serve results as XML.
case two :
$xml = $this->method->find('other $var conditions...');
... use RSS Helper to serve results as XML.
}
}
Can I use the RSS Helper in this circumstance? What calls/syntax do I use?
There are 2 ways to do this.
Basically you can pass a variable like this:
http://yourserver.com/news/feed.rss?recent=20
and then in the controller you can access this variable with
$this->params['url']['recent']; //20
Or you can add a line in your Router file like this:
Router::connect('/feed-:recent/*', array('plugin'=>false, 'controller' => 'news', 'action' => 'feed'), array('recent'=>'[0-9]+'));
This way your url will look like:
http://yourserver.com/news/feed-20.rss
and finally I believe that url like this will work as well:
http://yourserver.com/news/feed.rss/recent:20
You can pass params to the function the same as any other controller call.
IE
public function rss( $limit = 20, $topic = null ){
if( !$topic ){
$xml = $this->Article->find( 'all', array( 'limit' => $limit ));
...
} else {
$xml = $this->Article->find( 'all', array( 'limit' => $limit, 'conditions' => array( 'Article.topic' => $topic )));
}
...
}
}
?>
Then you can access the rss feed with: http://domain/articles/rss.rss
If you need to pass parameters: http://domain/articles/rss/100.rss (fetch all with 100 results)
Or like this: http://domain/articles/rss/10/obama.rss (fetch all with the topic "obama" and return 10 items.
The RequestHandler allows you to use a url like /posts/index.rss and it automatically loads the RSS Helper and sends the output to /views/posts/rss/index.ctp, and uses layout at /views/layouts/rss/default.ctp.
But if you want to use the RSS Helper on it's own you need to:
1) include it the controller
var $helpers = array('Rss');
2) in your controller action you need to specify where the output goes, so
$this->render('/posts/rss/index','/rss/default');
In this case I also specified which layout to use in the 2nd argument. The first arg - the index.ctp file location is relative to your views/ directory. The second arg - the layout is relative to your views/layouts/ directory.
So I have a method in my posts_controller that I use to identify which feed is wanted (through a passed var) and subsequently finds the posts and sends them to the correct views and layouts:
function rss(){
if (!empty($this->params['pass'])){
$ops=array(
'conditions'=>'where feedname_id=' . $this->params['pass'][0],
'order' => 'Post.created DESC',
'limit' => 10
);
$this->set('posts', $this->Post->find('all',$ops));
$this->render('/posts/rss/index','/rss/default');
} else {
$this->redirect(array('controller'=>'feednames','action'=>'index'));
}
}
There might be better ways to code this - if so please let me know.
Related
In my routes.php file, I've put this into Router::scope('/', function ($routes) {
$routes->connect(
'/:controller/:id',
['action' => 'view'],
['id' => '[0-9]+']
);
However it does not seem to work? The URLs still go to players/view/1
I'm not sure what I'm doing wrong
From the book: book.cakephp.org/3.0/en/development/routing.html#route-elements (just below the code you may have cut-and-pasted):
CakePHP does not automatically produce lowercased and dashed URLs when using the :controller parameter. If you need this, the above example could be rewritten like so:
$routes->connect(
'/:controller/:id',
['action' => 'view'],
['id' => '[0-9]+', 'routeClass' => 'DashedRoute']
);
...and then a little further down:
Once this route has been defined, requesting /apples/5 would call the view() method of the ApplesController. Inside the view() method, you would need to access the passed ID at $this->request->params['id'].
So in my (for example) ApplesController's view() method, I added the following at the very top:
if ($id == null) {
$id = $this->request->params['id'];
}
...and now apples/view/5 and apples/5 both work the same way.
I'm creating a plugin for my application (using CakePHP 2.6.0) that allows users to login into a user area using the same model as for the admin area, so I'm trying to get the same type of URI scheme as the admin area e.g. /admin/users/login but then for /special/users/login. I have the following route in my plugin's Config/routes.php and added the 'special' prefix to the 'Routing.prefixes' configuration:
Router::connect('/special/:controller/:action', array(
'special' => true,
'prefix' => 'special',
'plugin' => 'Special',
'controller' => ':controller',
'action' => ':action',
));
With above route and entering the following url /special/users/login it would make sense to me right now if Cake went for Plugin/Controller/SpecialUsersController.php (considering namespace conflicts with the main application's UsersController) but instead I get an error Error: Create the class UsersController.
Is there a built-in way for it to load a prefixed controller (without changing the url) based on the plugin? Or is there a better way to neatly extend my main application? Am I going about this the wrong way?
I could not find a built-in way for it to work as I wanted to so I changed the way URL strings were parsed using a custom route class in my app's Routing/Route/ folder:
App::uses('CakeRoute', 'Routing/Route');
/**
* Plugin route will make sure plugin routes get
* redirected to a prefixed controller.
*/
class PluginRoute extends CakeRoute {
/**
* Parses a string URL into an array.
*
* #param string $url The URL to parse
* #return bool False on failure
*/
public function parse($url) {
$params = parent::parse($url);
if($params && !empty($params['controller']) && !empty($params['plugin'])) {
$params['controller'] = $params['plugin'] . ucfirst($params['controller']);
}
return $params;
}
}
And then setting up my plugin routes as:
App::uses('PluginRoute', 'Routing/Route');
Router::connect('/special/:controller/:action', array(
'special' => true,
'prefix' => 'special',
'plugin' => 'Special',
'controller' => ':controller',
'action' => ':action',
), array(
'routeClass' => 'PluginRoute'
));
This resulted in /special/users/login creating the controller I wanted Plugin/Controller/SpecialUsersController.php, no side effects so far. Extending the main application's UsersController is a different story though.
Maybe someone else has use of this or knows a better solution?
I code a client/server application.
Server side is powered by CakePHP 2.4.7.
Client side run with angularjs and cordova on mobile devices
I use several cakephp route prefixes whose 'admin' and 'mobile'.
(And I use $resource and $httpInterceptor angularjs factories to setup my REST requests.)
I want to call /website/mobile/posts/add.json with json data posting.
So I call /website/mobile/posts.json with a POST ajax query:
The problem is here: the called controller action is 'index', not 'add';
On top of my PostsController, I added this:
echo $this->request->params['action'] . "\n";
echo ($this->request->isPost())? "post" . "\n" : "not post";
die;
and the response is always:
mobile_index
post
So the ajax request seems correct but cakephp don't map it to the add action, but index one.
However my configuration seems good too; here is a fragment of my routes.php
Router::mapResources(array('users','posts'));
Router::parseExtensions('json');
Any idea ?
Prefix routing doesn't work with REST routing out of the box
REST routing works by automatically creating routes for the controllers passed to Router::mapResources(). Prefix routing pretty much does the same, it creates default routes including the prefixes defined in Routing.prefixes.
However both functionalities don't know about each other, they both create separte routes, so Router::mapResources() will connect to URLs without prefixes (the prefix option for this method is not using actual prefix routing, it will just add the value of that option to the beginning of the URL to connect to!), and therefore your request to /mobile/... doesn't actually use REST routing but only prefix routing.
Defining prefixed REST routes manually
There is no simple fix for this problem like using an option or something, instead you'll have to define the REST routes manually so that the prefix option is included, simple enough though.
See Modifying the default REST routes and Custom REST Routing.
A sample Route could look like this:
Router::connect(
'/mobile/users',
array(
'prefix' => 'mobile',
'mobile' => true,
'controller' => 'users',
'action' => 'add',
'[method]' => 'POST'
)
);
This would connect POST requests to /mobile/users to UsersController::mobile_add(). Similary you'll have to do this for all other methods like GET and PUT, with and without passing an id, etc.
Note that when connecting manually you can ditch the Routing.prefixes option and of course the call to Router::mapResources().
Automated mapping
Defining all those routes by hand is kinda exhausting, you're better of automating it with respect to the Router::resourceMap() configuration.
Here's an example on how to do that, it's somewhat similar to Router::mapResources(), but it accepts a prefix option that actually makes use of prefix routing:
function mapResources(array $controllers) {
$resourceMap = Router::resourceMap();
foreach($controllers as $controller => $options) {
if(!is_array($options)) {
$controller = $options;
$options = array();
}
$options += array(
'prefix' => null,
'plugin' => null,
'id' => Router::ID . '|' . Router::UUID
);
foreach($resourceMap as $params) {
$url = '';
if($options['prefix']) {
$url .= '/' . $options['prefix'];
}
if($options['plugin']) {
$url .= '/' . $options['plugin'];
}
$url .= '/' . $controller;
if($params['id']) {
$url .= '/:id';
}
Router::connect(
$url,
array(
'prefix' => $options['prefix'],
$options['prefix'] => !!$options['prefix'],
'plugin' => $options['plugin'],
'controller' => $controller,
'action' => $params['action'],
'[method]' => $params['method']
),
array(
'id' => $options['id'],
'pass' => array('id')
)
);
}
}
}
You would call it like this:
mapResources(array(
'books' => array(
'prefix' => 'mobile'
)
));
and it would map all the REST routes for your books controller using the mobile prefix.
I am looking for input/help on how to do this. Might be some PHP/cake developers could provide some good solutions here. Cakephp 2.3 something :)
Problem; How to put shortcodes in wysiwyg editor (example: [slideshow=1]slideshow here[/slideshow]) and render an element (in this case, loading and displaying the slideshow with ID=1).
ShortcodeHelper.php
App::import('Helper', 'Html', 'Router');
class ShortcodeHelper extends AppHelper {
public $shortcodes = array(
'slideshow' => '/(\[slideshow=)(.+?)(\])(.+?)(\[\/slideshow\])/'
);
public $returncodes = array(
//'slideshow' => $this->render('/elements/slideshow', array('id'=>'\\2'))
'slideshow' => '<strong rel="\\2">\\4</strong>'
);
public function render($content, $render=null) {
$shortcodes = $this->shortcodes;
$returncodes = $this->returncodes;
if(isset($render)) {
$temp_shortcodes = array();
$temp_returncodes = array();
foreach ($render as $key => $value) {
$temp_shortcodes[$key] = $shortcodes[$value];
$temp_returncodes[$key] = $returncodes[$value];
}
$returncodes = $temp_returncodes;
$shortcodes = $temp_shortcodes;
}
$return = preg_replace($shortcodes, $returncodes, $content);
return $this->output($return);
}
}
view.ctp (call render function from helper, and run the page-content trough it):
<?php echo $this->Shortcode->render($page['Page']['body']); ?>
Thanks. You are awesome!! :)
-Tom
You need to turn the short code string into a method call, parse it.
Your helper will need to be able to detect them and then break them up. Your code needs to be mapped somehow to a callback.
// [slideshow=1]slideshow here[/slideshow]
$this->requestAction(array('controller' => 'slideshows', 'action' => 'view', $id);
For example.
I think the best way here would be to just always map the first arg, the "function call" to an element instead and pass all other args to the element. This way you can do there whatever you want and request the data or just simply display HTML only.
I would put the mapping of short codes into something like Configure::write('ShortCodes', $shortCodeArray); this way plugins could even register their callback mapping by simply adding them to that array.
array(
'slideshow' => array('controller' => 'slideshows', 'action' => 'view')
);
You'll have to merge that with args from the parsed short code.
Why requestAction()? You should not violate the MVC pattern, for this reason you'll have to request the data via requestAction().
I have a serious deadlock about my project. I am looking for a solution for days but there is nothing.
My index page have 4 different mysql queries. I tried to code this at first inside 1 controller and 1 view. It was not the right way. Then somebody suggested using 4 elements with requestAction() function. It was very good at first. Then I needed mysql between command. I could not found a way for it to use with requestAction(). My question on Cakephp group still unanswered. Somebody suggested using actions in controller. But I couldn't figure it out how to create that controller.
Please tell me what you know about it. Thanks in advance,
Here is my current post controller's index function:
function index() {
$posts = $this->paginate();
if (isset($this->params['requested'])) {
return $posts;
} else {
$sql = array( 'conditions' => array( 'id BETWEEN ? AND ?' => array( 286, 291 ) ) );
$this->Post->find('all', $sql);
$this->set('posts', $posts);
}
}
What should I do? Should I add a new controller for rest 3 actions? Or should I do something inside index() function?
Every time I need several queries in the single controller I do this way:
// model Foo
function edit($id){
$this->data = $this->Foo->read(null, $id);
$second = $this->Foo->Foo2->find('list');
$third = $this->Foo->Foo3->find('list');
$this->set(compact('second', 'third'));
}
I guess, you want to paginate on those 3 columns so the example above is not good for that.
I think you have an error in your method. $posts is not related to your find. There should be $posts = $this->Post->find('all', $sql);. But this would not allow you to paginate on the result. Take a look at Custom Query Pagination in the manual. Maybe this would work for you:
function index(){
if(!isset($this->params['requested'])) {
$this->paginate = array('Post' => array(
'conditions' => array('id BETWEEN ? AND ?' => array(286, 291))
));
}
$this->set('posts', $this->paginate());
}