i try to build a custom POST route for ReST API in cakephp 3, but when i want to connect to the url i got result:
The view for CalculatedpricesController::getCosts() was not found.
My url to connect to ReST like this :
http://localhost/test/api/calculatedprices/getCosts
here's the route code:
Router::scope('/', function (RouteBuilder $routes) {
Router::prefix('api', function ($routes) {
$routes->extensions(['json', 'xml']);
$routes->resources('Calculatedprices', [
'map' => [
'getCosts' => [
'action' => 'getCosts',
'method' => 'POST'
]
]
]);
});
$routes->fallbacks(DashedRoute::class);
});
here's the controller code:
namespace App\Controller\Api;
use App\Controller\Api\AppController;
/**
* Calculatedprices Controller
*
* #property \App\Model\Table\CalculatedpricesTable $Calculatedprices
*/
class CalculatedpricesController extends AppController
{
public function getCosts(){
$originIdCity = $this->request->query('originCity');
$originIdSub = $this->request->query('originSub');
$courierId = $this->request->query('courierId');
$serviceId = $this->request->query('serviceId');
$conditions = array('origin_city_id' => $originIdCity,
'courier_id' => $courierId,
'service_id' => $serviceId
);
if($originIdSub == ''){
$condition = 'origin_subdistrict_id IS NULL';
array_push($conditions,$condition);
} else{
$conditions['origin_subdistrict_id'] = $originIdSub;
}
$calculatedprices = $this->Calculatedprices->find('all', array(
'conditions' => $conditions
));
$this->set([
'calculatedprices' => $calculatedprices,
'_serialize' => ['calculatedprices']
]);
}
}
Related
The following route works fine and the method can loop through the items:
http://localhost/library/api/books
$app->get('/api/books', 'Book:getBooks');
The class:
class Book {
:
:
public function __construct($container) {
$this->container = $container;
}
public function getBooks($request, $response) {
:
:
echo '{"book": ' . json_encode($books) . '}';
}
public function getBook($id) {
echo json_encode($id);
}
}
Calling the method with route pattern identified by 'id' as follows, returns nothing (empty $id):
http://localhost/library/api/books/10
$app->get('/api/books/{id}', 'Book:getBook');
It seems like 'id' won't pass.
How to handle correctly route pattern by identifier?
As I said in the comments, please let us know what the dev console says for instance in chrome under the category console and network.
I am not sure why you choose to create your routes like that, but I would create them following way (which also looks more tidy) :
Route::group(['prefix' => 'book'], function ()
{
Route::get('/', ['as' => 'index', 'uses' => 'BookController#index']);
Route::get('new', ['as' => 'new', 'uses' => 'BookController#new']);
Route::get('show/{bookID}', ['as' => 'show', 'uses' => 'BookController#show']);
Route::get('edit/{bookID}', ['as' => 'edit', 'uses' => 'BookController#edit']);
Route::post('create', ['as' => 'create', 'uses' => 'BookController#create']);
Route::post('update', ['as' => 'update', 'uses' => 'BookController#update']);
Route::delete('destroy/{deviceID}', ['as' => 'destroy', 'uses' => 'BookController#destroy']);
});
The BookController would look like this then:
class BookController extends Controller
{
// this shows all books and adds a pagination of 15 items, which you can easily increase or decrease
public function index()
{
$books = DB::table('books')->paginate(15);
return view('books.index', compact('books');
}
public function new()
{
$book = new Book;
return view('books.new', [
'books' => $books,
'type' => 'new'
]);
}
public function create(Request $request)
{
$this->validate($request, Book::$rules); // I put the rules inside of the Book Model, but you could just add them here aswell
$data = $request->all();
$book = new Book();
$book->fill($data);
if($book->save())
{
return redirect()->route('new')->with('success', 'success.');
}
else
{
return redirect()->route('new')->with('error', 'Error.')->withInput();
}
public function edit(Request $request, $bookID = 0)
{
$books = Book::all();
$newBook = new Book;
$book = Book::find($bookID);
if(is_null($book))
{
$books = Device::paginate(10); // paginate if you like to
return view('books.index', [
'books' => $books,
'errorNoBook' => 'No BOok'
]);
}
else
{
$bookID = $book->id;
}
return view('books.edit', [
'allBooks' => $allBooks,
'new' => $new,
'book' => $book,
]);
}
}
The following is a simple working solution that I found:
:
:
public function getBook($request, $response) {
$route = $request->getAttribute('route'); // route object
$id = $route->getArgument('id'); // route object identifier
$book = $this->db->table('books')->where('id', $id)->first();
echo json_encode($book);
}
I've implemented a router, securityplugin (for ACL) and notfoundplugin.
I want my site to be set up with a subcontroller structure: Link
The website is set up in the following main parts:
Index
Admin
Tickets
Account
The issues I have:
When calling: domain/admin/actionofadmin
Returns custom 404: "Page doesn't exist" instead of the normal action result
When calling: domain/admin/actionofadmin. (<-- mind the dot at the end)
Returns index action of index controller instead of the normal action result
Why does the router return theses results? How can they be fixed?
Extra questions:
How does Phalcon know where to find a view and link it to the correct controller? Example: A dashboardController resides in a folder "admin" inside the folder "controllers".
How does Phalcon know that in the SecurityPlugin ACL it needs to search for the correct controller while it doesn't get a namespace? Example: When I want to allow controller Tickets of namespace app\controllers\admin to be only viewed by admin users.
Extra information:
Phalcon 3.0.3
PHP 5.6
Let me know if you need any more information / files or if I should post it somewhere else for ease of reading.
Files:
/app/controllers/AdminController.php
<?php
namespace Ontrack\Controllers;
class AdminController extends ControllerBase
{
public function indexAction(){
}
public function testAction(){
echo "test";
}
}
/app/config/services.php Excerpt
//This makes sure the routes are correctly handled for authorized/unauthorized
/**
* MVC dispatcher
*/
$di->set("dispatcher", function () use ($di) {
// Create an events manager
$eventsManager = $di->getShared('eventsManager');
/**
*Check if the user is allowed to access certain action using the SecurityPlugin
*Listen for events produced in the dispatcher using the Security plugin
*/
$eventsManager->attach("dispatch:beforeDispatch", new SecurityPlugin());
// Handle exceptions and not-found exceptions using NotFoundPlugin
$eventsManager->attach("dispatch:beforeException", new NotFoundPlugin());
$dispatcher = new Dispatcher();
$dispatcher->setDefaultNamespace('Ontrack\Controllers');
// Assign the events manager to the dispatcher
$dispatcher->setEventsManager($eventsManager);
return $dispatcher;
}
);
/app/config/loader.php
<?php
$loader = new \Phalcon\Loader();
/**
* We're a registering a set of directories taken from the configuration file
*/
$loader->registerDirs(
[
$config->application->controllersDir,
$config->application->modelsDir,
$config->application->pluginsDir
]
)->register();
$loader->registerNamespaces(
[
'Ontrack\Controllers' => APP_PATH . '/controllers/',
'Ontrack\Controllers\Admin' => APP_PATH . '/controllers/admin',
'Ontrack\Models' => APP_PATH . '/models/'
]
)->register();
/app/config/routes.php
<?php
$router = new Phalcon\Mvc\Router(false);
$router->setDefaults(
[
"controller" => "index",
"action" => "index",
]
);
$router->add('/:controller/:action/:params', [
'namespace' => 'Ontrack\Controllers',
'controller' => 1,
'action' => 2,
'params' => 3,
]);
$router->add('/:controller/:action', [
'namespace' => 'Ontrack\Controllers',
'controller' => 1,
'action' => 2,
]);
$router->add('/:controller', [
'namespace' => 'Ontrack\Controllers',
'controller' => 1,
]);
$router->add('/admin/:controller/:action/:params', [
'namespace' => 'Ontrack\Controllers\Admin',
'controller' => 1,
'action' => 2,
'params' => 3,
]);
$router->add('/admin/:controller/:action', [
'namespace' => 'Ontrack\Controllers\Admin',
'controller' => 1,
'action' => 2,
]);
$router->add('/admin/:controller', [
'namespace' => 'Ontrack\Controllers\Admin',
'controller' => 1,
]);
$router->removeExtraSlashes(true);
return $router;
/app/plugins/SecurityPlugin.php
<?php
use Phalcon\Acl;
use Phalcon\Acl\Role;
use Phalcon\Acl\Adapter\Memory as AclList;
use Phalcon\Acl\Resource;
use Phalcon\Events\Event;
use Phalcon\Mvc\User\Plugin;
use Phalcon\Mvc\Dispatcher;
class SecurityPlugin extends Plugin
{
/**
* Returns an existing or new access control list
*
* #returns AclList
*/
public function getAcl()
{
if (!isset($this->persistent->acl)) {
$acl = new AclList();
$acl->setDefaultAction(Acl::DENY);
// Register roles
$roles = [
'admins' => new Role(
'admins',
'Website administrators'
),
'users' => new Role(
'users',
'Member privileges, granted after sign in.'
),
'guests' => new Role(
'guests',
'Anyone browsing the site who is not signed in is considered to be a "Guest".'
)
];
foreach ($roles as $role) {
$acl->addRole($role);
}
//Private area resources
$privateResources = array(
'account' => array('*')
);
$privateResourcesAdmin = array(
'admin' => array('*'),
'tickets' => array('*')
);
//Public area resources
$publicResources = array(
'index' => array('*'),
'register' => array('*'),
'errors' => array('show401', 'show404', 'show500'),
'register' => array('*'),
'login' => array('*'),
'logout' => array('*')
);
foreach ($privateResources as $resource => $actions) {
$acl->addResource(new Resource($resource), $actions);
}
foreach ($privateResourcesAdmin as $resource => $actions) {
$acl->addResource(new Resource($resource), $actions);
}
foreach ($publicResources as $resource => $actions) {
$acl->addResource(new Resource($resource), $actions);
}
//Grant access to public areas to users, admins and guests
foreach ($roles as $role) {
foreach ($publicResources as $resource => $actions) {
foreach ($actions as $action){
$acl->allow($role->getName(), $resource, $action);
}
}
}
//Grant access to private area to role Users
foreach ($privateResources as $resource => $actions) {
foreach ($actions as $action){
$acl->allow('users', $resource, $action);
}
}
foreach ($privateResourcesAdmin as $resource => $actions) {
foreach ($actions as $action){
$acl->allow('admins', $resource, $action);
}
}
//The acl is stored in session, APC would be useful here too
$this->persistent->acl = $acl;
}
return $this->persistent->acl;
}
/**
* This action is executed before execute any action in the application
*
* #param Event $event
* #param Dispatcher $dispatcher
* #return bool
*/
public function beforeDispatch(Event $event, Dispatcher $dispatcher){
$auth = $this->session->has('auth');
if (!$auth){
$role = 'guests';
} else {
$authSession = $this->session->get("auth");
if($authSession['account_type'] == 99){
$role = 'admins';
} else {
$role = 'users';
}
}
$controller = $dispatcher->getControllerName();
$action = $dispatcher->getActionName();
$acl = $this->getAcl();
if (!$acl->isResource($controller)) {
$dispatcher->forward([
'controller' => 'errors',
'action' => 'show404'
]);
return false;
}
$allowed = $acl->isAllowed($role, $controller, $action);
if (!$allowed) {
if($controller === 'admin'){
$dispatcher->forward(array(
'controller' => 'errors',
'action' => 'show404'
));
} else {
$dispatcher->forward(array(
'controller' => 'errors',
'action' => 'show401'
));
}
return false;
}
}
}
/app/plugins/NotFoundPlugin.php
<?php
use Phalcon\Events\Event;
use Phalcon\Mvc\User\Plugin;
use Phalcon\Dispatcher;
use Phalcon\Mvc\Dispatcher\Exception as DispatcherException;
use Phalcon\Mvc\Dispatcher as MvcDispatcher;
/**
* NotFoundPlugin
*
* Handles not-found controller/actions
*/
class NotFoundPlugin extends Plugin
{
/**
* This action is executed before execute any action in the application
*
* #param Event $event
* #param MvcDispatcher $dispatcher
* #param Exception $exception
* #return boolean
*/
public function beforeException(Event $event, MvcDispatcher $dispatcher, Exception $exception)
{
error_log($exception->getMessage() . PHP_EOL . $exception->getTraceAsString());
if ($exception instanceof DispatcherException) {
switch ($exception->getCode()) {
case Dispatcher::EXCEPTION_HANDLER_NOT_FOUND:
case Dispatcher::EXCEPTION_ACTION_NOT_FOUND:
$dispatcher->forward(array(
'controller' => 'errors',
'action' => 'show404'
));
return false;
}
}
$dispatcher->forward(array(
'controller' => 'errors',
'action' => 'show500'
));
return false;
}
}
When calling: domain/admin/actionofadmin(as i understand domain is for example www.google.pl) phalcon is expecting ActionofadminController according to your routes. Are you sure there is such controller? Don't sure why with with dot it's hitting index controller and index action though.
How does Phalcon know where to find a view and link it to the correct controller? Example: A dashboardController resides in a folder "admin" inside the folder "controllers".
It's getting this info from dispatcher. Mvc application if you don't render view your self is implicit automatically rendering. Check this source: https://github.com/phalcon/cphalcon/blob/master/phalcon/mvc/application.zep#L348 And other view classes.
About Acl Plugin - it doesn't check for namespace at all. So if you have two controllers with same name but other namespace this wil cause obviously a problem. You just need to change security plugin to your needs.
My question is based on how I can pass the $searchResult in my Controller class so as I can use it to display the search result
This is my Controller
class SearchController extends Controller {
public function getHome($searchFor = null) {
$result = SearchPost::all();
return view('home', ['resulta' => $result]);
}
public function postSearch(Request $request) {
$this->validate($request, [
'searchString' => 'required|max:20|alpha',
]);
$searchFor = $request['searchString'];
//Connection with model(SearchPost) to search
$searchResult = SearchPost::search($searchFor);
return redirect()->route('home', ['searchFor' => $searchFor]);
}
}
Routes:
Route::get('/{searchFor?}', [
'uses' => 'SearchController#getHome',
'as' => 'home'
]);
Route::post('/search', [
'uses' => 'SearchController#postSearch',
'as' => 'search'
]);
Try the following methods:
return redirect(route('home', ['searchFor' => $searchFor]));
Or
return redirect('home')->with('home', ['searchFor' => $searchFor]);
I am new to laravel framework any help would appreciate
When i try to execute the below code i get this error
FatalErrorException in SocialController.php line 27: Class 'App\Http\Controllers\Hybrid_Auth' not found in SocialController.php line 27
when i remove the namespace from SocialController.php i get this error saying BaseController not found.
onclick this button
<i class="fa fa-facebook"></i> Facebook
SocialController.php
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
class SocialController extends BaseController
{
//this is the code for facebook Login
public function getFacebookLogin($auth=NULL)
{
if ($auth == 'auth')
{
try
{
Hybrid_Endpoint::process();
}
catch (Exception $e)
{
return Redirect::to('fbauth');
}
return;
}
$oauth = new Hybrid_Auth(app_path(). '/config/fb_auth.php');
$provider = $oauth->authenticate('Facebook');
$profile = $provider->getUserProfile();
return var_dump($profile).'Log Out';
}
public function getLoggedOut()
{
$fauth = new Hybrid_auth(app_path().'/config/fb_auth.php');
$fauth->logoutAllProviders();
return view::make('/');
}
}
fb_auth.php
<?php
return array(
"base_url" => "http://urmk.com/fbauth/auth",
"providers" => array (
"Facebook" => array (
"enabled" => true,
"keys" => array ( "id" => "APP_ID", "secret" => "APP_SECRET" ),
"scope" => "email"
)
)
);
Routes.php
Route::get('fbauth/{auth?}' ,array('as'=>'facebook', 'uses'=>'SocialController#getFacebookLogin'));
Route::get('logout',array('as'=>'logout','uses'=>'SocialController#getLoggedOut'));
You will need to add the namespace to your Hybrid Auth class. At the moment, when you are trying to instantiate the Hybrid_Auth object, it's not finding the class definition.
Here is my setup for Laravel:
app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind('Hybrid_Auth', function($app) {
return new \Hybrid_Auth(config_path('hybridauth.php'));
});
}
config/hybridauth.php
<?php
return [
'base_url' => env('APP_URL').'/auth/endpoint',
'providers' => [
'Facebook' => [
'enabled' => true,
'display' => 'popup',
'keys' => [
'id' => 'xxxx',
'secret' => 'xxx'
],
'scope' => 'email'
],
]
];
app/Http/routes.php
Route::group(['prefix' => 'auth'], function()
{
Route::get('login', 'AuthenticateController#login');
Route::get('endpoint', 'AuthenticateController#endpoint');
Route::get('logout', 'AuthenticateController#logout');
});
app/Http/Controllers/AuthenticateController.php
public function login(\Hybrid_Auth $auth)
{
$provider = $auth->authenticate('facebook');
$profile = $provider->getUserProfile();
$user = User::where('facebook', '=', $profile->identifier);
if($user->first()) {
return response()->json(['token' => $this->signin($user->first())]);
} else {
$user = new User;
$user->facebook = $profile->identifier;
$user->save();
return response()->json(['token' => $this->signin($user)]);
}
}
public function endpoint() {
\Hybrid_Endpoint::process();
}
public function logout(\Hybrid_Auth $auth) {
$auth->logoutAllProviders();
}
I managed to write the REST API code and it works for the standard actions.
Now, if I want to send more attributes, like url_to_api_action?a=b&c=d&e=f, this does not match any of the standard actions.
I need to search by attributes, using a RESTful API in Yii2.
any ideas?
<?php
namespace api\modules\v1\controllers;
use yii\rest\ActiveController;
class UneController extends ActiveController {
public $modelClass = 'common\models\Une';
}
I'm elaborating the answer
add search action mentioned in this link to the controller
Yii2 REST query
<?php
namespace api\modules\v1\controllers;
use yii\rest\ActiveController;
use yii\data\ActiveDataProvider;
/**
* Country Controller API
*
* #author Budi Irawan <deerawan#gmail.com>
*/
class CountryController extends ActiveController
{
public $modelClass = 'api\modules\v1\models\Country';
public $serializer = [
'class' => 'yii\rest\Serializer',
'collectionEnvelope' => 'items',
];
public function actionSearch()
{
if (!empty($_GET)) {
$model = new $this->modelClass;
foreach ($_GET as $key => $value) {
if (!$model->hasAttribute($key)) {
throw new \yii\web\HttpException(404, 'Invalid attribute:' . $key);
}
}
try {
$provider = new ActiveDataProvider([
'query' => $model->find()->where($_GET),
'pagination' => false
]);
} catch (Exception $ex) {
throw new \yii\web\HttpException(500, 'Internal server error');
}
if ($provider->getCount() <= 0) {
throw new \yii\web\HttpException(404, 'No entries found with this query string');
}
else {
return $provider;
}
}
else {
throw new \yii\web\HttpException(400, 'There are no query string');
}
}
}
And add urlManager like below in the config/main.php
Cant use tockens and extrapattern together for REST services in Yii2
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => 'v1/country',
'extraPatterns' => [
'GET search' => 'search'
],
],
[
'class' => 'yii\rest\UrlRule',
'controller' => 'v1/country',
'tokens' => [
'{id}' => '<id:\\w+>'
]
],
],
]
therefor we can use both default actions of the activecontroller and our custom actions together
You can create your own actions inside the controller, and you just need to return the result from Active Record and it will take care of formatting the data.
public function actionSearch($keyword)
{
$result = YourModel::find()
->where(['keyword' => $keyword])
->all();
return $result;
}
More details here: http://www.yiiframework.com/doc-2.0/guide-rest.html#creating-controllers-and-actions
public function actionSearch($keyword)
{
$result = YourModel::find()
->with('model relation')
->where(['keyword' => $keyword])
->all();
return $result;
}