Symfony 3.0: Reuse entity in repository - php

On my Symfony 3.0 project I have a Entity named ImageGroups and a repository I made ImageGroupsRepository that Use ImageGroups entity. I also made an Images entity with a ImagesRepository
In ImageGroupsRepository I have a method named getUserImageGroups and on ImagesRepository I have a method named add.
What I want to ask is How to use the getUserImageGroups method from ImageGroupsRepository into add from ImagesRepository?

The answer given by A.L is correct, I just wanted to offer an alternative method to access the entity manager without having to call the function again, via $this->_em:
class ImagesRepository extends EntityRepository
{
public function add()
{
$imagesGroups = $this->_em
->getRepository('AcmeBundle:ImageGroups')
->getUserImageGroups();
// …
}
}
If you look at the documentation for EntityRepository you'll see that the getEntityManager() function simply returns the protected $_em member of the EntityRepository class.

In your repository, you can get the entity manager with $this->getEntityManager(), this allow to call getRepository() in order to get another repository:
class ImagesRepository extends EntityRepository
{
public function add()
{
$em = $this->getEntityManager();
$imagesGroups = $em
->getRepository('AcmeBundle:ImageGroups')
->getUserImageGroups();
// …
}
}

Related

Refactoring a Controller in symfony to adapt to hexagonal architecture

I have create a controller that creates a Owner record into database. Everything was done on the CreateOwnerController like this and working properly:
class CreateOwnerController extends Controller
{
public function executeAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$owner = new Owner($request->request->get("name"));
$em->persist($owner);
$em->flush();
return new Response('Added',200);
}
}
Now,In order to refactor that I have created an interface that defines the OwnerRepository:
interface OwnerRepositoryInterface {
public function save(Owner $owner);
}
And a OwnerRepository that implements this interface:
class OwnerRepository extends EntityRepository implements OwnerRepositoryInterface {
public function save(Owner $owner) {
$this->_em->persist($owner);
$this->_em->flush();
}
}
Then I have Created for the application layer a CreateOwnerUseCase Class that receives a OwnerRepository and executes a method to save in into OwnerRepository:
class CreateOwnerUseCase {
private $ownerRepository;
public function __construct(OwnerRepositoryInterface $ownerRepository) {
$this->ownerRepository = $ownerRepository;
}
public function execute(string $ownerName) {
$owner = new Owner($ownerName);
$this->ownerRepository->save($owner);
}
}
Ok, i'm spliting the initial Controller intro layer Domain / Aplication / Framework layers.
On the CreateOwnerController now i have instantiated that Use Case and passed as parameter the OwnerRepository like this:
class CreateOwnerController extends Controller {
public function executeAction(Request $request) {
$createOwnerUseCase = new CreateOwnerUseCase(new OwnerRepository());
$createOwnerUseCase->execute($request->request->get("name"));
return new Response('Added',200);
}
}
But it fails when Make the request to create new Owner:
Warning: Missing argument 1 for Doctrine\ORM\EntityRepository::__construct(), called in /ansible/phpexercises/Frameworks/mpweb-frameworks-symfony/src/MyApp/Bundle/AppBundle/Controller/CreateOwnerController.php
It happens on OwnerRepository passed as parameter. It wants an $em and Mapped Class... What is the meaning of this mapped Class? How solve this error?
This answer is for Symfony 3.3+/4+.
You need to register your repository as a service. Instead of extending it 3rd party code, you should use composition over inheritance.
final class OwnerRepository implements OwnerRepositoryInterface
{
private $entityManager;
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}
public function save(Owner $owner)
{
$this->entityManager->persist($owner);
$this->entityManager->flush();
}
}
And register it as a service:
# app/config/services.yml
services:
App\Repository\:
# for location app/Repository
resource: ../Repository
You might need to tune paths a bit, to make that work.
To get more extended answer, see How to use Repository with Doctrine as Service in Symfony

Symfony2 Entity method called in repository class

How can I call method from entity class in repository class.
I had tried to do something like this, but no success.
class ProfileConnectionsListRepository extends EntityRepository
{
public function connectionUserNames($userId)
{
$connections = $this->_em
->findOneBy(array('user1Id' => $userId))
->getUser2Id();
}
}
so if this is invalid can do something like that on doctrine way without using raw queries.
You might need to get repository first.
$connections = $this->_em
->getRepository(UserEntity::class)
->findOneBy(array('user1Id' => $userId))
->getUser2Id();

Symfony2 extending entity

I'm new in Symfony2. I need to extend entity, also I need add custom methods to repository class.
What is best way to do this?
I need have possibility to access from this class entity class methods for example getCompanyId();
namespace Catalog\WebBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class ComCompany
{
private $cmpId;
public function getcmpId() {
return $this->cmpId
}
}
class ComCompanyService extends ComCompany
{
public function getcmpIdChanget() {
return ($this->cmpId) * 2
}
}
Also I need have possibility to access repository class methods
$em = $this->getDoctrine()->getManager();
$products = $em->getRepository('WebBundle:ComCompanyService')
->getcmpId();
Maybe it's poor example, but I thing you understand what I want. What I need to use for this ? Services or EntityRepository ? or something else ?

Laravel 4 setting up model using the IoC container

I recently watched this video and wanted to change my Laravel controllers so that they had their dependencies managed with Laravel's IoC container. The video talks about creating an interface for a Model and then implementing that interface for the specific data source used.
My question is: when implementing the interface with a class that extends Eloquent and binding that class to the controller so that it is accessible from $this->model, should I also create interfaces and implementations for the Eloquent models which may be returned when calling methods such as $this->model->find($id)? Should there be different classes for the Model and the ModelRepository?
Put it another way: how do I do new Model when my model is in $this->model.
Generally, yes, people doing that pattern (the repository pattern) have an interface which have some methods defined that your app will use:
interface SomethingInterface {
public function find($id);
public function all();
public function paged($offset, $limit);
}
Then you create an implementation of this. If you're using Eloquent, then you can make an Eloquent implementation
use Illuminate\Database\Model;
class EloquentSomething {
protected $something;
public function __construct(Model $something)
{
$this->something = $something;
}
public function find($id)
{
return $this->something->find($id);
}
public function all() { ... }
public function paged($offset, $limit) { ... }
}
Then you make a service provider to put it all together, and add it into app/config/app.php.
use Something; // Eloquent Model
use Namespace\Path\To\EloquentSomething;
use Illuminate\Support\ServiceProvider;
class RepoServiceProvider extends ServiceProvider {
public function register()
{
$app = $this->app;
$app->bind('Namespace/Path/To/SomethingInterface', function()
{
return new EloquentSomething( new Something );
});
}
}
Finally, your controller can use that interface as a type hint:
use Namespace/Path/To/SomethingInterface;
class SomethingController extends BaseController {
protected $something;
public function __construct(SomethingInterface $something)
{
$this->something = $something;
}
public function home() { return $this->something->paged(0, 10); }
}
That should be it. Apologies on any errors, this isn't tested, but is something I do a lot.
Downsides:
More code :D
Upsides:
Able to switch out implementations (instead of EloquentSomething, can use ArraySomething, MongoSomething, whatever), without changing your controller code or any code that uses an implementation of your interface.
Testable - you can mock your Eloquent class and test the repository, or mock your constructor dependency and test your controller
Re-usable - you can App::make() to get the concrete EloquentSomething anywhere in your app and re-use the Something repository anywhere in your code
Repository is a good place to add additional logic, like a layer of cacheing, or even validation rules. Stock mucking about in your controllers.
Finally:, since I likely typed all that out and STILL DIDN'T ANSWER YOUR QUESTION (wtf?!), you can get a new instance of the model using $this->model. Here's an example for creating a new Something:
// Interface:
public function create(array $data);
// EloquentSomething:
public function create(array $data)
{
$something = this->something->newInstance();
// Continue on with creation logic
}
Key is this method, newInstance().
I've used $newModel = $this->model and it's worked for me.

Zend framework 2 translator in model

How to get translator in model?
Inside view we can get translator using this code
$this->translate('Text')
Inside controller we can get translator using this code
$translator=$this->getServiceLocator()->get('translator');
$translator->translate("Text") ;
But how to get translator in model?
I'd tried so many ways to get service locator in models
2 of those
1)Using MVC events
$e=new MvcEvent();
$sm=$e->getApplication()->getServiceManager();
$this->translator = $sm->get('translator');
if i pring $sm it is showing null. but it works fine in Model.php onBootstrap
2)Created one model which implements ServiceLocatorAwareInterface
SomeModel.php
<?php
namespace Web\Model;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
class SomeModel implements ServiceLocatorAwareInterface
{
protected $services;
public function setServiceLocator(ServiceLocatorInterface $locator)
{
$this->services = $locator;
}
public function getServiceLocator()
{
return $this->services;
}
}
and used that inside my model
$sl = new SomeModel();
$sm=$sl->getServiceManager();
var_dump($sm); exit;
$this->translator = $sm->get('translator');
this is also printing null.
If you don't need the servicemanager instance in your model, simply inject translator instance to it.
For example:
// Your model's constructor
class MyModel {
// Use the trait if your php version >= 5.4.0
use \Zend\I18n\Translator\TranslatorAwareTrait;
public function __construct( $translator )
{
$this->setTranslator( $translator );
}
public function modelMethodWhichNeedsToUseTranslator()
{
// ...
$text = $this->getTranslator()->translate('lorem ipsum');
// ...
}
}
When you creating your model first time on service or controller level
class someClass implements ServiceLocatorAwareInterface {
public function theMethodWhichCreatesYourModelInstance()
{
// ...
$sm = $this->getServiceLocator();
$model = new \Namespace\MyModel( $sm->get('translator') )
// ...
}
}
If you need to instantiate your model (new MyModel();) on multiple methods/classes, consider to writing a factory for it.
Here is a nice article about Dependency Injection and PHP by Ralph Schindler for more detailed comments about this approach.
For your Model class to be ServiceLocatorAware, you not only need to implement the interface, you also need to make your model a service of the service manager, and fetch the model from there.
Add your model to the service manager, since it doesn't appear to need any constructor params, it's invokable, so you can add it to the invokables array in service manager config. You can do that by using the getServiceConfig() method in your Module class...
class Module
{
public function getServiceConfig()
{
return array(
'invokables' => array(
'SomeModel' => 'Fully\Qualified\ClassName\To\SomeModel',
),
);
}
}
Then, instead of calling the new keyword to create your model instance, you fetch it from the service manager, for instance, by calling the getServiceLocator() method in a controller action...
public function fooAction()
{
$sm = $this->getServiceLocator();
$model = $sm->get('SomeModel');
}
When your model is fetched from the service manager, a service initializer will look to see if it implements the ServiceLocatorAwareInterface and automatically call setServiceLocator() if it does, passing it an instance of the service manager.

Categories