I'm trying to add REST api to my existing classic Yii2 (advanced template) project. According to Creating a REST API for Yii2-basic-template
and RESTful API in Yii 2 Advanced Application Template I'm trying to achieve that by adding a new module to my existing app.
Here is my application structure now:
+ api
+ config
-main.php
+ modules
+ v1
+ controllers
-Module.php
-index.php
-.htaccess
+ backend
+ common
...
My api/config/main.php file:
<?php
$params = require(__DIR__ . '/../../backend/config/params.php');
return [
'id' => 'app-backend-api',
'basePath' => dirname(__DIR__) . '/..',
'bootstrap' => ['log'],
'modules' => [
'v1' => [
'class' => 'api\modules\v1\Module'
]
],
'components' => [
'request' => [
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' => ['v1/goal']],
],
],
],
'params' => $params,
];
and my Module.php
<?php
namespace api\modules\v1;
class Module extends \yii\base\Module
{
public $controllerNamespace = 'api\modules\v1\controllers';
public function init()
{
parent::init();
}
}
The problem is that when I try to navigate to http://my-url/api/v1/goals I get the following error:
Invalid Configuration – yii\base\InvalidConfigException
Failed to instantiate component or class "api\modules\v1\Module".
Caused by: ReflectionException
Class api\modules\v1\Module does not exist
in C:\wamp64\www\agency\vendor\yiisoft\yii2\di\Container.php at line 453
Create file common/config/aliases.php:
Yii::setAlias('common', dirname(__DIR__));
Yii::setAlias('frontend', dirname(dirname(__DIR__)) . '/frontend');
Yii::setAlias('backend', dirname(dirname(__DIR__)) . '/backend');
Yii::setAlias('console', dirname(dirname(__DIR__)) . '/console');
Yii::setAlias('api', dirname(dirname(__DIR__)) . '/api');
Add this line to file api/web/index.php
require(__DIR__ . '/../../common/config/aliases.php');
Related
My code structure:
config/
controllers/
models/
api-data/
config/
api.php
modules/
v1/
controllers/
ProgramStudiController.php
module.php
index.php
.htaccess
Here is api.php:
<?php
$db = require(__DIR__ . '/../../config/db.php');
$params = require(__DIR__ . '/params.php');
$config = [
'id' => 'basic',
'name' => 'TimeTracker',
// Need to get one level up:
'basePath' => dirname(__DIR__).'/..',
'bootstrap' => ['log'],
'components' => [
'request' => [
// Enable JSON Input:
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
// Create API log in the standard log dir
// But in file 'api.log':
'logFile' => '#app/runtime/logs/api.log',
],
],
],
'urlManager' => [
'enablePrettyUrl' => true,
'enableStrictParsing' => true,
'showScriptName' => false,
'rules' => [
['class' => 'yii\rest\UrlRule', 'controller' => 'v1/programstudi'],
],
],
'db' => $db,
],
'modules' => [
'v1' => [
'basePath' => '#app/modules/v1',
'class' => 'api-data\modules\v1\Module', // here is our v1 modules
'controllerNamespace' => 'app\modules\v1\controllers',
],
],
'params' => $params,
];
return $config;
index.php:
<?php
// comment out the following two lines when deployed to production
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
// Use a distinct configuration for the API
$config = require(__DIR__ . '/config/api.php');
(new yii\web\Application($config))->run();
.htaccess:
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
module.php:
<?php
// Check this namespace:
namespace api-data\modules\v1;
class Module extends \yii\base\Module
{
public function init()
{
parent::init();
// ... other initialization code ...
}
}
ProgramStudiController.php:
<?php
namespace \api-data\modules\v1\controllers;
use yii\rest\ActiveController;
class ProjectController extends ActiveController
{
// We are using the regular web app modules:
public $modelClass = 'app\models\ProgramStudi';
}
I call with http://localhost/sbmptn/api-data/v1/programstudi, but the response is 404. Does anybody know what I'm doing wrong?
You named conroller as ProgramStudiController and then class ProjectController. Rename it and use url like /api-data/v1/program-studi, with - sign, because you used camelcase in controller name.
Btw, you should create main controller in controllers/ folder and then extend it in api-data/modules/v1/controllers.
I've been following a few tutorials online but I can't seem to figure out how to create a REST API for Yii2. I keep getting a 404 page not found. This is what I have so far:
Folder structure:
api
- config
-- api.php
-- bootstrap.php
- modules
-- v1
--- controllers
---- UserController.php
--- Api.php
--- Module.php
.htaccess
index.php
api/api.php
<?php
$params = require(__DIR__ . '/params.php');
$config = [
'id' => 'api',
'basePath' => dirname(__DIR__).'/..',
'bootstrap' => ['log'],
'components' => [
// URL Configuration for our API
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
[
'class' => 'yii\rest\UrlRule',
'controller' => [
//'v1/user'
'users' => 'v1/users'
],
]
],
],
'request' => [
// Set Parser to JsonParser to accept Json in request
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
],
'cache' => [
'class' => 'yii\caching\FileCache',
],
// Set this enable authentication in our API
'user' => [
'identityClass' => 'app\models\User',
'enableAutoLogin' => false, // Don't forget to set Auto login to false
],
// Enable logging for API in a api Directory different than web directory
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
// maintain api logs in api directory
'logFile' => '#api/runtime/logs/error.log'
],
],
],
'db' => require(__DIR__ . '/../../config/db.php'),
],
'modules' => [
'v1' => [
'basePath' => '#api/modules/v1',
'class' => 'api\modules\v1\Api',
]
],
'params' => $params,
];
return $config;
api/bootstrap.php
<?php
Yii::setAlias('api', dirname(dirname(__DIR__)) . '/api');
api/modules/v1/controllers/UserController.php
<?php
namespace app\api\modules\v1\controllers;
class UserController extends ActiveController
{
public $modelClass = 'app\models\User';
}
api/modules/v1/Api.php
<?php
namespace api\modules\v1;
use \yii\base\Module;
class Api extends Module
{
public $controllerNamespace = 'api\modules\v1\controllers';
public function init()
{
parent::init();
// custom initialization code goes here
}
}
api/modules/v1/Module.php
<?php
namespace api\modules\v1;
class Module extends \yii\base\Module
{
public $controllerNamespace = 'api\modules\v1\controllers';
public function init()
{
parent::init();
\Yii::$app->user->enableSession = false;
// custom initialization code goes here
}
}
api/.htaccess
Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php
api/index.php
<?php
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
require(__DIR__ . '/config/bootstrap.php');
$config = require(__DIR__ . '/config/api.php');
$application = new yii\web\Application($config);
$application->run();
mod_rewrite is enabled
Not sure what else needs to be done from here. I also have this added to common/config/main.php
'modules' => [
'user' => [
'class' => 'dektrium\user\Module',
],
'v1' => [
'basePath' => '#api/modules/v1',
'class' => 'api\modules\v1\Api',
]
],
I use Postman to send GET requests:
http://example.com/api/v1/users
and
http://example.com/v1/users which returns Class app\api\modules\v1\Api does not exist
I made a few changes to the configuration and files, but no luck. This is the cleanest version I have.
Please try this
Your controller name is UserController
and you are accessing users in api
try to access user in api url
I have Yii2 advanced template, I want to set translation for my frontend views, here is what I did:
frontend/config/main.php:
'sourceLanguage'=>'en-US',
'language'=>'en-US',
'components' => [
'i18n' => [
'translations' => [
'app*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '#common/messages',
'sourceLanguage' => 'en-US',
'fileMap' => [
'app' => 'app.php',
'app/error' => 'error.php',
],
],
],
],
]
then I added i18n.php in common/config:
<?php
return [
'sourcePath' => __DIR__. '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR,
'languages' => ['fr-FR','en-US'], //Add languages to the array for the language files to be generated.
'translator' => 'Yii::t',
'sort' => false,
'removeUnused' => false,
'only' => ['*.php'],
'except' => [
'.svn',
'.git',
'.gitignore',
'.gitkeep',
'.hgignore',
'.hgkeep',
'/messages',
'/vendor',
],
'format' => 'php',
'messagePath' => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'messages',
'overwrite' => true,
];
and the common/messages/en-US/app.php:
<?php
return[
// Menu texts
'menu.login'=>'login',
];
and I used it in the views as : Yii::t('app', 'menu.login');
but the translation didn't work, it displayed as menu.login
You Just Follow This Steps......
Step 1: In the common directory , create messages folder.
Step 2: Create i18n.php file inside common/config directory with following content:
<?php
return [
'sourcePath' => __DIR__. '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR,
'languages' => ['en-EN', 'ru-RU'], //Add languages to the array for the language files to be generated, here are English and Russian.
'translator' => 'Yii::t',
'sort' => false,
'removeUnused' => false,
'only' => ['*.php'],
'except' => [
'.svn',
'.git',
'.gitignore',
'.gitkeep',
'.hgignore',
'.hgkeep',
'/messages',
'/vendor',
],
'format' => 'php',
'messagePath' => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'messages', //path of messages folder created above
'overwrite' => true,
];
Note: Make sure to add all required languages to 'languages' array. In the above example I have added English and Russian for Generate Yii2 Framework multi language.
Step 3: Add the i18n component in config file common/main.php configuration as follows:
'components' => [
...
'i18n' => [
'translations' => [
'frontend*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '#common/messages',
],
'backend*' => [
'class' => 'yii\i18n\PhpMessageSource',
'basePath' => '#common/messages',
],
],
],
...
],
Step 4:
Add the language module in common config file to use the default language on your app, such as:
'language' => 'en-EN' inside common/main.php.
You now can use Yii::$app->language = ‘en-EN’ at any runtime like URL request, query code.
Note: In any Model, Controller Generate by Gii, you can see Enable I18n ticket choice, just enable this for Multi language. Gii Tool will auto generate a Model has pre-defined as below, due to frontent or backend folder:
Yii::t('frontend', 'Translatable String');
Yii::t('backend', 'Translatable String');
Step 5: Run this command line from Yii2 app folder:
yii message/extract #common/config/i18n.php
This command line will Generate Yii2 Framework multi language translation files inside common/messages and divide into frontend and backend folder.
For example: Yii message will generate the translation files as follows:
common/
.....
messages/
en-EN/
backend.php
frontend.php
ru-RU/
backend.php
frontend.php
.....
If you want to edit the translate text, just open backend.php or frontend.php file and edit.
I'm a beginner at zf2 and trying to do some sort of folder structuring so make them nice and manageable.
I'm trying to structure my controllers and views in such way that backend related files are in their folder and frontend will be in theirs. I managed to separate my controllers with folders and namespacing them, (ex. Blog\Controller\Frontend\Blog & Blog\Controller\Backend\Blog) and I can make call to them as well using the invokables in the config. However I cannot do that same in the views (Ex. view\blog\frontend\blog & views\blog\backend\blog) as it is looking only in views\blog\blog folder.
Can anyone help how can I fix it so that my views can have some separation of folders for each end?
My module.config.php looks like the following:
<?php namespace Blog;
return [
'controllers' => [
'invokables' => [
// 'Blog\Controller\Blog' => 'Blog\Controller\BlogController',
'Blog\Controller\Frontend\Blog' => 'Blog\Controller\Frontend\BlogController',
'Blog\Controller\Backend\Blog' => 'Blog\Controller\Backend\BlogController',
],
],
'router' => [
'routes' => [
'blog' => [
'type' => 'segment',
'options' => [
'route' => '/blog/blog[/:action][/:id]',
'constraints' => [
// 'controller' => 'Blog\Controller\Blog',
'controller' => 'Blog\Controller\Frontend\Blog',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
],
'defaults' => [
// 'controller' => 'Blog\Controller\Blog',
'controller' => 'Blog\Controller\Frontend\Blog',
'action' => 'index',
],
],
],
],
],
'view_manager' => [
'template_path_stack' => [
'blog' => __DIR__ . '/../view',
],
],
// Doctrine config
'doctrine' => [
'driver' => [
__NAMESPACE__ . '_driver' => [
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => [
__DIR__ . '/../src/' . __NAMESPACE__ . '/Entity'
],
],
'orm_default' => [
'drivers' => [
__NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver'
],
],
],
],
];
First of all, you could've come with Blog\Controller\BlogFrontend and Blog\Controller\BlogBackend classes. It would've made your life a little bit easier.
If, for one reason or another, you don't want to rename them, you can set a rendering template manually:
class IndexController extends AbstractActionController
{
public function indexAction()
{
$view = new ViewModel();
$view->setTemplate ('application/frontend/blog/index.phtml');
return $view;
}
}
and in the admin controller
class IndexController extends AbstractActionController
{
public function indexAction()
{
$view = new ViewModel();
$view->setTemplate ('application/backend/blog/index.phtml');
return $view;
}
}
Here i have used yii2 configuration with rules
<?php
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'),
require(__DIR__ . '/../../common/config/params-local.php'),
require(__DIR__ . '/params.php'),
require(__DIR__ . '/params-local.php')
);
return [
'id' => 'app-backend',
'basePath' => dirname(__DIR__),
'controllerNamespace' => 'backend\controllers',
'bootstrap' => ['log'],
'modules' => [],
'components' => [
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'urlManager' => [
'enablePrettyUrl' => true,
'rules' => require(__DIR__ . '/routes.php'),
],
'errorHandler' => [
'errorAction' => 'site/error',
],
],
'params' => $params,
];
And given below routes.php
<?php
use yii\web\UrlRule;
return array(
// REST routes for CRUD operations
'POST <controller:\w+>s' => '<controller>/create', // 'mode' => UrlRule::PARSING_ONLY will be implicit here
'api/<controller:\w+>s' => '<controller>/index',
'PUT api/<controller:\w+>/<id:\d+>' => '<controller>/update',// 'mode' => UrlRule::PARSING_ONLY will be implicit here
'DELETE api/<controller:\w+>/<id:\d+>' => '<controller>/delete', // 'mode' => UrlRule::PARSING_ONLY will be implicit here
'api/<controller:\w+>/<id:\d+>' => '<controller>/view',
// normal routes for CRUD operations
'<controller:\w+>s/create' => '<controller>/create',
'<controller:\w+>/<id:\d+>/<action:update|delete>' => '<controller>/<action>',
);
When i access local2host.com/advanced/backend/web/index.php/country/create - It's working fine
but when i access through local2host.com/advanced/backend/web/index.php/api/country/create
It's throwing 404 - not found error
Unable to resolve the request "api/country/create".
As per my requirement :
when i access this link local2host.com/advanced/backend/web/index.php/api/country/create
it should access "country" as controller and "create" as action
It seems you have modules. First you need to add your api module into your config file:
'modules' => [
'api'
],
Second, you need to add module into your rules like below:
'<module:\w+>/<controller:\w+>/<action:\w+>'=>'<module>/<controller>/<action>',
'<module:\w+><controller:\w+>/<action:update|delete>/<id:\d+>' => '<module>/<controller>/<action>',
This is remarkable that, you may need to take care of other rules with module and have your own customized rules.