symfony 4 Doctrine service allowed memory size exhausted - service

I inject '#doctrine.orm.entity_manager' in a simple class service like this:
tigris_base.array_to_form:
class: Tigris\BaseBundle\Service\ArrayToFormService
arguments: ['#form.factory', '#doctrine.orm.entity_manager']
public: true
And my service constructor
public function __construct(FormFactory $formFactory, EntityManagerInterface $entityManager)
{
$this->formFactory = $formFactory;
$this->entityManager = $entityManager;
}
But I have an error:
Allowed memory size of 536870912 bytes exhausted (tried to allocate 20480 bytes)
I try to set a higher value in PHP.ini.
I don't understand why I have this error, I use doctrine services in other services and it works.
Do you know where is the problem ?
Thanks.

Related

Symfony 4.2 Creating Repository as service in vendor/acme/demo-bundle

I am working on a third party bundle which is in the vendor/ directory.
I have an Entity class which looks like this:
/**
* #ORM\Entity(repositoryClass="Acme\DemoBundle\Repository\ArticleRepository")
* #ORM\Table(name="acme_demo_article")
*/
class Article
And a Repository class like this:
class ArticleRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, Article::class);
}
}
This generates the following error:
The "Acme\DemoBundle\Repository\ArticleRepository" entity repository
implements
"Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepositoryInterface",
but its service could not be found. Make sure the service exists and
is tagged with "doctrine.repository_service".
If i remove the repositoryClass from the entity definition, I dont have the error anymore and i can use doctrine as such from my controller:
this->getDoctrine()->getRepository(Article::class)->findBy([], null, $limit, ($page - 1) * $limit);
I tried adding the repository as a service in the bundle service definition but it does not change anything:
vendor/Acme/demo-bundle/Resources/config/services.yaml
services:
Acme\DemoBundle\Repository\:
resource: '../../Repository/ArticleRepository.php'
autoconfigure: true
tags: ['doctrine.repository_service']
bin/console debug:autowire or debug:container wont show the service.
I also tried adding the extension:
namespace Acme\BlogBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
class AcmeBlogExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new YamlFileLoader(
$container,
new FileLocator(__DIR__.'/../Resources/config')
);
$loader->load('services.xml');
}
}
Did not work either. I dont have the impression that the extension is being called. I tried adding a constructor to it and dump, die in the constructor, but there are no results of the dump.
So my question is how do i define my repositories as a service from the vendor directory ?
The source code is overhere: https://github.com/khalid-s/sf4-bundle-test
After much struggling, i succedded in my task. I dont think that's it should be done like this, but if this can help someone...
I added in my DependencyInjection folder of the bundle:
class AcmeBlogExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$loader = new YamlFileLoader(
$container,
new FileLocator(__DIR__.'/../Resources/config')
);
$loader->load('services.yaml');
}
}
I created a compiler (this is the part which i struggled to figure out) to register my service
class RepositoryCompiler implements CompilerPassInterface
{
/**
* #inheritdoc
*/
public function process(ContainerBuilder $container)
{
$container->register('acme_blog.repository', ArticleRepository::class);
}
}
I added in my Bundle class:
class AcmeBlogBundle extends Bundle
{
/** #info this function normally is useless */
public function getContainerExtension()
{
// This is only useful if the naming convention is not used
return new AcmeBlogExtension();
}
/**
* #inheritDoc
*/
public function build(ContainerBuilder $container)
{
$container->addCompilerPass(new RepositoryCompiler());
parent::build($container);
}
}
And finally the service itself:
services:
Acme\BlogBundle\Repository\:
resource: '../../Repository/*Repository.php'
autoconfigure: true
autowire: true
tags: ['doctrine.repository_service']
The autoconfigure and autowire are useless since they are not taken into consideration when i debug:container which looks like this:
php bin/console debug:container acme
Information for Service "acme_blog.article.repository"
=======================================================
---------------- -----------------------------------------------
Option Value
---------------- -----------------------------------------------
Service ID acme_blog.article.repository
Class Acme\BlogBundle\Repository\ArticleRepository
Tags doctrine.repository_service
Public yes
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired no
Autoconfigured no
---------------- -----------------------------------------------
One very important note which made me loose a lot of time:
Do clear your cache after every change to your services. Even in dev
mode they are not reloaded after every refresh

MongoDB and Large Datasets when using a Repository pattern

Okay so at work we are developing a system using MVC C# & MongoDB. When first developing we decided it would probably be a good idea to follow the Repository pattern (what a pain in the ass!), here is the code to give an idea of what is currently implemented.
The MongoRepository class:
public class MongoRepository { }
public class MongoRepository<T> : MongoRepository, IRepository<T>
where T : IEntity
{
private MongoClient _client;
private IMongoDatabase _database;
private IMongoCollection<T> _collection;
public string StoreName {
get {
return typeof(T).Name;
}
}
}
public MongoRepository() {
_client = new MongoClient(ConfigurationManager.AppSettings["MongoDatabaseURL"]);
_database = _client.GetDatabase(ConfigurationManager.AppSettings["MongoDatabaseName"]);
/* misc code here */
Init();
}
public void Init() {
_collection = _database.GetCollection<T>(StoreName);
}
public IQueryable<T> SearchFor() {
return _collection.AsQueryable<T>();
}
}
The IRepository interface class:
public interface IRepository { }
public interface IRepository<T> : IRepository
where T : IEntity
{
string StoreNamePrepend { get; set; }
string StoreNameAppend { get; set; }
IQueryable<T> SearchFor();
/* misc code */
}
The repository is then instantiated using Ninject but without that it would look something like this (just to make this a simpler example):
MongoRepository<Client> clientCol = new MongoRepository<Client>();
Here is the code used for the search pages which is used to feed into a controller action which outputs JSON for a table with DataTables to read. Please note that the following uses DynamicLinq so that the linq can be built from string input:
tmpFinalList = clientCol
.SearchFor()
.OrderBy(tmpOrder) // tmpOrder = "ClientDescription DESC"
.Skip(Start) // Start = 99900
.Take(PageLength) // PageLength = 10
.ToList();
Now the problem is that if the collection has a lot of records (99,905 to be exact) everything works fine if the data in a field isn't very large for example our Key field is a 5 character fixed length string and I can Skip and Take fine using this query. However if it is something like ClientDescription can be much longer I can 'Sort' fine and 'Take' fine from the front of the query (i.e. Page 1) however when I page to the end with Skip = 99900 & Take = 10 it gives the following memory error:
An exception of type 'MongoDB.Driver.MongoCommandException' occurred
in MongoDB.Driver.dll but was not handled in user code
Additional information: Command aggregate failed: exception: Sort
exceeded memory limit of 104857600 bytes, but did not opt in to
external sorting. Aborting operation. Pass allowDiskUse:true to opt
in..
Okay so that is easy to understand I guess. I have had a look online and mostly everything that is suggested is to use Aggregation and "allowDiskUse:true" however since I use IQueryable in IRepository I cannot start using IAggregateFluent<> because you would then need to expose MongoDB related classes to IRepository which would go against IoC principals.
Is there any way to force IQueryable to use this or does anyone know of a way for me to access IAggregateFluent without going against IoC principals?
One thing of interest to me is why the sort works for page 1 (Start = 0, Take = 10) but then fails when I search to the end ... surely everything must be sorted for me to be able to get the items in order for Page 1 but shouldn't (Start = 99900, Take = 10) just need the same amount of 'sorting' and MongoDB should just send me the last 5 or so records. Why doesn't this error happen when both sorts are done?
ANSWER
Okay so with the help of #craig-wilson upgrading to the newest version of MongoDB C# drivers and changing the following in MongoRepository will fix the problem:
public IQueryable<T> SearchFor() {
return _collection.AsQueryable<T>(new AggregateOptions { AllowDiskUse = true });
}
I was getting a System.MissingMethodException but this was caused by other copies of the MongoDB drivers needing updated as well.
When creating the IQueryable from an IMongoCollection, you can pass in the AggregateOptions which allow you to set AllowDiskUse.
https://github.com/mongodb/mongo-csharp-driver/blob/master/src/MongoDB.Driver/IMongoCollectionExtensions.cs#L53

ScopeConfigInterface as parameter in constructor - Magento 2

I'm working with Magento 2, I'm still new.
I have this constructor inside a controller class:
public function __construct(Context $context, PageFactory $pageFactory, \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig)
{
$this->pageFactory = $pageFactory;
$this->scopeConfig = $scopeConfig;
return parent::__construct($context);
}
It was working until I added the ScopeConfigInterface.
Now, when I load my page I get this error:
Recoverable Error: Argument 3 passed to xxx\Customer\Controller\Login::__construct() must implement interface Magento\Framework\App\Config\ScopeConfigInterface, none given, called in...
Any ideas? Thanks.
I deleted folder:
"var/generation"
And that solved the problem.

apache commons pool - how to use a factory that takes arguments

I am trying to use apache commons pool to create a pool of 'objects'. Since I already have an object factory which takes a string type argument and create a right type of object I want to use this factory.
But the problem is that none of the signatures of generic pool object allow me to pass a factory which takes arguments.
//This is a wrapper class that holds an Object pool
Class INService {
private ObjectPool<INConnection> pool_ = null;
/**
* Constructs an instance of INService, given a pool size
* and a class which implements INHandler interface.
* #param poolSize - size of the service pool
* #param c - the class which handles the INHandler service interface.
*/
public INService(int poolSize, String objectType) {
pool_ = new GenericObjectPool<INConnection>(factory, Objecttype); // won't compile.
}
...
}
The PoolableObjectfactory interface defines methods like makeObject, destroyObject, validateObject, activateObject and passivateObject. But no makeObject() method which takes parameters.
It seems that the only way I can do this is to write multiple factory classes for each type of object and write an if-else stuff, like:
public INService(int poolSize, String objectType) {
if (objectType.equals("scap")
pool_ = new GenericObjectPool<INConnection>(scapFactory);
else if (objectType.equals("ucip")
pool_ = new GenericObjectPool<INConnection>(ucipFactory);
...
}
Or, is there any elegant way, instead of duplicating/creating several factory classes just for this sake?
You should read up on the KeyedObjectPool<K,V> interface which can also be found in commons-pool.
From its javadoc:
A keyed pool pools instances of multiple types. Each type may be accessed using an arbitrary key.
You could then implement a KeyedPoolableObjectFactory<K,V> to make instances based on the key parameter, it has the makeObject(K key) function you are looking for.
PS: It appears you haven't marked any answers to your questions as "accepted", you might want to work on that.

Symfony2 service not found

I have a custom service class:
namespace Acme\OpsBundle\Lib;
use Doctrine\ORM\EntityManager;
use Monolog\Logger;
class ProductManager
{
private $m_logger;
private $m_em;
public function __construct(EntityManager $em, Logger $logger)
{
$this->m_logger = $logger;
$this->m_em = $em;
}
...
}
Defined in config.yml as:
services:
opsbundle.prod_manager:
class: Acme\OpsBundle\Lib\ProductManager
arguments: [#doctrine.orm.entity_manager, #monolog.logger]
And Im accessing it in a controller via:
$repoman = $this->get('opsbundle.prod_manager');
But I get the following error:
Fatal error: Class 'Acme\OpsBundle\Lib\ProductManager' not found
in C:\apache\Symfony\app\cache\dev\appDevDebugProjectContainer.php on
line 1555
This worked at one point but I cant figure out what has changed since then to break it. I have tried clearing the cache and restarting apache.
Can anyone suggest why this would happen?