zf2 Zend\ServiceManager\Exception\ServiceNotCreatedException - exception

I spent half day to resolve this issue with no success.
I'm doing a setup in EC2, centos 6/64 bit. LAMP installed. On another hosting, my zf2 solution it work fine, so I've searched issue in php modules installed also (list at the end).
This error happen when zf2 try to get an instance of my custom service, also with wasabi mail.
\zend\config\application.config.php
'config_glob_paths' => array(
'./config/autoload/{,*.}{global,local}.php',
),
\zend\config\autoload\global.php
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
'Zend\CustomLogger' => function ($sm) {
$auth = $sm->get('zfcuser_auth_service');
$customLogger = new \Application\Service\CustomLogger(
$sm->get('Request'),
$sm->get('ZendLog'),
new \Zend\Session\SessionManager(),
$auth->getIdentity(), // $user
$sm->get('Mail'));
return $customLogger;
},
controller
<?php
namespace Foo\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Doctrine\ORM\EntityManager;
use MyProject\Proxies\__CG__\OtherProject\Proxies\__CG__\stdClass;
class FooController extends AbstractActionController
{
protected $customLogger;
private function getCustomLogger()
{
if (null === $this->customLogger) {
$this->customLogger = $this->getServiceLocator()->get('Zend\CustomLogger');
}
return $this->customLogger;
}
public function indexAction()
{
$this->getCustomLogger();
$this->customLogger->controllerLog("ENTER IN Foo\Controller\FooController\index", "info");
// .... other code
}
}
Error
Zend\ServiceManager\Exception\ServiceNotCreatedException
File:
/var/www/solutions/mysolution/zend/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:930
Message:
An exception was raised while creating "Zend\CustomLogger"; no instance returned
PHP modules installed
bz2.so curl.so fileinfo.so iconv.so mbstring.so mysqlnd.so pdo_sqlite.so shmop.so sqlite3.so sysvshm.so xmlreader.so xsl.so
calendar.so dom.so ftp.so intl.so mysqlnd_mysqli.so pdo_mysqlnd.so phar.so simplexml.so sysvmsg.so tokenizer.so xml.so zip.so
ctype.so exif.so gettext.so json.so mysqlnd_mysql.so pdo.so posix.so sockets.so sysvsem.so wddx.so xmlwriter.so
Extension enabled in PHP ini
extension=/usr/lib64/php/5.5/modules/php_bz2.so
extension=/usr/lib64/php/5.5/modules/php_curl.so
extension=/usr/lib64/php/5.5/modules/php_fileinfo.so
extension=/usr/lib64/php/5.5/modules/php_gd2.so
extension=/usr/lib64/php/5.5/modules/php_intl.so
extension=/usr/lib64/php/5.5/modules/php_mbstring.so
extension=/usr/lib64/php/5.5/modules/php_mysql.so
extension=/usr/lib64/php/5.5/modules/php_mysqli.so
extension=/usr/lib64/php/5.5/modules/php_openssl.so
extension=/usr/lib64/php/5.5/modules/php_pdo_mysql.so
extension=/usr/lib64/php/5.5/modules/php_soap.so
extension=/usr/lib64/php/5.5/modules/php_xmlrpc.so
extension=/usr/lib64/php/5.5/modules/php_xsl.so

So simple solution... permission on log directory and some others directory are wrong. Restore the correct permissione, user and group on directory (e.g. data/logs, data/cache...)

Related

Insert query works fine on my local but doesn't execute on my live database (Laravel/MySQL)

I have a very simple function that loops through an array and inserts some data into a results table - this works perfectly fine on my local using the very same code. On my local setup (Mac) using Laravel Valet & an MySQL database it hits the function Result::create($data) and inserts this data in the database. However on the live/remote site it never hits the Result::create() within the insertUniqueMatches for some reason.
I have added the db user in the env file and it has been granted all privileges so I cannot understand why this won't insert the entry into the results table. Can anyone explain what I am doing wrong? All migrations have been ran to ensure my local and live db are identical.
P.S i have tried both the $fillable variable with all the relevant items in the array and also with the $guarded as a blank array and the problem persists.
class Result extends Model
{
use HasFactory;
// protected $fillable = ['match_id', 'home_team_id', 'away_team_id', 'home_team_goals', 'away_team_goals', 'outcome', 'match_date', 'properties', 'platform_id'];
protected $guarded = [];
public static function insertUniqueMatches($matches, $platform = null)
{
$inserted = 0;
foreach ($matches as $match) {
// check if existing match already exists in the db, if so don't re-insert this
if (Result::where('match_id', '=', $match['matchId'])->doesntExist()) {
$carbonDate = Carbon::now();
$carbonDate->timestamp($match['timestamp']);
$clubs = collect($match['clubs'])->values();
$data = [
'match_id' => $match['matchId'],
'home_team_id' => $clubs[0]['id'],
'away_team_id' => $clubs[1]['id'],
'home_team_goals' => $clubs[0]['goals'],
'away_team_goals' => $clubs[1]['goals'],
'outcome' => self::getMatchOutcome($clubs[0]),
'match_date' => $carbonDate->format('Y-m-d H:i:s'),
'properties' => json_encode([
'clubs' => $match['clubs'],
'players' => $match['players']
]),
'platform_id' => $platform
];
dump($data); // this shows valid data in the terminal
// this if condition is only reached on my local development but never on live so no inserts happen on the live DB
if (Result::create($data)) {
$inserted++;
dump('inserted matchId: '. $match['matchId']); // never see this on line but always on local
}
}
}
return $inserted;
}
i think better solution for now is you can find the problem.
you could write code into try-catch for more information.
replace this code
try {
Result::create($data);
} catch (\Exception $e) {
dd($e);
}
with:
dump($data); // this shows valid data in the terminal
// this if condition is only reached on my local development but never on live
if (Result::create($data)) {
$inserted++;
dump('inserted matchId: '. $match['matchId']); // never see this on line but always on local
}

Laravel: Store error messages in database

Any one know how to send error messages to database in laravel which generate from app/exceptions/handler.php ?
I need to send what error massages generated in report() method to database.
If you are interested doing this manually, you can do something as following.
Step 1 -
Create a model to store errors that has a DB structure as following.
class Error extends Model
{
protected $fillable = ['user_id' , 'code' , 'file' , 'line' , 'message' , 'trace' ];
}
Step 2
Locate the App/Exceptions/Handler.php file, include Auth, and the Error model you created. and replace the report function with the following code.
public function report(Exception $exception) {
// Checks if a user has logged in to the system, so the error will be recorded with the user id
$userId = 0;
if (Auth::user()) {
$userId = Auth::user()->id;
}
$data = array(
'user_id' => $userId,
'code' => $exception->getCode(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'message' => $exception->getMessage(),
'trace' => $exception->getTraceAsString(),
);
Error::create($data);
parent::report($exception);
}
(I am demonstrating this using laravel 5.6)
Because Laravel uses Monolog for handling logging it seems that writing Monolog Handler would be the cleanest way.
I was able to find something that exists already, please have a look at monolog-mysql package. I did not use it, so I don't know whether it works and if it works well, but it's definitely good starting point.

Yii2 codeception dataFile fixture can't be found

I am trying to run simple test and insert two record in db via fixture dataFile.
What I get is :
[ReflectionException] Class C:\xampp\htdocs\codeception\frontend\tests/_data\user.php does not exist
The file is obviously there. My UserTest.php looks like this:
<?php
class UserTest extends \Codeception\Test\Unit
{
public function _fixtures()
{
return [
'class' => \frontend\tests\fixtures\UserFixture::className(),
'dataFile' => codecept_data_dir() . 'user.php'
];
}
public function testValidation()
{
$user = new \common\models\User();
$user->setUsername(null);
$this->assertFalse($user->validate(['username']));
$user->setUsername('aaaaaaaaaaaaaaaaaaaaaaaaaa');
$this->assertFalse($user->validate(['username']));
$user->setUsername('toma');
$this->assertTrue($user->validate(['username']));
}
public function testIfUserExist()
{
$this->tester->seeRecord('user', ['name' => 'Toma']);
}
}
I saw the linux like forward slash in the error but don't know how to change it. Not sure if this is the problem because I had the same path with some images and it was fine then. What can cause this ? Thank you!
You're using seeRecord() in a wrong way. First argument needs to by class name, including namespace, so you should use it like this:
$this->tester->seeRecord(\frontend\models\User::class, ['name' => 'Toma']);

How to use the global.php/local.php configs in the getConfig() of a module in a Zend Framework 2 application?

In a ZF2 application I have some cofigs, that: 1. need to be different dependening on the environment; 2. are specific for a concrete module. I'm curently using it like here described:
global.php & local.php
return array(
...
'modules' => array(
'Cache' => array(
'ttl' => 1, // 1 second
)
)
...
);
Module class
Module {
...
public function getServiceConfig() {
try {
return array (
'factories' => array(
'Zend\Cache\Adapter\MemcachedOptions' => function ($serviceManager) {
return new MemcachedOptions(array(
'ttl' => $this->getConfig()['modules']['Cache']['ttl'],
...
));
},
...
)
);
}
...
}
...
}
It's working fine, but I believe, that the module specific settings should be accessed over one central place in the module -- the getConfig() method of the Module class. Like this:
class Module {
public function getConfig() {
$moduleConfig = include __DIR__ . '/config/module.config.php';
$application = $this->getApplicationSomehow(); // <-- how?
$applicationModuleConfig = $application->getConfig()['modules'][__NAMESPACE__];
$config = array_merge($moduleConfig, $applicationModuleConfig);
return $config;
}
...
public function getServiceConfig() {
try {
return array (
'factories' => array(
'Zend\Cache\Adapter\MemcachedOptions' => function ($serviceManager) {
return new MemcachedOptions(array(
'ttl' => $serviceManager->get('Config')['modules']['Cache']['ttl'],
...
));
},
...
)
);
}
...
}
...
}
The problem is, that I don't get, how to access the global.php/local.php configs in the getConfig() of a module. How can I do it?
Every single configuration of every single loaded Module will be merged into one single config. Namely this would be:
$serviceManager->get('config');
The reason behind (global|local).config.php is merely for usage purpose. Global configuration files should always be deployed. Local configuration files however should only be deployed as distributionables, alias local.config.php.dist.
Distributionals will not be loaded, no matter where they are places. However common notion of ZF2 is to copy the distributionables into the /config/autoload-directory of the ZF2 Application and rename them to local.config.php
One example:
// YourModule/config/module.config.php
return array(
'key' => 1337
);
// YourModule/config/local.yourmodule.php.dist
return array(
'key' => 7331
);
Now when you publish / deploy your application, only module.config.php will be used. If someone wants to change the configuration of your Module, they would never touch module.config.php, as this file would constantly be overwritten when your module will be updated.
However what people can do is to copy:
YourModule/config/local.yourmodule.php.dist
to
/config/autoload/local.yourmodule.php
And change the config values inside this local configuration.
To understand:
You should always configure your module as best as possible for a LIVE-Scenario.
If you have environment-specific needs, overwrite this config using a local-config
local configs are never deployed automatically, this is a manual task needing to be done from inside the environment itself
Hope this got a little more clear
Ultimately:
configure your module for a LIVE-Scenario
On your development machine create a /config/autoload/mymodule.local.php and overwrite your ttl with it's development value
LoadOrder:
The last interesting part, which i have completely forgotten about, would be the load order of the configuration files. As all files are merged, this is important to note!
First to load is /config/application.config.php
Second to load would be each Modules /modules/{module}/config/module.config.php *
Last but not least the autoloadable files will be loaded /config/autoload/{filename}.php
asterix It is actually NOT module.config.php which is called, but rather the Module-classes configuration functions. Mainly these are:
getConfig()
getServiceConfig()
getViewHelperConfig()
ultimately everything under Zend\ModuleManager\Feature\{feature}ProviderInterface
If i understand this part of the ConfigListener correctly, then getConfig() will be called first and all of the specialiced {feature}ProviderInterfaces will overwrite the data of getConfig(), but don't take this for granted, it would need a check!
You're not supposed to access other Modules setting in your Module#getConfig(). If you rely on other configuration, that CAN ONLY BE for service purposes. Ergo you'd rely on Module#getServiceConfig() and inside the factories you do have access to the ServiceManagerand access your configs with $serviceManager->get('config');. (see Sam's comment)
The loading order of the configs is by default:
/config/application.config.php, that is the initial config file; not for module configs; here is the filename pattern for the config files to load defined ('config_glob_paths' => array('config/autoload/{,*.}{global,local}.php')).
{ModuleNamespace}\Module#getConfig() (e.g. Cache\Module#getConfig()), that by convention should load its /module/{ModuleNamespace}/config/module.config.php;
/config/autoload/global.php, that should not contain any module specific configs (see below);
/config/autoload/local.php, that contains environment specific settings also should not contain any module specific configs (see below); it should not versioned/deployed;
/config/autoload/{ModuleNamespaceLowerCased}.local.php (e.g. cache.local.php), that contains only the module AND environment specific settings and should not be versioned/;
For the Cache module above there can be following config files:
/module/Cache/config/module.config.php -- a complete set of module configs; loaded by Cache\Module#getConfig()
/module/Cache/config/cache.local.php.dist -- an example for /config/autoload/cache.local.php
/config/autoload/cache.local.php -- environment specific module configs
The setting ttl can be accessed from any place, where one has access to the Service Locator. For example in factory methods of Cache\Module#getServiceConfig()
class Module {
public function getConfig() {
$moduleConfig = include __DIR__ . '/config/module.config.php';
$application = $this->getApplicationSomehow(); // <-- how?
$applicationModuleConfig = $application->getConfig()['modules'][__NAMESPACE__];
$config = array_merge($moduleConfig, $applicationModuleConfig);
return $config;
}
...
public function getServiceConfig() {
try {
return array (
'factories' => array(
'Zend\Cache\Adapter\MemcachedOptions' => function ($serviceManager) {
return new MemcachedOptions(array(
'ttl' => $serviceManager->get('Config')['ttl'],
...
));
},
...
)
);
}
...
}
...
}
For futher information about how configs are managed in ZF2 see Sam's answer and blog article.

Symfony 2 Console command for creating custom Database

I am working on a Symfony 2 project where each user have his own database. In my config.yml file I have a doctrine:dbal:orm set for a client but no connection properties because they are set at runtime and referenced by all users. I.e I only have one default dbal connection and two orm-connection and the amount of users is unlimited.
This works fine but I need to create the database and schema when the user is registered (FOS UserBundle). In the extended userbundle controller I can put my own logic.
The problem is that I cannot run the 'php app/console doctrine:database:create' since there are not parameters set for the new user.
Is there any way of specifying a custom database parameter to the console commands?
I could probably get around this by some very ugly mysql commands but I'd rather not.
Many thanks in advance!
You can create your own command using the code below as an outline:
namespace Doctrine\Bundle\DoctrineBundle\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Doctrine\DBAL\DriverManager;
class CreateDatabaseDoctrineCommandDynamically extends DoctrineCommand
{
protected function configure()
{
$this
->setName('doctrine:database:createdynamic')
->setDescription('Creates the configured databases');
}
/**
* {#inheritDoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
/***
** Edit this part below to get the database configuration however you want
**/
$connectionFactory = $this->container->get('doctrine.dbal.connection_factory');
$connection = $connectionFactory->createConnection(array(
'driver' => 'pdo_mysql',
'user' => 'root',
'password' => '',
'host' => 'localhost',
'dbname' => 'foo_database',
));
$params = $connection->getParams();
$name = isset($params['path']) ? $params['path'] : $params['dbname'];
unset($params['dbname']);
$tmpConnection = DriverManager::getConnection($params);
// Only quote if we don't have a path
if (!isset($params['path'])) {
$name = $tmpConnection->getDatabasePlatform()->quoteSingleIdentifier($name);
}
$error = false;
try {
$tmpConnection->getSchemaManager()->createDatabase($name);
$output->writeln(sprintf('<info>Created database for connection named <comment>%s</comment></info>', $name));
} catch (\Exception $e) {
$output->writeln(sprintf('<error>Could not create database for connection named <comment>%s</comment></error>', $name));
$output->writeln(sprintf('<error>%s</error>', $e->getMessage()));
$error = true;
}
$tmpConnection->close();
return $error ? 1 : 0;
}
}