Laminas (ex Zend Framework 3) class not found resolving factory - service

I'm lost with this problem...
I have a module Tables with a factory for my final class "Entreprise"
so in module/Tables/config/module.config.php
<?php
namespace \Tables\Service\Factory;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Tables\Service\Entreprise;
class EntrepriseFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
DIE('FACTORY ENTREPRISE NOT REACHED ... :-( ');
$entreprise = new Entreprise();
return $enteprise;
}
}
module/Tables/Modules.php
<?php
namespace Tables;
class Module
{
public function getServiceConfig()
{
return [
'factories' => [
'EntrepriseTableGateway' => function ($sm)
{
...
...
$e=$sm->get(\Service\Entreprise::class);
// Here is the problem
// \Service\Entreprise is resolved
// as Tables\Service\Factory\EntrepriseFactory as expected
// but Tables\Service\Factory\EntrepriseFactory is not found...
here is the factory flow
----module/Tables/src/Tables/Service
contains Entreprise.php (but the problem is not here at this time)
----/module/Tables/config/module.config.php
<?php
return array(
'service_manager' => [
// the resolution works...
// but the final class is not found...
'invokables' => [
Service\Entreprise::class => \Tables\Service\Factory\EntrepriseFactory::class,
]
]
);
module/Tables/src/Tables/Service/Factory.php
<?php
namespace \Tables\Service\Factory;
use Interop\Container\ContainerInterface;
use Laminas\ServiceManager\Factory\FactoryInterface;
use Tables\Service\Entreprise;
class EntrepriseFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
DIE('FACTORY ENTREPRISE NOT REACHED !!!');
$entreprise = new Entreprise();
return $entreprise;
}
}
in composer.json (composer dump-autoload done)
...
"autoload": {
"psr-4": {
"Application\\": "module/Application/src/",
"Tfirst\\": "module/Tfirst/src/",
"Tables\\": "module/Tables/src/"
}
},
...
and in root config in SERVER/config/modules.config.php
...
return [
'Laminas\Db',
'Laminas\Di',
'Laminas\Mvc\Plugin\FilePrg',
'Laminas\Mvc\Plugin\FlashMessenger',
'Laminas\Mvc\Plugin\Identity',
'Laminas\Mvc\Plugin\Prg',
'Laminas\Session',
'Laminas\Mvc\I18n',
'Laminas\Mvc\Console',
'Laminas\Form',
'Laminas\Hydrator',
'Laminas\InputFilter',
'Laminas\Filter',
'Laminas\I18n',
'Laminas\Cache',
'Laminas\Router',
'Laminas\Validator',
'Application',
'Tables',
'Tfirst',
......
And the error dump
Error
File:
/home/vagrant/Code/yeting/SERVER/vendor/laminas/laminas-servicemanager/src/Factory/InvokableFactory.php:31
Message:
Class 'Tables\Service\Factory\EntrepriseFactory' not found
Stack trace:
#0 /home/vagrant/Code/yeting/SERVER/vendor/laminas/laminas-servicemanager/src/ServiceManager.php(765): Laminas\ServiceManager\Factory\InvokableFactory->__invoke()
#1 /home/vagrant/Code/yeting/SERVER/vendor/laminas/laminas-servicemanager/src/ServiceManager.php(201): Laminas\ServiceManager\ServiceManager->doCreate()
#2 /home/vagrant/Code/yeting/SERVER/module/Tables/src/Module.php(246): Laminas\ServiceManager\ServiceManager->get()
... any advice ?

ok... I found my mistake...
Actually, I mixed old school zend 2 directory structure with new Zend 3 tutorial (and now Laminas) , so the namespaces were wrong.
before correction : My structure directory was:
(ie for model : ) modules/Tables/src/Tables/Model
the new structure is
(ie for model : ) modules/Tables/src/Model
idem for Factory, etc...
There are always errors, but that's another problem ...
I close the question.

Related

Sysmfony 4.4 - Testing form with 'contraints' in options of TimeType generate an UndefinedOptionsException

I made a form in Symfony 4.4 with a TimeType field defined like this :
$builder
->add('planned_start', TimeType::class, [
'widget' => 'single_text',
'empty_data' => '',
'constraints' => [
new NotBlank([
'message' => 'worksheet.worker.planned_start.required_error'
])
]
])
Functional tests of my controller work perfectly and return the defined error if no valid is given.
But,when I'm testing the form directly, I get the following exeception like I can't put any constraint on the TimeType field
Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException: An error has occurred resolving the options of the form "Symfony\Component\Form\Extension\Core\Type\TimeType": The option "constraints" does not exist. Defined options are: "action",
"allow_file_upload", "attr", "attr_translation_parameters", "auto_initialize", "block_name", "block_prefix", "by_reference", "choice_translation_domain", "compound", "data", "data_class", "disabled", "empty_data", "error_bubbling", "help",
"help_attr", "help_html", "help_translation_parameters", "hours", "html5", "inherit_data", "input", "input_format", "label", "label_attr", "label_format", "label_translation_parameters", "mapped", "method", "minutes", "model_timezone", "placeholder",
"post_max_size_message", "property_path", "reference_date", "required", "row_attr", "seconds", "translation_domain", "trim", "upload_max_size_message", "view_timezone", "widget", "with_minutes", "with_seconds".
/var/www/vendor/symfony/form/ResolvedFormType.php:99
/var/www/vendor/symfony/form/FormFactory.php:76
/var/www/vendor/symfony/form/FormBuilder.php:94
/var/www/vendor/symfony/form/FormBuilder.php:244
/var/www/vendor/symfony/form/FormBuilder.php:195
/var/www/vendor/symfony/form/FormFactory.php:30
/var/www/tests/Form/WorksheetWorkerFormTypeTest.php:39
Here is how I test the form :
<?php
namespace App\Tests\Form\Type;
use App\Form\Type\TestedType;
use App\Form\WorksheetWorkerFormType;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\Form\PreloadedExtension;
use Symfony\Component\Form\Test\TypeTestCase;
// ...
class WorksheetWorkerFormTypeTest extends TypeTestCase
{
private $objectManager;
protected function setUp()
{
// mock any dependencies
$this->objectManager = $this->createMock(ObjectManager::class);
parent::setUp();
}
protected function getExtensions()
{
// create a type instance with the mocked dependencies
$type = new WorksheetWorkerFormType($this->objectManager);
return [
// register the type instances with the PreloadedExtension
new PreloadedExtension([$type], []),
];
}
public function testMinimal()
{
$form = $this->factory->create(WorksheetWorkerFormType::class);
$form->submit([
'planned_start' => '08:00',
'planned_end' => '16:00'
]);
$this->assertTrue($form->isValid());
}
}
Any Idea ?
Thanks

How to add functions in entity manager configuration doctrine in zend framework 3

I have currently a controller and a controller factory
AbcControllerFactory
public function __invoke(ContainerInterface $container, $requestedName, array $options = null){
$entityManager = $container->get("doctrine.entitymanager.orm_default");
return new AbcController($entityManager);
}
And AbcController
private $entityManager;
public function __construct($entityManager){
$this->entityManager = $entityManager;
}
I am trying to use this doctrine library
doctrine library for json functions
but the only issue is I'm stuck in adding these functions
$config = new \Doctrine\ORM\Configuration();
$config->addCustomStringFunction(DqlFunctions\JsonExtract::FUNCTION_NAME, DqlFunctions\JsonExtract::class);
$config->addCustomStringFunction(DqlFunctions\JsonSearch::FUNCTION_NAME, DqlFunctions\JsonSearch::class);
I'm fairly new to this doctrine bit. Can anyone help how should I add these function in the existing entity manager configuration
This is my local.php file where all information is stored
return [
"doctrine" => [
"connection" => [
"orm_default" => [
"driverClass" => PDOMySqlDriver::class,
"params" => [
"driver" => "pdo_mysql",
"dsn" => "mysql:dbname=abc;host=localhost;charset=utf8",
"host" => "localhost",
"user" => "root",
"password" => "",
"dbname" => "abc",
]
],
],
],
];
Okay this is a bit sluggish from me. However, I found out you could add function like this in controller:
$this->entityManager->getConfiguration()->addCustomStringFunction(DqlFunctions\JsonExtract::FUNCTION_NAME, DqlFunctions\JsonExtract::class);
$this->entityManager->getConfiguration()->addCustomStringFunction(DqlFunctions\JsonSearch::FUNCTION_NAME, DqlFunctions\JsonSearch::class);

Scanning translatable strings in zend 3 forms with Poedit

Zend 3 translates form labels automatically.
If forms are created using array specification, how is it possible to scan translatable form element strings with Poedit?
How to add translator->translate() functionality to forms? I tried the following in module.php onBootstrap method but this does not work:
$sm = $e->getApplication()->getServiceManager();
$vhm = $sm->get('ViewHelperManager');
$translator = $sm->get('MvcTranslator');
$vhm->get('form')->setTranslator($translator);
I want to use it like $form->translator->translate(), in such a way it would be possible to scan code with Poedit to find translatable labeles, placeholders etc.
Here's a TranslatorFactory if you need
final class TranslatorFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
// get translator files' paths from config
$paths = $container->get('config')['settings']['localization-paths'] ?? [];
$translator = new Translator();
// add zend-i18n-resources files to translator
$translator->addTranslationFilePattern(
'phpArray',
Resources::getBasePath(),
Resources::getPatternForValidator()
);
// add your translation files to translator
foreach ($paths as $path) {
$translator->addTranslationFilePattern('phpArray', $path, '%s.php');
}
// todo: replace with user's preferred language
$translator->setLocale('tr');
return $translator;
}
}
And add your factory to service manager
'service_manager' => [
'factories' => [
\Zend\I18n\Translator\TranslatorInterface::class => \MyModule\Factory\TranslatorFactory::class,
],
],
Not sure if you're still looking for a solution, so I'll add mine.
I use the TranslatorAwareTrait in my AbstractForm class.
use Zend\I18n\Translator\TranslatorAwareTrait;
abstract class AbstractForm extends \Zend\Form\Form implements
{
use TranslatorAwareTrait;
// Form stuff
}
Then, in the *FormFactory do the following:
use Zend\I18n\Translator\Translator;
use Zend\ServiceManager\Factory\FactoryInterface;
class SomeFormFactory implements FactoryInterface
{
/**
* #param ContainerInterface $container
* #param string $requestedName
* #param array|null $options
* #return mixed|object|AbstractForm
* #throws \Psr\Container\ContainerExceptionInterface
* #throws \Psr\Container\NotFoundExceptionInterface
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
// Obviously you'll have more/other requirements. Fulfil them here.
$form = new SomeForm();
$form->setTranslator(
$container->get('translator')
);
return $form;
}
}
Usage example:
use Zend\I18n\Translator\TranslatorAwareTrait;
abstract class AbstractForm extends \Zend\Form\Form implements
{
use TranslatorAwareTrait;
public function init()
{
if (!$this->has('submit')) {
$this->addSubmitButton();
}
}
public function addSubmitButton($value = 'Save', array $classes = null)
{
$this->add([
'name' => 'submit',
'type' => Submit::class,
'attributes' => [
'value' =>
// Translate $value before passing to this function
$value === 'Save' ? $this->getTranslator()->translate('Save') : $value,
'class' => (!is_null($classes) ? join (' ', $classes) : 'btn btn-primary'),
],
]);
}
}
On the other hand, you could...
Translate strings before passing them if you're translating with Poedit.
If your modules contain the following config (in each module!):
'translator' => [
'translation_file_patterns' => [
[
'type' => 'gettext',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s.mo',
],
],
],
You can see here that translation is done using gettext. This is a PHP module that searches for the following code strings and translates its contents: _('translatable string').
The translation files to look for end with the .mo extension and can be found in __DIR__ . '/../language'.
Thus, if you make sure to have the PHP gettext module enabled to use this.
To use this with just normal strings, even in config for a Fieldset or a form, you could have the following:
$this->add([
'name' => 'street',
'required' => true,
'type' => Text::class,
'options' => [
'label' => _('Street'), // <<-- translated using gettext
],
]);

Using OAuth2 and ZF3-MVC to protect REST API

I'm trying to get https://github.com/zfcampus/zf-oauth2 working with my ZF3-MVC Application (ok, one solution could be to wait Apigility update).
I have successfully implemented the oauth2-server-php (https://github.com/bshaffer/oauth2-server-php), its zf-oauth2 module support (https://github.com/zfcampus/zf-oauth2) and adapted zf-oauth2 client for ZF3 (https://github.com/API-Skeletons/zf-oauth2-client).
However, I'm totaly stuck now trying to protect my API y following zf-oauth2 module's recommandation:
You can protect your API using the following code (for instance, at the top of a controller):
if (!$this->server->verifyResourceRequest(OAuth2Request::createFromGlobals()))
{
// Not authorized return 401 error
$this->getResponse()->setStatusCode(401);
return;
}
where $this->server is an instance of OAuth2\Server (see the AuthController.php).
I've read this post (Using ZF2 Oauth2) but it's not compliant with ZF3. I guess there's a more efficient way rather than copying/pasting zf-oauth2 module's controller and factory to instantiate the server from scratch.
Would anyone have a clue on how to implement the instance of OAuth2\Server in my API controller?
I finally did it by my own. As I spent a significant amount time on this and saw that others where also looking for a solution, here is how I did it.
At first, I suggest you read https://docs.zendframework.com/tutorials/in-depth-guide/models-and-servicemanager/ if you're not familiar with Dependency Injection and Factories (this was my case).
module.config.php
// In module/YourModule/config/module.config.php:
namespace YourAppNamespace;
use Zend\ServiceManager\Factory\InvokableFactory;
return [
'controllers' => [
'factories' => [
Controller\YourController::class => Factory\YourControllerFactory::class,
],
],
'service_manager' => [ /** Your Service Manager Config **/ ]
'router' => [ /** Your Router Config */ ]
'view_manager' => [ /** Your ViewManager Config */ ],
];
YourControllerFactory.php
// In module/YourModule/src/Controller/YourControllerFactory.php:
namespace YourAppNamespace\Factory;
use YourAppNamespace\Controller\YourController;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
class YourControllerFactory implements FactoryInterface
{
/**
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
*
* #return YourController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$controllerPluginManager = $container;
$serviceManager = $controllerPluginManager->get('ServiceManager');
// Requires zf-campus/zf-oauth2
$server = $serviceManager->get('ZF\OAuth2\Service\OAuth2Server');
$provider = $serviceManager->get('ZF\OAuth2\Provider\UserId');
return new YourController($server, $provider);
}
}
YourController.php
// In module/YourModule/src/Controller/YourController.php:
namespace YourAppNamespace\Controller;
use ZF\OAuth2\Controller\AuthController;
use OAuth2\Request as OAuth2Request;
use ZF\OAuth2\Provider\UserId\UserIdProviderInterface;
class YourController extends AuthController
{
public function __construct($serverFactory, UserIdProviderInterface $userIdProvider)
{
parent::__construct($serverFactory, $userIdProvider);
}
public function indexAction()
{
$server = call_user_func($this->serverFactory, "oauth");
if (!$server->verifyResourceRequest(OAuth2Request::createFromGlobals())) {
// Failure
$response = $server->getResponse();
return $this->getApiProblemResponse($response);
}
// Success
echo json_encode(array('success' => true, 'message' => 'It works!'));
}
}
Hope it helps!

Injecting variables into Forms __construct function Zend 2

I am trying to prepopulate a form's drop down options via data stored statically in the module.config.php in Zend 2 and am running into a problem which entails:
I try to get the Servicemanager in the __construct() function but it is unavailable.
I move the element declarations to another function within the form class so I can pass variables into it but the view controller cannot find the elements.
I currently call the form via a Servicemanager Invokable. How can I pass these arrays into the form's __construct() function?
Here is the code:
class ILLForm extends Form
{
public function __construct($fieldsetName, $campuses, $ILLTypes, $getFromOptions)
{
parent::__construct('create_ill');
$this
->setAttribute('method', 'post')
->setHydrator(new ClassMethodsHydrator(false))
->setInputFilter(new InputFilter())
;
$ill = new ILLFieldset('ill', $campuses, $ILLTypes, $getFromOptions);
$ill->setName('ill')
->setOptions(array(
'use_as_base_fieldset' => true,
));
$captcha = new Element\Captcha('captcha');
$captchaAdapter = new Captcha\Dumb();
$captchaAdapter->setWordlen(5);
$captcha->setCaptcha($captchaAdapter)
->setLabelAttributes(array('class' => 'sq-form-question-title'))
->setAttribute('class', 'sq-form-field required')
->setLabel("* Captcha")
->setAttribute('title', 'Help to prevent SPAM');
$submit = new Element\Submit('submit');
$submit->setAttribute('value', 'Submit ILL')
->setAttribute('class', 'sq-form-submit')
->setAttribute('title', 'Submit ILL');
$this->add($ill)
->add($captcha)
->add($submit);
}
}
The Indexcontroller Factory that calls the Form:
class IndexControllerFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $controllers)
{
$allServices = $controllers->getServiceLocator();
$sm = $allServices->get('ServiceManager');
$smConfig = $allServices->get('config');
$campuses = $smConfig['campuses'];
$illCategories = $smConfig['ILLCategories'];
$getFromOptions = $smConfig['getFromOptions'];
$controller = new IndexController();
$controller->setCampuses($campuses);
$controller->setILLCategories($illCategories);
$controller->setGetFromOptions($getFromOptions);
$controller->setILLForm($sm->get('ILL-form'));
$controller->setILLFormFilter($sm->get('ILL-form-filter'));
//$controller->setParams($sm->get('params'));
return $controller;
}
}
and the relevant module.config.php excerpt:
'service_manager' => array(
'abstract_factories' => array(
'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
'Zend\Log\LoggerAbstractServiceFactory',
),
'invokables' => array(
'ILL-form-filter' => 'ILL\Form\ILLFormFilter',
'ILL-form' => 'ILL\Form\ILLForm',
),
I ended up taking the form out of the service manager invokables in module.config.php (removed line for 'ILL-form') and call it from the indexControllerFactory.php instead
$create_ill = new Form\ILLForm('create_ill', $campuses, $illCategories, $getFromOptions);
$controller->setILLForm($create_ill);
instead of
$controller->setILLForm($sm->get('ILL-form'));