CakePHP - creating an API for my cakephp app - php

I have created a fully functional CakePHP web application. Now, i wanna get it to the next level and make my app more "opened". Thus i want to create an RESTful API. In the CakePHP docs,i found this link (http://book.cakephp.org/2.0/en/development/rest.html) which describes the way to make your app RESTful. I added in the routes.php the the two lines needed,as noted at the top of the link,and now i want to test it.
I have an UsersController.php controller,where there is a function add(),which adds new users to databases. But when i try to browse under mydomain.com/users.json (even with HTTP POST),this returns me the webpage,and not a json formatted page,as i was expecting .
Now i think that i have done something wrong or i have not understood something correctly. What's actually happening,can you help me a bit around here?
Thank you in advace!

You need to parse JSON extensions. So in your routes.php file add:
Router::parseExtensions('json');
So a URL like http://example.com/news/index you can now access like http://example.com/news/index.json.
To actually return JSON though, you need to amend your controller methods. You need to set a _serialize key in your action, so your news controller could look like this:
<?php
class NewsController extends AppController {
public function index() {
$news = $this->paginate('News');
$this->set('news', $news);
$this->set('_serialize', array('news'));
}
}
That’s the basics. For POST requests, you’ll want to use the RequestHandler component. Add it to your controller:
<?php
class NewsController extends AppController {
public $components = array(
'RequestHandler',
...
);
And then you can check if an incoming request used the .json file extension:
public function add() {
if ($this->RequestHandler->extension == 'json') {
// JSON request
} else {
// do things as normal
}
}

Related

How to achieve this kind of url routing in codeigniter

i want to achieve url routing something like www.example.com/alicia
suppose alicia is not a class name or method name just something like passing data in url and with some class i want to access this and want to use it for further process.How i can use it ? Thanks in advance.
You can use Codeigniter's built-in routing, the file route.php is located in your config folder.
there you can add:
$route['alicia'] = 'welcome/index/something';
$route['alicia/:any'] = 'welcome/index/someotherthing/$1';
then in your controller, for example welcome you just create a function like:
public function index($page = null){
if($page=='something'){
// do what you need to do, for example load a view:
$this->load->view('allaboutalicia');
}
elseif ($page=='someotherthing'){
// here you can read in data from url (www.example.com/alicia/2017
$year=$this->uri->segment(2); // you need to load the helper url previously
}else{
// do some other stuff
}
}
documentation on routing and on urlhelper
edit after comment:
in case your uri segment is representing a variable, like a username, then you should use a uri scheme like www.example.com/user/alice and create your route like:
$route['user/:any'] = 'welcome/index/user';
then in your controller welcome
public function index($page=null){
if($page=='user'){
// do what you need to do with that user
$user=$this->uri->segment(2); // you need to load the helper url
}
else{
// exception
}
}
This could be tricky because you don't want to break any existing urls that already work.
If you are using Apache, you can set up a mod_rewrite rule that takes care to exclude each of your controllers that is NOT some name.
Alternatively, you could create a remap method in your base controller.
class Welcome extends CI_Controller
{
public function _remap($method)
{
echo "request for $method being handled by " . __METHOD__;
}
}
You could write logic in that method to examine the requested $method or perhaps look at $_SERVER["REQUEST_URI"] to decide what you want to do. This can be a bit tricky to sort out but is probably a good way to get started.
Another possibility, if you can think of some way to distinguish these urls from your other urls, would be to use the routing functionality of codeigniter and define a pattern matching rule in the routes.php file that points these names to some controller which handles them.
I believe that the default_controller will be a factor in this. Any controller/method situations that actually correspond to a controller::method class should be handled by that controller::method. Any that do not match will, I believe, be assigned to your default_controller:
$route['default_controller'] = 'welcome';

Ignore route in Laravel 5.1

I want to create dynamic pages CMS for my Laravel app. Admin is allowed to provide any URI for any page, so for example, he can create page with one/two/three URI and http://example.com/one/two/three will point to this site. I already figured out it's possible to add single route for multiple level URLs like this:
get('{uri}', 'PageController#view')->where('uri', '.+');
Now, I also want to have /{username} URLs to point to users profiles. That means, if I need to make it work together. For me, the perfect code would be something like this:
get('{username}', 'ProfileController#view');
get('{uri}', 'PageController#view')->where('uri', '.+');
Then, in ProfileController I'd like to make my route go further just like it wasn't there. Something like this:
// ProfileController
public function view()
{
$user = User::whereUsername($username)->first();
if ($user === null) {
// Go to the next route.
}
}
Can it be done with Laravel?
I can think of another solution, just to have dynamic routing controller for both usernames and page uris mapping, but I would prefer to have it as separate routes.
You can resolve a new PageController instance out of the Service Container if $user is null.
// ProfileController
public function view()
{
$user = User::whereUsername($username)->first();
if ($user === null) {
// Go to the next route.
$params = []; // If your view method on the PageController has any parameters, define them here
$pageController = app(PageController::class);
return $pageController->callAction('view', $params)
}
}
This way, the {username} route will stay but will show custom content defined by the admin.
Edit:
If you don't want to call a controller manually, you could analyze the current URL segments and check for an existing user before you define your route. In order to not make your routes.php file too complex, I'd add a dedicated service class that analyzes your URL segments:
App\Services\RouteService.php:
<?php
namespace App\Services;
class RouteService {
public static function isUserRoute()
{
if(count(Request::segments()) == 1)
return !! User::whereUsername(Request::segment(1))->first();
}
return false;
}
}
routes.php:
<?php
use App\Services\RouteService;
if(RouteService::isUserRoute())
{
get('{username}', 'ProfileController#view');
}
get('{uri}', 'PageController#view')->where('uri', '.+');
I have not tested this, but it should work. Adjust the RouteService class to your needs.
I'm using the first approach in my CMS and it works realy well. The only difference is that I have written a Job that handles all incoming requests and calls the controller actions respectively.

How to route cutom URL with to custom controller in CodeIgniter?

I have a PHP CodeIgniter Controller with name User and have a method that get details of user user_detail($username)
Now when i need to show user data for example for userName mike
I call this URL
http://www.example.com/user/user_detail/mike
My target
How to make user data accessible by next URLs
http://www.example.com/user/mike
or / and
http://www.example.com/mike
You have to read the this page from the official documentation of codeigniter. It covers all related things to Routing URLs easily. All routes must be configured via the file:
application/config/routes.php
It could be something like this :
$route['user/(:any)'] = "user/user_detail/$1";
This can be achieved by overriding CI_Controller class BUT dont change the original core files, like I said override the controller and put your logic in it.
Help: https://ellislab.com/codeigniter/user-guide/general/core_classes.html
how to create Codeigniter route that doesn't override the other controller routes?
Perhaps an easier solution would be to route it with the help of apache mod_rewrite in .htaccess
Here is an detailed explanation on how to achieve it: http://www.web-and-development.com/codeigniter-remove-index-php-minimize-url/
Hatem's answer (using the route config) is easier and cleaner, but pointing the usage of the _remap() function maybe helpful in some cases:
inside the CI_Controller, the _remap() function will be executed on each call to the controller to decide which method to use. and there you can check if the method exist, or use some defined method. in your case:
application/controllers/User.php
class User extends CI_Controller {
public function _remap($method, $params = array())
{
if (method_exists(__CLASS__, $method)) {
$this->$method($params);
} else {
array_unshift($params, $method);
$this->user_detail($params);
}
}
public function user_detail($params) {
$username = $params[0];
echo 'username: ' . $username;
}
public function another_func() {
echo "another function body!";
}
}
this will result:
http://www.example.com/user/user_detail/john => 'username: john'
http://www.example.com/user/mike ........... => 'username: mike'
http://www.example.com/user/another_func ... => 'another function body!'
but it's not going to work with: http://www.example.com/mike , since the controller -even if it's the default controller- is not called at all, in this case, CI default behaviour is to look for a controller called mike and if it's not found it will throws 404 error.
for more:
Codeigniter userguide 3: Controllers: Remapping Method Calls
Redirect to default method if CodeIgniter method doesn't exists.

CakePHP admin routing for REST API

frontend of my CakePHP app is based on the REST API, each controller has user and admin methods.
I would like to run admin method on controller with classic Cake view.
But if i type into browser URL like this:
http://myproject.loc/admin/cards/add/
I get only:
{
code: 500,
name: "View file api/app/View/Cards/json/admin_add.ctp" is missing.",
message: "View file api/app/View/Cards/json/admin_add.ctp" is missing.",
url: "/admin/cards/add/"
}
Question is:
How can i set right URL for admin routes? (without json prefix)
Read Json and XML Views in CakePHP and read it properly. A common mistake is that people forget to add the RequestHandler component to their components array. The component will take care of getting the right layout set for you and the data serialized.
If you really want to insist on removing the .json suffix from the URL but calling the same URL via browser and AJAX you'll have to make sure that you request the right content type. Check the headers you send.
I'm not sure if the RequestHandler will send you the right response if you only request json (application/json) in the header without using the suffix in the URL, it should work, give it a try.
Here is the ref.
http://book.cakephp.org/2.0/en/views/json-and-xml-views.html
You need to add following line into the your controller function
I hope your encoding it to the json in the following way
$arrayData = array(...);//as example
class PostsController extends AppController {
public function index() {
$this->autoRender = false;
$this->layout = null;
$this->set(compact('posts', 'comments'));
}
}
// View code - app/View/Posts/json/index.ctp
foreach ($posts as &$post) {
unset($post['Post']['generated_html']);
}
echo json_encode(compact('posts', 'comments'));

CakePHP: using Security::allowedControllers and Security::allowedActions

I'm trying to use Security::allowedControllers and Security::allowedActions. So I have a controller which look more or less like this
class AppController extends Controller {
var $components = array('Security'); //other components
//other stuff
}
class BookController extends AppController {
function beforeFilter() {
parent::beforeFilter();
$this->Security->allowedControllers = array('Users');
$this->Security->allowedActions = array('view');
$this->Security->RequireAuth = array('search', 'results');
}
//other stuff
}
The action 'search' displays a form, which then calls 'results' to show the results of the search. I am intentionally trying to be blackholed.
For what I understand of $this->Security->allowedControllers and $this->Security->allowedActions, I should be able to get POST data only from the action 'view' of the controller 'Users'. In particular the action 'results' should redirect me to a black hole, since it obtains POST data from the action 'search' of the controller 'Books'.
But this is not the case. I can even make cross controller requests, and never get blackholed, so I guess I'm not using correctly this variables. What is the right way to trigger cross-controller requests control?
Try this:
$this->Security->allowedFields = array('Model.fieldname', ...);
You need to add the fields that are not in the model to the allowedFields like I guess your Model.search field in the form.
This is a good and short tutorial for doing Auth with CakePHP 1.3: http://tv.cakephp.org/video/jasonwydro/2011/01/29/cakephp_1_3_auth_authentication_component_tutorial_-_administrator_login

Categories