How to update getServicelocator to zend 3 - zend-framework

I'm new to zend3, and I came across a problem, getservicelocator no longer exists in version 3, I'm working with a controller, I wanted to know how to implement this migration, Anyone know how to make this change
namespace Base\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Paginator\Paginator;
use Zend\Paginator\Adapter\ArrayAdapter;
abstract class AbstractController extends AbstractActionController
{
/**
* Entity manager
* #var
*/
protected $em;
/** Entity
* #var
*/
protected $entity;
/**
* Controller
* #var
*/
protected $controller;
/**
* #var
*/
protected $route;
/**
* #var
*/
protected $service;
/**
* #var
*/
protected $form;
private $configTable;
/**
* AbstractController constructor.
*/
abstract function __construct();
...
/**
*
* #return \Zend\Http\Response
*/
public function excluirAction()
{
$service = $this->getServiceLocator()->get($this->service);
$id = $this->params()->fromRoute('id',0);
// Abstract service
if ($service->remove(array('id' => $id))) {
$this->flashMessenger()->addSuccessMessage('Success');
} else {
$this->flashMessenger()->addErrorMessage('Error');
}
return $this->redirect()->toRoute($this->route, array('controller' => $this->controller));
}

The architecture is not really good in your case, why would you have an action in an abstract controller...
The right way would be for the controller not to be abstract and pass the service through the constructor.
The wrong way would be to inject the service locator using a delegator.
The idea of removing the service locator is to be clearer on the dependencies of the class, so the code is way more readable (like "oh, I see this class needs ... and ... to do NAME_OF_THE_ACTION").
Also, it highly improve the code testability (you know what dependencies to mock/fake).

Related

Symfony 4 MongoDB ODM One to ONe relationship is not working

I am facing an error with symfony and mongoDB odm on one to one relationship
for example i have a user that has Work .
User Class:
/**
* #MongoDB\Document
* #MongoDBUnique(fields="email")
*/
class User implements UserInterface
{
/**
* #MongoDB\Id
*/
private $id;
/**
* #MongoDB\Field(type="string")
*/
private $firstName;
/**
* #MongoDB\Field(type="string")
*/
private $lastName;
/**
* #MongoDB\Field(type="string")
* #Assert\NotBlank()
* #Assert\Email()
*/
private $email;
/**
* #MongoDB\ReferenceOne(targetDocument=Work::class)
*/
private $work;
//getter setter
Work Class:
class Work
{
/**
* #MongoDB\Id()
*/
private $id;
/**
* #MongoDB\ReferenceOne(targetDocument=User::class)
*/
private $user;
//getter setter
}
Controller:
class TestingController extends AbstractController
{
/**
* #Route("/testing", name="testing")
* #param DocumentManager $documentManager
* #return Response
* #throws MongoDBException
*/
public function index(DocumentManager $documentManager)
{
$user = new User();
$user->setFirstName('test1');
$user->setLastName('test2');
$user->setEmail('test123#gmail.com');
$documentManager->persist($user);
$work= new Work();
$work->setUser($user);
$documentManager->persist($work);
$documentManager->flush();
return new Response("test");
}
/**
* #Route("/test", name="test")
* #param DocumentManager $documentManager
* #return Response
*/
public function test(DocumentManager $documentManager){
$user = $documentManager->getRepository(User::class)->findAll();
dump($user);
return new Response("test test");
}
}
So I created 2 classes one as user that has one work, I created the user , then I created a work and i assigned the user from the work class.
in MongoDB compass I got under Work collection a reference for the user.
now in the test method in the controller i try to find the users and dump the data.
The problem is whenever i want to find $user->getWork() i get a null value, while the user exists. but the inverse is working fine . whenever i try $work->getUser() i can find the user.
is there anything wrong in my code ? I want to use both methods : $user->getWork() and $work->getUser(),
I have tried adding to the ReferenceOne mappedBy and inversedBy but its always one of the two methods returns null value.
I think you forgot the mappedBy and inversedBy arguments in the annotation. See the documentation: https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/2.1/reference/bidirectional-references.html#one-to-one

Doctrine 2 Modular App With Entity Replacement

I'm building an application using ZF2 and Doctrine2.
The ideia is to have a base app entity (lets call it UserEntity).
But in one Module A, I will have another UserEntity-like entity that will "upgrade" the base one, with new fields. And another Module B that will add more fields.
Ex:
BaseUserEntity {
protected $id;
// ...
}
ModuleAUserEntity extends BaseUserEntity {
protected moduleAId;
}
ModuleBUserEntity extends BaseUserEntity {
protected moduleBUserName;
}
Is it possible, somehow, to get a method so when I call UserEntity, it will return the full, upgraded-by-module, entity? Ex:
UserEntity {
protected $id;
// ...
protected moduleAId;
protected moduleBUserName;
}
Is there another way to achieve something like this? The possibility to "extension" of an entity?
I have 2 different approaches:
1.First one:
you should take a look at:
http://docs.doctrine-project.org/en/latest/reference/inheritance-mapping.html
thats the legitimate and recommend by doctrine way of doing this.
2. Second one
If you dont want doctrine to mess with the database, you can use a different aproach:
Create an interface that defines the common behavior of all classes
Write your base class, implementing that behavior.
write your child classes, implementing the interface, containing the new methods, and wrapping an instance of the base class
You implement the methods that are defined in the interface, but since they are already implemented in the parent class, you just bypass the call to the wrapped object.
So, you are using composition over inheritance to avoid doctrine (and probably you) to get crazy
In order to have a really clean behavior with doctrine, the database that i imagine is:
a table with the parent entity
a table with the child entity, containing
a foreign key with the id of the related parent entity (this is, the row in the parent table that contains the values asociated to this, since the child has to have the parent and the child fields)
all the extra columns
For instance:
Interface:
namespace DBAL\Entity;
interface IProfesional
{
public function setName($name);
public function getName();
public function getId();
}
Parent class:
namespace DBAL\Entity;
use Doctrine\ORM\Mapping as ORM;
use DBAL\Entity\User\IUserAware;
/**
* Profesional
*
* #ORM\Table(name="profesional")
* #ORM\Entity
*/
class Profesional implements IProfesional
{
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=45, nullable=true)
*/
private $name;
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* Set nombre
*
* #param string $nombre
* #return Profesional
*/
public function setName($nombre)
{
$this->name = $nombre;
return $this;
}
/**
* Get nombre
*
* #return string
*/
public function getNombre()
{
return $this->name;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
}
child class:
namespace DBAL\Entity;
use DBAL\Entity\User\IUserAware;
use Doctrine\ORM\Mapping as ORM;
/**
* Jugador
*
* #ORM\Table(name="jugador")
* #ORM\Entity(repositoryClass="DBAL\Repository\JugadorRepository")
*/
class Player implements IProfesional
{
/**
* #var integer
*
* #ORM\Column(name="profesional_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var \Profesional
*
* #ORM\OneToOne(targetEntity="Profesional")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="profesional_id", referencedColumnName="id", unique=true)
* })
*/
private $profesional;
/**
* Constructor: you create an empty Profesional,
so you are sure you will never use a reference to an in-existent object.
But anyways, if this is an entity loaded from the database by doctrine,
doctrine will fill that field whith an actual professional from the parent table,
based in the foreign key id
*/
public function __construct()
{
if(!isset($id)){
$this->profesional=new Profesional();
}
}
/**
* Set profesional
*
* #param \Profesional $profesional
* #return Jugador
*/
public function setProfesional( Profesional $profesional = null)
{
$this->profesional = $profesional;
return $this;
}
/**
* Get profesional
*
* #return \Profesional
*/
public function getProfesional()
{
return $this->profesional;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->profesional->getId();
}
///New fields, for instance:
/**
* #var integer
*
* #ORM\Column(name="height", type="integer", nullable=true)
*/
private $height;
public function getHeight()
{
return $this->height;
}
public function setHeight($h)
{
$this->height=$h;
}
}

How to add indexes to FOSUserBundle:User?

I noticed FOSUserBundle does not create any indexes.
We are supposed to create a user Document like this:
use FOS\UserBundle\Document\User as BaseUser;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
/**
* #MongoDB\Document
*/
class User extends BaseUser
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/*
public function __construct()
{
parent::__construct();
// your own logic
}
*/
}
So how do I add an index to say, the 'email' field? Should I just overwrite the inherited attribute?
Actually FOSUserBundle does create. You should run
php app\console doctrine:mongodb:schema:update
to create them. By default there is usernameCanonical and emailCanonical indexes.
If you need custom index use this approach:
<?php
/**
* #MongoDB\Document
* #MongoDB\Indexes({
* #MongoDB\Index(keys={"email"="asc"})
* })
*/
class User extends BaseUser {
// ...
and do not forget to run doctirne:mongodb:schema:update task again.

Generate merged entity class files with symfony2

I'm a little bit stuck with my poor knowledge of Symfony2 and Doctrine. Here is what I'm trying to do: I have two different files containing a class definition of the same class. I want to merge these two into a new class file.
I have an existing entity class file Foo.php:
/**
* #ORM\Entity
* #ORM\Table(name="foo")
*/
class Foo
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*
* #var int
*/
protected $id;
/**
* #ORM\Column(type="string")
*
* #var string
*/
protected $name;
/**
* #param string $name
* #return void
*/
public function setName($name)
{
$this->name = (string) $name;
}
/**
* #return string name
*/
public function getName()
{
return $this->name;
}
protected function someMagic($in) {
die('no magic happens.');
}
}
and a second entity class file with the same name Foo.php:
/**
* #ORM\Entity
* #ORM\Table(name="foo")
*/
class Foo
{
/**
* #ORM\Column(type="string")
*
* #var string
*/
protected $color;
/**
* #param string $name
* #return void
*/
public function setColor($color)
{
$this->color = $this->someColorMagic($color);
}
/**
* #return string name
*/
public function getColor()
{
return $this->color;
}
protected function someMagic($in) {
return 'magic: ' . $out;
}
}
How can I merge these two together (not at runtime, just during installation of a symfony application - could be done with a symfony console command like foobar:install) so I get a merged class Foo written to a file FooExtended.php that contains properties and methods of both classes and the doctrine annotations preserved?
Does Symfony (or the DoctrineBundle within) support stuff like this out of the box? Or can someone point me into the right direction how this can be achieved?
It now turned out with some changes in design I can solve my problem with simple class inheritance. So there is no need for a class merging at design time.

Symfony2 Sluggable does not exist or could not be autoloaded

I've been trying to get an existing project working on local copy but have been countering alot of problems with the ODM and the dependencies.
I'm encountering this Sluggable issue :
[Semantical Error] The annotation "#Gedmo\Mapping\Annotation\Sluggable" in property
Cereals\ProductBundle\Document\Category\Specialty::$name does not exist, or could not be
auto-loaded.
And my Cereals...\Specialty file is such:
<?php
namespace Cereals\ProductBundle\Document\Category;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #MongoDB\Document(collection="Specialty",
repositoryClass="Cereals\ProductBundle\Repository\SpecialtyRepository")
*/
class Specialty
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/**
* #Gedmo\Sluggable
* #MongoDB\Index(order="asc")
* #MongoDB\String
*/
protected $name;
/**
* #MongoDB\String
* #MongoDB\UniqueIndex
* #Gedmo\Slug
*/
protected $slug;
/**
* #MongoDB\String
*/
I understand from Googling that there are some syntax updates for doctrine 2.1.x and I've used the new annotations for the #Gedmo\Mapping\Annotation\Sluggable here too.
Still the Semantical Error turns up.
Can anyone point some directions ? Thanks !
The #Gedmo\Sluggable annotation does not exisit. If you look in this folder, you will see this anottation is not implemented.
Actually, You can define your class like that:
<?php
namespace Cereals\ProductBundle\Document\Category;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* #MongoDB\Document(collection="Specialty",
repositoryClass="Cereals\ProductBundle\Repository\SpecialtyRepository")
*/
class Specialty
{
/**
* #MongoDB\Id(strategy="auto")
*/
protected $id;
/**
* #MongoDB\Index(order="asc")
* #MongoDB\String
*/
protected $name;
/**
* #MongoDB\String
* #MongoDB\UniqueIndex
* #Gedmo\Slug(fields={"name"})
*/
protected $slug;
}
The #Gedmo\Slug annotation needs the properties which will be used for the slug generation.