Missing 'className' parameter - phalcon

I am working on a old project change request and the project was developed in phalcon 1.2.6 verson. When I am trying to execute the application the application returns an error. After doing some R&D I found that the system did not find the config key from the $di object.
When I am trying to print the $di object it's printing properly with key config. But when trying to access the config key, I am unable to access it.
When the system tries to execute the below code, it throws an exception.
$di = \Phalcon\DI::getDefault();
print_r($di['config']);
I am getting the below error.
Invalid service definition. Missing 'className' parameter
#0 [internal function]: Phalcon\DI\Service\Builder->build(Object(Phalcon\DI\FactoryDefault), Array, NULL)
#1 [internal function]: Phalcon\DI\Service->resolve(NULL, Object(Phalcon\DI\FactoryDefault))
#2 [internal function]: Phalcon\DI->get('config', NULL)
#3 /var/www/sites/mfs_merged/apps/api/Module.php(44): Phalcon\DI->offsetGet('config')
#4 [internal function]: AppServer\Api\Module->registerServices(Object(Phalcon\DI\FactoryDefault))
#5 /var/www/sites/mfs_merged/public/index.php(64): Phalcon\Mvc\Application->handle()
#6 {main}
below is a part of my $di object
Phalcon\DI\FactoryDefault Object
(
[_services:protected] => Array
(
[...] => Phalcon\DI\Service Object
(....)
[config] => Phalcon\DI\Service Object
(
[_name:protected] => config
[_definition:protected] => Array
(
[database] => Array
(
[adapter] => Oracle
[host] => 172.20.3.228
[username] => XXXXX
[password] => XXXXXXX
[schema] => XE
[dbname] => (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 172.20.3.228)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XE)))
)
[memcache] => Array
(
[lifetime] => 3600
[host] => localhost
[port] => 11211
[persistent] =>
)
[soapClient] => Array
(
[connectionTimeout] => 60
[exceptions] =>
[trace] => 1
[cache] => 0
[useSoapHeader] => 1
[soapHeader] => Array
(
[username] => XXXXX
[password] => XXXXXX
)
)
[SMSCodesLogPath] => /var/www/sites/mfs_merged/config/TZ/../../public/files/_SMSTokens/tokens_TZ.log
)
[_shared:protected] => 1
[_sharedInstance:protected] =>
)
)
[_sharedInstances:protected] => Array
(.....)
[_freshInstance:protected] => 1
)

I faced the same issue with you. and I found that Phalcon DI container use array for Constructor Injection. So if you set an array into Phalcon DI container, it understands that you want to set an object by using Constructor Injection and it requires "className" definition. You can check this at Constructor Injection section at https://docs.phalconphp.com/3.4/en/di.
Example of constructor injection in the document:
$di->set(
'response',
[
'className' => 'Phalcon\Http\Response'
]
);
$di->set(
'someComponent',
[
'className' => 'SomeApp\SomeComponent',
'arguments' => [
[
'type' => 'service',
'name' => 'response',
],
[
'type' => 'parameter',
'value' => true,
],
]
]
);
MY SOLUTION:
Suppose that I want to set this config array ['key' => 'value'] into DI.
I create MyConfigFactory class, which has function build to return ['key' => 'value'].
I inject my config as below:
$di->set('myConfigFactory', new MyConfigFactory());
$di->set('config', function () use ($di) {
return $di->get('myConfigFactory')->build();
});
Good luck.

Related

Cakephp 4 save delete auto_increment

I'm doing cakephp4 controller test with phpUnit but when I call save my id auto_increment disapear.
My table before save():
Image before save
The test:
public function testAdd(): void
{
$this->session([
'Auth' => [
'id' => 1,
'DNI_CIF' => '22175395Z',
'name' => 'Prueba',
'lastname' => 'Prueba Prueba',
'username' => 'Pruebatesting',
'password' => 'prueba',
'email' => 'prueba#gmail.com',
'phone' => '639087621',
'role' => 'admin',
'addres_id' => 1
]
]);
$this->get('animal/add');
$this->assertResponseOk();
$data=[
'id' => 1,
'name' => 'AñadirAnimal',
'image' => '',
'specie' => 'dog',
'chip' => 'no',
'sex' => 'intact_male',
'race' => 'cat',
'age' => 1,
'information' => 'Es un animal.',
'state' => 'sick',
'animal_shelter' => [
'id' => 1,
'start_date' => '2022-11-03 10:47:38',
'end_date' => '2022-11-03 10:47:38',
'user_id' => 1,
'animal_id' => 1
]
];
$this->enableCsrfToken();
$this->post('animal/add',$data);
$this->assertResponseOk();
}
The controller:
public function add()
{
$animal = $this->Animal->newEmptyEntity();
if ($this->request->is('post')) {
$animal = $this->Animal->patchEntity($animal, $this->request->getData());
if(!$animal->getErrors){
$image = $this->request->getData('image_file');
if($image !=NULL){
$name = $image->getClientFilename();
}
if( !is_dir(WWW_ROOT.'img'.DS.'animal-img') ){
mkdir(WWW_ROOT.'img'.DS.'animal-img',0775);
if($name){
$targetPath = WWW_ROOT.'img'.DS.'animal-img'.DS.$name;
$image->moveTo($targetPath);
$animal->image = 'animal-img/'.$name;
}
}
if ($this->Animal->save($animal)) {
$this->Flash->success(__('El animal se ha añadido.'));
return $this->redirect(['action' => 'index']);
}
}
$this->Flash->error(__('El animal no se ha podido añadir, por favor intentalo de nuevo'));
}
$allUsers = $this->getTableLocator()->get('User');
$user = $allUsers->find('list', ['limit' => 200])->all();
$this->set(compact('animal','user'));
}
My table after:
Image after save
The error:
1) App\Test\TestCase\Controller\AnimalControllerTest::testAdd
Possibly related to PDOException: "SQLSTATE[HY000]: General error: 1364 Field 'id' doesn't have a default value"
…
Failed asserting that 500 is between 200 and 204.
I don't know why this is happening or how to know the reason. In the app the controller works fine. Data in the app:
Data in app
Data in test:
Data in test
I hope someone can help me, I don't know what to try anymore or how to know where the problem is...
I tried to look at the data but it doesn't apear to have any errors so I don't know where the error can be.
It was that the sql file used in the bootstrap didn't have the autoincrement value.

Laravel queue:work not behaving same as queue:listen

<?php
namespace App\Notifications;
use Illuminate\Notifications\Channels\MailChannel;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Facades\Config;
class DynamicEmailChannel extends MailChannel
{
public function send($notifiable, Notification $notification)
{
$service = $notification->service;
$customConfig = [];
$from = [];
if ($service->sender_email && $service->sender_password) {
$customConfig = [
'transport' => 'smtp',
'host' => 'smtp.googlemail.com',
'port' => 587,
'encryption' => 'tls',
'username' => $service->sender_email,
'password' => $service->sender_password,
'timeout' => null,
'auth_mode' => null,
];
$from = [
'address' => $service->sender_email,
'name' => $service->title
];
} else {
$customConfig = [
'transport' => 'smtp',
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
'port' => env('MAIL_PORT', 587),
'encryption' => env('MAIL_ENCRYPTION', 'tls'),
'username' => env('MAIL_USERNAME'),
'password' => env('MAIL_PASSWORD'),
'timeout' => null,
'auth_mode' => null,
];
$from = [
'address' => env('MAIL_FROM_ADDRESS', 'hello#example.com'),
'name' => env('MAIL_FROM_NAME', 'Example')
];
}
Config::set('mail.mailers.smtp', $customConfig);
Config::set('mail.from', $from);
app()->forgetInstance('mail.manager');
parent::send($notifiable, $notification);
}
}
this program works when run through php artisan queue:listen but the app()->forgetInstance('mail.manager'); runs only once when run through php artisan queue:work. How do i make it behave as with queue:listen?
I am trying to send mail notifications through credentials saved in database.
If i am not wrong, if i delete the 'mail.manager' serviceInstance, it will create new one when called with latest config. it works the same way for queue:listen but not for queue:work. what am i missing, or not understanding here.
After doing some digging replacing app()->forgetInstance('mail.manager'); with Mail::purge('smtp'); solved the issue.

zfcuser + doctrine custom user entity

I'm working on a project with zf2, and the zfcuser module with doctrine. I have created a custom user module that extends zfcuser, also a custom entity for the user table, and make all the necessary changes for the integration. But my problem is when trying to authenticate myself, I get this error:
An alias "Zend\Db\Adapter\Adapter" was requested but no service could be found.
This happens when zfcuser_user_mapper attempts to change the adapter.
Note: I am not very clear why I need to use the Zend \ Db \ Adapter \ Adapter, since I am working with doctrine.
This is the code in the module.php of the custom user module.
public function getServiceConfig() {
return [
'aliases' => array(
'zfcuser_zend_db_adapter' => 'Zend\Db\Adapter\Adapter',
),
'factories' => [
'usuario_login_form' => 'Usuario\Factory\Form\Login',
'usuario_registro_form' => 'Usuario\Factory\Form\Register',
'usuario_user_service' => 'Usuario\Factory\Service\UserFactory',
//'usuario_user_mapper' => 'Usuario\Factory\Mapper\User',
'usuario_auth_service' => 'Usuario\Factory\AuthenticationService',
'Usuario\Authentication\Adapter\Db' => 'Usuario\Factory\Authentication\Adapter\DbFactory',
'Usuario\Authentication\Storage\Db' => 'Usuario\Factory\Authentication\Storage\DbFactory',
//'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\Adapter',
'usuario_user_mapper' => function ($sm) {
$mapper = new Mapper\User();
$mapper->setDbAdapter($sm->get('zfcuser_zend_db_adapter'));
$mapper->setEntityPrototype(new ORM\Entity\Usuarios());
$mapper->setHydrator(new \ZfcUser\Mapper\UserHydrator());
return $mapper;
},
]
];
}
This is my global.php file
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'driverClass' => 'Doctrine\DBAL\Driver\PDOMySql\Driver',
'params' => array(
'host' => 'localhost',
'port' => '3306',
'user' => 'root',
'password' => 'toor',
'dbname' => 'deporte',
)
)
)
),
);
This is my module.config.php file:
'controllers' => array(
),
'doctrine' => array(
'driver' => array(
// overriding zfc-user-doctrine-orm's config
'usuario_entity' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'paths' => __DIR__ . '/../src/Usuario/ORM/Entity',
),
'orm_default' => array(
'drivers' => array(
'Usuario\ORM\Entity' => 'usuario_entity',
),
),
),
),
'zfcuser' => array(
'auth_adapters' => array(100 => 'Usuario\Authentication\Adapter\Db'),
// telling ZfcUser to use our own class
'user_entity_class' => 'Usuario\ORM\Entity\Usuarios',
// telling ZfcUserDoctrineORM to skip the entities it defines
'enable_default_entities' => false,
),
I thank you for the help, I have already been with this error for days. Thank you very much, and excuse my English.
If you want to change the Entity and want to use your then use following steps:
if the zfcuser.global.php file which is placed in config/autoload folder (if not then you can copy if from zfcuser module.
In this global file search for "user_entity_class" key and define your own entity class.By default it uses
'user_entity_class' => 'ZfcUser\Entity\User',
Like I am using it for Employee entity
'user_entity_class' => 'Employee\Entity\Employee',
In this entity you need to implement UserInterface.
use ZfcUser\Entity\UserInterface;
/**
* Employee
*
* #ORM\Table(name="employee")
* #ORM\Entity(repositoryClass="Employee\Repository\EmployeeRepository")
*/
class Employee implements UserInterface {
}
If you want to override db adapter then you need to do following steps:
'service_manager' => array(
'invokables' => array(
'ZfcUser\Authentication\Adapter\Db' => 'Employee\Authentication\Adapter\Db',
),
),
In this file you need to extend and implements.
namespace Employee\Authentication\Adapter;
use InvalidArgumentException;
use Zend\Authentication\Result as AuthenticationResult;
use Zend\Crypt\Password\Bcrypt;
use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\ServiceManagerAwareInterface;
use Zend\Session\Container as SessionContainer;
use ZfcUser\Authentication\Adapter\AdapterChainEvent as AuthenticationEvent;
use ZfcUser\Entity\UserInterface as UserEntity;
use ZfcUser\Mapper\HydratorInterface as Hydrator;
use ZfcUser\Mapper\UserInterface as UserMapper;
use ZfcUser\Authentication\Adapter\AbstractAdapter;
use ZfcUser\Options\AuthenticationOptionsInterface as AuthenticationOptions;
class Db extends AbstractAdapter implements ServiceManagerAwareInterface
{
}
For more information you can follow zfcuser wiki here:
https://github.com/ZF-Commons/ZfcUser/wiki

Zend Framework 2 + Doctrine 2 and Authentication Service

It was successfully working before I changed the authentication service name from 'orm_default' to 'admin', and it is necessary since I have more modules which uses more authentication services.
The problem is I'm getting the following error:
Fatal error: Uncaught exception 'Zend\ServiceManager\Exception\ServiceNotFoundException' with message 'Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for doctrine.authenticationservice.admin'
My module.config.php
'doctrine' => array
(
'driver' => array
(
__NAMESPACE__ . '_driver' => array
(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(__DIR__ . '/../src/' . __NAMESPACE__ . '/Entity')
),
'orm_default' => array
(
'drivers' => array
(
__NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver'
),
)
),
'authentication' => array
(
'admin' => array
(
'object_manager' => 'Doctrine\ORM\EntityManager',
'identity_class' => __NAMESPACE__ . '\Entity\User',
'identity_property' => 'email',
'credential_property' => 'password',
'credentialCallable' => __NAMESPACE__ . '\Model\User::hashPassword'
),
),
),
My Module.php
public function getServiceConfig()
{
return array
(
'factories' => array
(
'Admin\Auth' => function($sm)
{
return $sm->get('doctrine.authenticationservice.admin');
},
'Admin\Form\Auth\Login' => function($sm)
{
return new Form\Auth\Login();
},
),
);
}
It was confirmed as a bug: https://github.com/doctrine/DoctrineORMModule/issues/291
According to a comment in a doctrine module source file it plans to be fixed in 1.0. In this meantime you can it in your any module.config.php file of your application like this:
'authentication' =>
[
'application' =>
[
'object_manager' => 'Doctrine\ORM\EntityManager',
'identity_class' => 'Application\Entity\Customer',
'identity_property' => 'email',
'credential_property' => 'password',
'credentialCallable' => 'Application\Entity\Customer::hashPassword'
],
],
'authenticationadapter' =>
[
'application' => true,
],
'authenticationstorage' =>
[
'application' => true,
],
'authenticationservice' =>
[
'application' => true,
]
I had exactly same problem when i was working on my project. After working my *ss out for two nights, i solved the problem by simply re-installing the doctrine-orm-module after reading https://github.com/doctrine/DoctrineORMModule, "Registered Service names" section. This simply means doctrine orm module wasn't properly installed, or wasn't installed.

ZF2: create url aliases in router

I'm new to Zend Framework 2 and i want to learn this framework. I want to create url aliases in router.
For example, I have defined something like this in module.config.php
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
'node' => array(
'type' => 'Application\Controller\AliasSegment',
'options' => array(
'route' => '/node[/:id]',
'constraints' => array(
'id' => '[0-9]+'
),
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
'id' => '0'
),
),
'may_terminate' => true,
),
),
),
When i type www.myapp.local/node/1 it routes to the default action in default controller of my application. What i want is a router extension that can handle aliases for url paths. For example:
www.myapp.local/node/1 = www.myapp.local/aboutus
www.myapp.local/node/2 = www.myapp.local/company/gallery
I know that it was possible in ZF. Here is a link to tutorial how to achieve this in ZF:
friendly urls
I know that this is in Polish but code is self-explanatory i think :)
The idea is to use url helper to assembly valid url using aliases or normal segments (node/[:id])
I've already created AliasSegment class in my Application\Controller folder but it shows me an error:
Fatal error: Uncaught exception 'Zend\ServiceManager\Exception\ServiceNotFoundException' with message 'Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Application\Controller\AliasSegment' in C:\xampp\htdocs\industengine\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:450 Stack trace: #0
My AliasSegment class (incomplete):
<?php
namespace Zend\Mvc\Router\Http;
use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
class AliasSegment extends Segment
{
public function match(Request $request, $pathOffset = null)
{
}
}
I was looking for an answer for hours and i couldnt find anything. Please tell me at least what I'm doing wrong, where to insert a code or maybe You know better sollution?
I'm not looking for ready application. I want to learn something but i would appreciate if You can tell me an answer in details :)
Thanks in advance and sorry for my English :)
EDITED:
My custom router is working now. At this moment aliases are hardcoded but it works.
My AliasSegment class looks now:
<?php
namespace Application\Controller;
use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http;
class AliasSegment extends \Zend\Mvc\Router\Http\Segment
{
public function match(Request $request, $pathOffset = null)
{
$uri = $request->getUri();
$path = $uri->getPath();
//sample logic here
//for /about/gallery uri set node id to 1
//todo: get action, controller and module from navigation
if($path == '/about/gallery'){
$uri->setPath('/node/1');
$request->setUri($uri);
}
return parent::match($request, $pathOffset);
}
protected function buildPath(array $parts, array $mergedParams, $isOptional, $hasChild)
{
if(isset($mergedParams['link'])){
return $mergedParams['link'];
}
return parent::buildPath($parts, $mergedParams, $isOptional, $hasChild);
}
}
In this case /about/gallery is an alias to /node/1. Both adresses are correct. The buildPath function returns alias path correctly. Well, I hope this would be usefull for somebody :)
However i want to setup it in Zend_Navigation with additional parameter named 'link'.
I've done 50% of what i want to achieve however now I have problem to get Zend_Navigation from my router. I don't know how to pass it. I guess it should be something like this:
$sm = $this->getServiceLocator();
$auth = $sm->get('Navigation');
It works in my IndexController but doesnt work in my AliasSegment. I need to find in navigation array nodes with 'link' parameter.
EDIT
I've found solution. The answer is below.
unable to fetch or create an instance for Application\Controller\AliasSegment
if this is controller then I would expect in module.config.php to have:
'controllers' => array(
'invokables' => array(
'\Application\Controller\AliasSegment' => '\Application\Controller\AliasSegment',
)
),
also namespace of your class looks a bit weird:
namespace Zend\Mvc\Router\Http;
what about:
namespace Application\Controller;
OK, I've made it. The important thing for this Thread:
ZF2: How to get Zend\Navigation inside custom route?.
You can use any segment type route. But this may need a little modifications to match function.
If navigation's single page will have 'link' param, the url will be converted to 'link' string but other params will stay behind it. Just think of it as an overlay for default URI of current route.
I had to modify my custom route class a little bit. First of all, i had to change its namespace to Application\Router. Here is a full class:
// EDIT - file within ModuleName/src/Router/Alias.php
namespace Application\Router;
use Traversable;
use Zend\Mvc\Router\Exception;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Mvc\Router\Http;
class Alias extends Http\Segment
{
private static $_navigation = null;
public function match(Request $request, $pathOffset = null)
{
$uri = $request->getUri();
$path = $uri->getPath();
$items = self::$_navigation->findAllBy('route', 'node');
$params = null;
if($items != null){
$t = sizeof($items);
for ($i=0; $i < $t; $i++) {
$item = $items[$i];
$params = $item->getParams();
if (isset($params['link']) && $params['link']==$path){
$uri->setPath('/'.$item->getRoute().'/'.$params['id']);
$request->setUri($uri);
break;
}
}
}
return parent::match($request, $pathOffset);
}
public function setNavigation($navigation){
self::$_navigation = $navigation;
}
protected function buildPath(array $parts,
array $mergedParams, $isOptional, $hasChild)
{
if(isset($mergedParams['link'])){
return $mergedParams['link'];
}
return parent::buildPath($parts, $mergedParams,
$isOptional, $hasChild);
}
}
here is sample part of module.config.php:
'navigation' => array(
// The DefaultNavigationFactory we configured in (1) uses 'default' as the sitemap key
'default' => array(
// And finally, here is where we define our page hierarchy
'account' => array(
'label' => 'Account',
'route' => 'node',
'params' => array(
'id' => '2',
),
'pages' => array(
'home' => array(
'label' => 'Dashboard',
'route' => 'node',
'params' => array(
'id' => '8',
'link' => '/about/gallery'
),
),
'login' => array(
'label' => 'Sign In',
'route' => 'node',
'params' => array(
'id' => '6',
'link' => '/signin'
),
),
'logout' => array(
'label' => 'Sign Out',
'route' => 'node',
'params' => array(
'id' => '3',
),
),
),
),
),
),
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
'node' => array(
'type' => 'Application\Router\Alias',
'options' => array(
'route' => '/node[/:id]',
'constraints' => array(
'id' => '[0-9]+'
),
'defaults' => array(
'__NAMESPACE__' => 'Application\Controller',
'controller' => 'Index',
'action' => 'index',
'id' => '0'
),
),
'may_terminate' => true,
),
),
),
If it is just for routes like /about and /about/galery then you can simply use literal routes with child routes
'about' => array(
'type' => 'literal',
'options' => array(
'route' => '/about',
'defaults' => array(
'controller' => 'module-controller-about',
'action' => 'index'
)
),
'may_terminate' => true,
'child_routes' => array(
'galery' => array(
'type' => 'literal',
'options' => array(
'route' => '/galery',
'defaults' => array(
'controller' => 'module-controller-galery'
)
)
)
)
)
When it comes to URLs like /blog/1-my-great-seo-title you probably have to set-up a Regex route (which is the slowest, literals are fastest).
Maybe check out DASPRiDs Slides from his Router Presentation