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

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);

Related

Zend_Cache understanding issue

I try to use Zend_Cache (first try) to save information about user grants. The idea and most of the source code comes from Oleg Krivtsovs tutorial.
I get an error, if I try to retrieve my cache.
Call to a member function getItem() on array
Here the implementation of FilesystemCache, in my global.php
'caches' => [
'FilesystemCache' => [
'adapter' => [
'name' => Filesystem::class,
'options' => [
// Store cached data in this directory.
'cache_dir' => './data/cache',
// Store cached data for 1 hour.
'ttl' => 60*60*1
],
],
'plugins' => [
[
'name' => 'serializer',
'options' => [
],
],
],
],
],
Here my factory class:
<?php
namespace User\Service;
use User\Controller\Plugin\AuthPlugin;
use User\Model\GrantsTable;
use User\Model\UserTable;
use Zend\Authentication\AuthenticationService;
use Zend\ServiceManager\Factory\FactoryInterface;
use Interop\Container\ContainerInterface;
class AccessControlFactory implements FactoryInterface {
public function __invoke(ContainerInterface $container, $requestedName, array $options = null) {
$config = $container->get('config');
$userTable = $container->get(UserTable::class);
$grantsTable = $container->get(GrantsTable::class);
$cache = $config['caches']['FilesystemCache'];
$userplugin = $container->get(AuthPlugin::class);
// $authentication = $container->get( \Zend\Authentication\AuthenticationService::class);
return new AccessControl($userTable, $grantsTable, $cache, $userplugin);//, $authentication
}
}
Now in the init function within my AccessControl Service, I try to retrieve from the cache:
$this->cache->getItem('rbac_container', $result);
There I get the above error.
Any help with a bit of explanation would be appreciated.
What you're injecting to the AccessControl constructor is an array, not a cache implementation, because $config['caches']['FilesystemCache'] returns an array of FilesystemCache options (adapter, plugins, etc.). What you're supposed to do is fetch the cache implementation via the ContainerInterface, like this:
$cache = $container->get('FilesystemCache');
Then the ContainerInterface will depend on StorageCacheAbstractServiceFactory to find your requested cache configs and return the class for you.

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

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

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.

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
],
]);

How can I perform a raw query in doctrine mongodb

Is there a way to perform a raw query (just as you can do with MySQL) in Doctrine with MongoDB?
I'm trying to do this:
db.report.aggregate([{"$group" : {_id:"$content", count:{$sum:1}}}])
It doesn't seem to be a native aggregate function in Doctrine either, is it?
Following did the trick for me
$dbName = $this->container->getParameter('mongo_db_name');
$connection = $this->container->get('doctrine_mongodb')->getConnection();
$mongo = $connection->getMongo();
$db = $mongo->selectDB($dbName);
$results = $db ->command([
'aggregate' => 'report',
'pipeline' => [
['$group' => ['_id' => '$content', 'count' => ['$sum' => 1]]]
]
]);
return $results;
Not sure about native Doctrine function, but in case of aggregations I'd prefer to have RAW JSON output, because it's mostly used to render out some charts.
I needed to use an advanced version of a $lookup stage, but sadly, didn't because its lookup() method adds just a basic version of a stage like:
public function getExpression(): array
{
return [
'$lookup' => [
'from' => $this->from,
'localField' => $this->localField,
'foreignField' => $this->foreignField,
'as' => $this->as,
],
];
}
An obvious solution would be to provide a custom version of Stage/Lookup.php class, but I didn't want to create a separate file for such a small thing, so I decided to go with inline class:
$lookupExpr = [
'$lookup' => [...],
];
$aggregationBuilder->addStage(new class($lookupExpr, $aggregationBuilder) extends Aggregation\Stage {
public function __construct(private array $lookupExpr, Builder $builder) {parent::__construct($builder);}
public function getExpression(): array
{
return $this->lookupExpr;
}
});
In Doctrine ODM 2.0, the underlying connection is handled by the mongodb/mongodb package instead of doctrine/mongodb. As such, you can get the connection though doctrine ManagerRegistry::getConnection(), then use the command function using the mongodb library:
use Doctrine\Bundle\MongoDBBundle\ManagerRegistry;
class Test {
function execute(ManagerRegistry $mr) {
$database= $mr->getConnection()->db_name;
$cursor = $database->command([
'geoNear' => 'restos',
'near' => [
'type' => 'Point',
'coordinates' => [-74.0, 40.0],
],
'spherical' => 'true',
'num' => 3,
]);
$results = $cursor->toArray()[0];
var_dump($results);
}
}
In my case i use aggregation
$db = $mongo->selectDB('ostrov_sync');
$dbTable = $mongo->selectCollection($db, 'sync_task');
$results = $dbTable->aggregate([
[
'$match' => [
'payloadHash' => [
'$eq' => '0000cfdc-c8cf-11e9-9485-000c29d1ed7a',
],
],
]
]);
dump(results);