I'm devising a codeception test to load a component,.... I have the following test file
<?php
namespace tests\codeception\common;
use Yii;
class FoursquareTest extends \Codeception\TestCase\Test
{
public $appConfig = '#tests/codeception/config/common/unit.php';
public function setUp()
{
parent::setUp();
$config = [
'components' => [
'foursquare' =>
[
'class' => 'garyrutland\foursquare\Foursquare',
'clientId' => '',
'secret' => ''
]
]];
Yii::configure(Yii::$app, $config);
}
// tests
public function testSearch()
{
//$this->assertInstanceOf('garyrutland\\foursquare\\Foursquare', Yii::$app->foursquare);
}
public function fixtures()
{
return [
'foursquare' => [
'class' => FoursquareFixture::className()
],
];
}
}
But when I run
codecept run unit FoursquareTest.php -vv
I get
PHPUnit_Framework_Exception: Creating default object from empty value
#1 /path/to/htdocs/yii/vendor/yiisoft/yii2/BaseYii.php:518
#2 /path/to/htdocs/yii/tests/codeception/common/unit/FoursquareTest.php:22
I instantiate the Foursquare class directly though there is no problem....
Whay do i gee the created Object Error
Related
Hi I'm new to Laravel framework and I'm trying to inject process ID into every log passed to Google Logging service.
I've been able to see the log passed into Google Logging service now, but I've no idea how I could inject more info(Process ID in this case) into my log message.
So far I've tried "tap" method and I can see addition info injected into my log while reading laravel.log file, but same method doesn't seems to work while using Google Cloud Logging plugin.
Below is my script for Google Logging service.
Inside config/logging.php
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['stackdriver'],
],
'stackdriver' => [
'driver' => 'custom',
'via' => App\Logging\CreateStackdriverLogger::class,
'level' => 'debug',
],
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => 'debug',
'tap' => [App\Logging\ProcessorTap::class],
],
];
CreateStackdriverLogger.php
use Google\Cloud\Logging\LoggingClient;
use Monolog\Handler\PsrHandler;
use Monolog\Logger;
class CreateStackdriverLogger
{
/**
* Create a custom Monolog instance.
*
* #param array $config
* #return \Monolog\Logger
*/
public function __invoke(array $config)
{
$logName = isset($config['logName']) ? $config['logName'] : 'app';
$psrLogger = LoggingClient::psrBatchLogger($logName);
$handler = new PsrHandler($psrLogger);
$logger = new Logger($logName, [$handler]);
return $logger;
}
}
Code for 'tap' method, I'm able to see 'pid' inside 'extra', but same method don't work with 'stackdriver'.
ProcessorTab.php
namespace App\Logging;
use Illuminate\Log\Logger;
use Illuminate\Support\Arr;
use Monolog\Formatter\LineFormatter;
class ProcessorTap
{
public function __invoke($logger)
{
foreach ($logger->getHandlers() as $handler) {
$handler->pushProcessor(function ($record) {
return Arr::add($record, 'prefix', getmypid());
});
$handler->setFormatter($this->getLogFormatter());
$handler->pushProcessor([$this, 'processLogRecord']);
}
}
public function processLogRecord(array $record): array
{
$record['extra'] += [
'pid' => getmypid(),
];
return $record;
}
protected function getLogFormatter()
{
$format = "[%datetime%] %channel%.%level_name%: %prefix%.%message% %context% %extra%\n";
return new LineFormatter($format, null, true, true);
}
}
I have such a simplified version of a class
class Handler extends ExceptionHandler
{
protected $dontReport = [];
public function report(Exception $exception)
{
$environment = \App::environment();
//...
}
//...
}
And I receive PHP Fatal error: Uncaught Error: Class 'App' not found in .../app/Exceptions/Handler.php:37.
In other places of the app it works.
In config/app.php it was registered.
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
//...
]
Add to top of your class use App then you can use App Facade like App::environment()
The problem was in jeroennoten/laravel-adminlte package, config/adminlte.php file.
Looks like in
'menu' => [
[
'text' => 'API documentation',
'url' => request()->getSchemeAndHttpHost() . '/docs',
'icon' => 'file-o',
],
],
request()->getSchemeAndHttpHost() in calling from the console has caused an exception and at that moment something related to facades was not initialized (would be glad to hear what exactly), so my handler has triggered a second exception I've been catching.
I have extracted menu creation to the provider, but I'm not sure, if it's a good solution.
class AdminMenuProvider extends ServiceProvider
{
public function boot(Dispatcher $events)
{
$events->listen(BuildingMenu::class, function (BuildingMenu $event) {
$event->menu->add([
'text' => 'API documentation',
'url' => request()->getSchemeAndHttpHost() . '/docs',
'icon' => 'file-o',
]);
//...
}
}
}
I am new to Zend Framework 3 and I am doing this tutorial:
I have a xampp, mysql setup.
I have done everything exactly like in this tutorial. Now I am at the point where you configure the database connection. Further I have set up the controller and view.
In the tutorial link above , they are using php to create a database and then in config/autoload/global.php.....the following code:
return [
'db' => [
'driver' => 'Pdo',
'dsn' => sprintf('sqlite:%s/data/zftutorial.db', realpath(getcwd())),
],
];
I have edited this to:
'db' => [
'driver' => 'Pdo_Mysql',
'dsn' => 'mysql:dbname=dbname;host=localhost;charset=utf8;username=myuser;password=mypassword',
],
When I call the url for the index view, there the following error:
Warning: Creating default object from empty value in C:\xampp\htdocs\zendtest\module\Album\src\Controller\AlbumController.php on line 15
Fatal error: Call to a member function fetchAll() on null in
C:\xampp\htdocs\zendtest\module\Album\src\Controller\AlbumController.php
on line 22
The AlbumController:
<?php
namespace Album\Controller;
use Album\Model\AlbumTable;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class AlbumController extends AbstractActionController {
private $table;
public function __construct(AlbumTable $table)
{
$this->table = $table;
}
public function indexAction()
{
return new ViewModel([
'albums' => $this->table->fetchAll(),
]);
}
}
I think that the connection doesn't work??
can you share your "AlbumControllerFactory.php" ?
if you have not yet created the factory you should do.
1 - Create AlbumControllerFactory that implements FactoryInterface
2 - Inside __invoke function use the Container to inject AlbumTable to your controller
3 - config your mapping in module.config.php
'controllers' => [
'factories' => [
Controller\AlbumController::class => Controller\Factory\AlbumControllerFactory::class,
All simple, you have mistake in key $this, you did write $htis instead )
I am using Yii2 Advanced version.
This is Login Model:
namespace common\models;
use Yii;
use yii\base\Model;
use common\models\User;
class LoginForm extends Model{
public $username;
public $password;
public $rememberMe = true;
public $verifyCode;
const BACKEND_TEST = 'none';
const BACKEND_ID = 'test';
const BACKEND_USERNAME = 'backend_username';
private $user;
public function rules(){
return [ [['username','password'],'required','message'=>'{attribute}required...'],
['username','validateUser'], ['verifyCode','captcha','captchaAction'=>'login/captcha','message'=>'Wrong'],
];
}
public function validateUser($attribute,$params){
$user = User::findOne(['username'=>$this->username]);
if(!$user || (md5($this->password) != $user['password'])){
$this->addError('password','Wrong>_<...');
}else{
$this->user = $user;
}
}
public function login(){
if(!$this->user){
return false;
}
var_dump($this->userInfo());
$this->createSession();
return true;
}
private function createSession(){
//Yii::$app->session->open();
Yii::$app->set(self::BACKEND_ID,$this->user['id']);
Yii::$app->set(self::BACKEND_USERNAME,$this->user['username']);
}
public function userInfo(){
return $this->user;
}
Also, there is LoginController that I think have no issue, and next thing is when user try to login and session will be opened, and direct to site page.
Here is the sitecontroller:
namespace backend\controllers;
use Yii;
use yii\web\Controller;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use common\models\LoginForm;
/**
* Site controller
*/
class SiteController extends Controller
{
public function actionIndex()
{
//var_dump(Yii::$app->session->get(common\models\LoginForm::BACKEND_ID));
var_dump(LoginForm::userInfo());
return $this->renderPartial('index');
}
Every time I try to login and the Error message comes out and provides:
Invalid Configuration – yii\base\InvalidConfigException
Unexpected configuration type for the "test" component: integer
How to solve the issue, and I try to get $user that stores all the data and it seems to fail?
main.php:
<?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' => ['smister' => [
'class' => 'backend\modules\smister\smister',
],],
'components' => [
'user' => [
'identityClass' => 'common\models\User',
'enableAutoLogin' => true,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
'levels' => ['error', 'warning'],
],
],
],
'errorHandler' => [
'errorAction' => 'site/error',
],
/*
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
],
],
*/
],
'params' => $params,
];
You are using
Yii::$app->set(self::BACKEND_ID,$this->user['id']);
probably for set a param value ..
but the Class yii\web\Application (alias Yii::$app->set ) contain a function named set() that register component ..(so your error : Unexpected configuration type for the "test" component: integer) in this way your code is misundestood by Yii2 because your costant BACKEND_ID = 'test'; is not a component id but the key for a param
see this reference for check
http://www.yiiframework.com/doc-2.0/yii-web-application.html
http://www.yiiframework.com/doc-2.0/yii-di-servicelocator.html#set()-detail
for you scope if you need param you can use the file param.php
returning the param you need
file config/param.php
<?php
return [
'test' => 'my_initial_value',
];
and you can access this param simply using
\Yii::$app->params['test'],
or you can simply setting runtime
\Yii::$app->params['test'] = 'Your_value';
I have a module calls API, and i want to load config file for it. The guide says that i have to use function \Yii::configure. I use it, but it doesn't apply any new configs. And i tried to use array instead config file, the result is same
class API extends \yii\base\Module
{
public $controllerNamespace = 'api\client\controllers';
public function init()
{
parent::init();
// \Yii::configure($this, require(__DIR__ . '/config/main.php'));
\yii::configure($this, [
'components' => [
'user' => [
'class' => 'yii\web\UserTest',
'identityClass' => 'api\client\models\User',
],
]
]);
echo \yii::$app->user->className();
die();
}
}
How I can override config in my module ?
UPDATE
You have to use setComponents method of Yii::$app
Yii::$app->setComponents(
[
'errorHandler'=>[
'errorAction'=>'forum/forum/error',
'class'=>'yii\web\ErrorHandler',
],
'user' => [
'class' => 'yii\web\User',
'identityClass' => 'app\modules\profile\models\User',
],
]
);
OLD ANSWER
Didn't it give you errors? Your casing are wrong and so instead of "yii" in small letters use "Yii" capitalized
class API extends \yii\base\Module
{
public $controllerNamespace = 'api\client\controllers';
public function init()
{
parent::init();
\Yii::configure($this, [
'components' => [
'user' => [
'class' => 'yii\web\UserTest',
'identityClass' => 'api\client\models\User',
],
]
]);
echo \Yii::$app->user->className();
die();
}
}
I see no reason to override the application components here. I'd use #StefanoMtangoo trick but to set the component to the Module itself instead of Yii::$app:
public function init()
{
parent::init();
$this->setComponents([
'db' => [
'class' => 'yii2tech\filedb\Connection',
'path' => '#app/builder/data',
]
]);
}
Then the tricky part is to differentiate between any app's components and your module's own components. For example if my Module had a model extending yii\db\ActiveRecord I'd override its getDB() as follow (original code here):
public static function getDb()
{
return Yii::$app->getModule('api')->get('db');
// instead of: return Yii::$app->getDb();
}
So whatever the app that is using my module has or hasn't a db component it won't matter.