I use Loggable to backup changes in Entities.
The default AbstractLogEntry does not have enough columns for my needs.
Thats why i extended the class and added extra getters and setters.
See the code below
/**
* EmployeeBackup
*
* #ORM\Table(name="employee_backup")
* #ORM\Entity(repositoryClass="Gedmo\Loggable\Entity\Repository\LogEntryRepository")
*
*/
class EmployeeBackup extends AbstractLogEntry
{
/**
* #var int
*
* #ORM\Column(name="division_id", type="integer", unique=true)
*/
private $divisionId;
/**
* #return int
*/
public function getDivisionId(): int
{
return $this->divisionId;
}
/**
* #param string $divisionId
*/
public function setDivisionId(string $divisionId): void
{
$this->divisionId = $divisionId;
}
}
The extension is using the class above. So it works.
But now i need to set the divisionId when a new version is stored.
I tried the code below
$loggable = new LoggableListener();
$loggable->setDivision($division);
$evm->addEventSubscriber($loggable);
And this is what i get:
Attempted to call an undefined method named "setDivision" of class "Gedmo\Loggable\LoggableListener".
And thats true because LoggableListener does not have a setDivision function. My question is: Do i need to override the listener and if so, how do i do that?
Thanks ;)
Related
I have a game where the player can finish some tasks.
I have separated the behaviour part of the task to its ORM part.
Eventually a copy of the task is being saved somewhere on the player's document (doesn't matter where for this specific question).
The problem is, I am not sure where to put the extra information that I send to the client that is not necessary for the behaviour itself, but it is needed to show the player information regarding the task itself.
This is my task interface:
interface ITask
{
/**
* #param Player $player
*/
public function init(Player $player);
/**
* #param PlayerAction $action
*/
public function progress(PlayerAction $action);
public function reset();
/**
* #return bool
*/
public function isComplete();
}
This is my abstract task:
abstract class BaseTask implements ITask
{
/**
* #var int
*/
public $id;
/**
* #var int
*/
protected $currentValue;
/**
* #var int
*/
protected $targetValue;
public function __construct($targetValue)
{
$this->currentValue = 0;
$this->targetValue = $targetValue;
}
/**
* #param int
*/
public abstract function setCurrentValue($current);
/**
* #return int
*/
public abstract function getCurrentValue();
/**
* #return int
*/
public abstract function getID();
/**
* #param int
*/
public abstract function setID($id);
/**
* #return int
*/
public abstract function getTargetValue();
/**
* #param int
*/
public abstract function setTargetValue($target);
/**
* #return boolean
*/
public function isComplete()
{
if ($this->getCurrentValue() >= $this->getTargetValue())
{
return true;
}
return false;
}
}
Now I need to decide how where to put the extra data, e.g description, title, theme etc...
I thought about two options: I can just put it on the base task
itself, but then what happens if I don't need it? I just leave it
blank? feel like the wrong place for me.
I could create a wrapper
class that will hold the task, but then I will need to always
call the wrapper to get to the task, and it feels kind of
wrong.
Looking for alternative suggestions.
You should inherit the CustomTask from TaskBase.
If you you have limitation in inheritance, encapsulate additional fields into a class called TaskAdditionalInfoBase and associate to the TaskBase.
Then various classes can inherit TaskAdditionalInfoBase to present a custom additional info to the the task.
I want to be able to select a school (that has its own entity) while creating a mission (also has its entity)
Since a school can have several missions, and you can select several schools at the mission's creation, I used a ManyToMany.
The problem is that after creating this "ManyToMany", generating the entities and updating my schema, Symfony created a table, but left it totally empty, without the two columns that I asked for. I'm not really used to Symfony nor to the ManyToMany system, so I might have done some mistake without noticing it, still I find this weird.
Here's the interesting part of my ecole (school) entity:
class Ecole{
// ...
/**
* #ORM\ManyToMany(targetEntity="MissionBundle\Entity\Mission", mappedBy="ecolesDispo")
*/
protected $missionsDispos;
// ...
/**
* Add missionsDispo
*
* #param \MissionBundle\Entity\Mission $missionsDispo
*
* #return Ecole
*/
public function addMissionsDispo(\MissionBundle\Entity\Mission $missionsDispo)
{
$this->missionsDispos[] = $missionsDispo;
return $this;
}
/**
* Remove missionsDispo
*
* #param \MissionBundle\Entity\Mission $missionsDispo
*/
public function removeMissionsDispo(\MissionBundle\Entity\Mission $missionsDispo)
{
$this->missionsDispos->removeElement($missionsDispo);
}
/**
* Get missionsDispos
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getMissionsDispos()
{
return $this->missionsDispos;
}
And here is the interesting part of my mission entity:
/**
* #ORM\ManyToMany(targetEntity="EcoleBundle\Entity\Ecole", inversedBy="missionsDispo")
* #ORM\JoinTable(name="Mission2Ecole",
* joinColumns={#ORM\JoinColumn(name="em_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="me_id", referencedColumnName="id")}
* )
*/
protected $ecolesDispo;
// ...
/**
* Constructor
*/
public function __construct()
{
$this->ecolesDispo = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Add ecolesDispo
*
* #param \EcoleBundle\Entity\Ecole $ecolesDispo
*
* #return Mission
*/
public function addEcolesDispo(\EcoleBundle\Entity\Ecole $ecolesDispo)
{
$this->ecolesDispo[] = $ecolesDispo;
return $this;
}
/**
* Remove ecolesDispo
*
* #param \EcoleBundle\Entity\Ecole $ecolesDispo
*/
public function removeEcolesDispo(\EcoleBundle\Entity\Ecole $ecolesDispo)
{
$this->ecolesDispo->removeElement($ecolesDispo);
}
/**
* Get ecolesDispo
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getEcolesDispo()
{
return $this->ecolesDispo;
}
After all this was created, I was supposed to get a multi selector with the list of all the schools saved in the database (I already added it to the missionType file), but I get absolutely nothing.
I don't really know if I inverted the annotations, or if the "joinTable" part is correct, but I'm completely lost here.
Does anyone have an idea?
Thank you in advance
Just wrong typo "s"? inversedBy="missionsDispo" >>> inversedBy="missionsDispos"
PS. Official doc here
http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/association-mapping.html#many-to-many-bidirectional
I am trying to create a saveAction in zend2 framework using doctrine.
in my PromotionsController i have this action:
public function saveLinkAction() {
$view = new ViewModel();
$salonId = (int) $this->params()->fromPost('salon_id', null);
$addLink = $this->getServiceLocator()->get('Promotions\Model\Link');
$linkData['salon_id'] = $salonId;
$linkData['link'] = '/link/example';
$addLink->setData($linkData);
return $view;
}
This is just for learning how to write data in database.
$addLink = $this->getServiceLocator()->get('Promotions\Model\Link');
This line of code is showing an error and i don't know what is the cause?
Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Promotions\Model\Link
I have created a Link.php in Model directory.
<?php
namespace Link\Model;
use Application\Model\Entity;
use Zend\Form\Annotation;
/**
* #Entity
* #Table(name="promo_link")
*/
class Link extends Entity {
/********** PROPERTIES **********/
/**
* #Id #GeneratedValue(strategy="AUTO") #Column(name="id", type="integer")
* #var int
*
* #Annotation\Exclude()
*/
protected $id;
/**
* #Column(name="salon", type="integer")
* #var int
*
* #Annotation\Options({"label":"Salon"})
* #Annotation\Validator({"name": "Digits"})
*/
protected $salon;
/**
* #Column(name="link", type="string")
* #var string
*/
protected $link;
/**
* #Column(name="start_date", type="string")
* #var string
*/
protected $start_date;
/**
* #Column(name="end_date", type="string")
* #var string
*/
protected $end_date;
}
?>
The error tells you where the problem is:
Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Promotions\Model\Link
Meaning: The ServiceManager doesn't know what Promotions\Model\Link is supposed to be. This key either doesn't exist in your SMConfig or while creating the instance to be returned some error occurs.
TL/DR - Check your ServiceManager Configuration regarding the key Promotions\Model\Link
In order to save your data in your database, you will need the entitymanager.
$link = new Link();
$link->setSalonId($salonId);
$link->setLink('/link/example');
$em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
$em->persist($link);
$em->flush();
You can start with the above code.
However, preferably you would create a repository and a servicelayer. The service should have access to the entityManager and hold your logic. Your controller should have access to this service.
I've got the following class in a Zend Framework project:
<?php
/**
* User's class
*
* This class should be responsible for all
*
* #author Steve Davies
* #copyright 2012
* #version SVN: $Id$
*/
class Api_Admin_Users extends Api_Core
{
/**
* Class Constructor
*
* #return void
*/
public function __construct() {
parent::__construct();
}
/**
* Get User's name
*
* This returns the user's name
*
* #return void
*/
public function new() {
$user = self::_instance()->_em->getRepository('UserManagement\Users')->find('1');
echo $user->getFullName();
}
}
However when I try and use code hinting on $user->getFullName();, it doesn't work.
Using the following trick from here, it works:
/**
* Get User's name
*
* This returns the user's name
*
* #return void
*/
public function new() {
/* #var $user \UserManagement\Users */
$user = self::_instance()->_em->getRepository('UserManagement\Users')->find('1');
echo $user->getFullName();
}
But, I don't want to have to include that comment line everytime I instantiate the object. When I try to move this to the Class definition - or even the method definition, it fails to work.
Can anyone provide an answer for this?
PHP is a dynamic language and as such it is not trivial to infer variable types from static code analysis (like it is in Java for example).
It's especially difficult with factory methods like yours getRepository('UserManagement\Users').
NetBeans currently has no way of knowing how to translate the function argument to the type of returned variable (unless you're satisfied with some parent class from which all subclasses returned by that factory derive). Unfortunatelly vdoc's are the only way to deal with such cases.
Create a method in Api_Admin_Users to access the repository and add the type hint there. This will benefit all methods in the class. As long as the methods in the repository are type-hinted correctly, you're all set.
class Api_Admin_Users extends Api_Core
{
/**
* Class Constructor
*
* #return void
*/
public function __construct() {
parent::__construct();
}
/**
* Get the repository
*
* #return \UserManagement\Users
*/
public static function getRepository() {
return self::_instance()->_em->getRepository('UserManagement\Users');
}
/**
* Get User's name
*
* This returns the user's name
*
* #return void
*/
public function new() {
$user = self::getRepository()->find('1');
echo $user->getFullName();
}
}
I'm using Doctrine ORM 2.
I got the following entity class.
/**
* #Entity
* #Table(name="objects")
*/
class MyObject
{
/**
* #Id
* #GeneratedValue
* #Column(type="integer")
*/
private $id;
/**
* #var Coordinate
*/
private $coordinate;
}
class Coordinate
{
private $x;
private $y;
private $z;
}
I want to implement the 3 coordinate values in a separate class for better handling within php. But within the database I want the 3 values to be included in the database table "objects".
Does anyone know how to achieve this?
Best regards
Edit:
I found a workaround but it's not the nicest.
/**
*
* #var integer
* #Column(type="integer")
*/
private $x;
/**
*
* #var integer
* #Column(type="integer")
*/
private $y;
/**
*
* #var integer
* #Column(type="integer")
*/
private $z;
public function getCoordinate()
{
return new Coordinate($this->x, $this->y, $this->z);
}
public function setCoordinate(Coordinate $coord)
{
$this->x = $coord->getX();
$this->y = $coord->getY();
$this->z = $coord->getZ();
}
The easiest way would be to set that field to use the "object" mapping type.
/**
* #Column(type="object")
*/
private $coordinate;
Then whatever class of object you put in that field, Doctrine will automatically serialise and unserialise when it is inserted and pulled out of the database.
The other way is to make a custom mapping type - http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/cookbook/custom-mapping-types.html. This uses the same method as the object type, but allows you to specify exactly how the object will be converted between PHP and SQL.
If you used this method had a mapping type named coordinate, you would then just declare this for the field:
/**
* #Column(type="coordinate")
*/
private $coordinate;
One drawback and as far as I can see there is no way around it, is that you can only use one database column for the field. So you wouldn't be able to order by x, y or z separately using DQL.
Just configure your getter and setter. Like this in your entity
public function setCoordinate (Coordinate $coordinate) {
$coordinateArr = $coordinate->getArrayCopy();
$this->coordinate = serialize($coordinateArr);
}
public function getCoordinate() {
$coordinateArr = unserialize($this->coordinate);
$coordinate = new Coordinate();
$coordinate->exchangeArray($coordinateArr);
return $coordinate;
}
But if you want sql search, you need use LIKE.