JMS VirtualProperty with Param - api

I have an API backend project build with symfony 2.8, doctrine and JSM Serializer. I have an m-m relation, beetween user and book.
What i want is, when i serilize all my book, have an virtualProperty that told me if a user have a book.
So i need to pass to the funcion of book entity isPossesed() the user object, so i can see if that user is in array of users that have that book.
The problem is that when i serialize with JSM i don't know how pass a param the the method.
Somethings like this:
/**
* #Serializer\VirtualProperty()
*/
public function isPossessed(User $user)
{
/* some code
*/
}
Someone can help me?

Related

Issues with EasyAdmin and Symfony relations One-to-Many

everyone.
I was having issues with Easy Admin and the one-to-many relationship handled by Symfony. The three entities that I currently have in place are User, Products, and Category.
When I place the relationship on Product and Category, I get this error when I try to add a new Category in the admin section of Easy Bundle:
Catchable Fatal Error: Object of class AppBundle\Entity\Product could not be converted to string
Here are what my associates look like int the Product and Category classes, they are basically copied straight out of the Symfony docs.
The Product Category
/**
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $category;
And here is the association on the Category end:
...
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\OneToMany(targetEntity="Product", mappedBy="category")
*/
private $products;
public function __construct()
{
$this->products = new ArrayCollection();
}
The main issues that I believe is going on is that their is no field for category in the products table and this is leaving the Easy Bundle confused, since it seems to be relying on the class properties.
If anyone can make a suggestion on how to fix this, that would be great. Or if you know of a butter admin bundle to work with that might have this issues, that would also be great.
Also, if you have any experience with Easy Admin Bundle, do you suggest just developer just make their own. Because I do see other issue with this Bundle, such as being able to list category names on the Products new form, since Symfony only seems to log the category_id and not the name. I wouldn't be able to list the categories by name, just id numbers. And I would like to list of the different category names.
Any suggestions or help with this would be great.
I just got this error as well. Just add a __toString() magic method to your Product entity:
class Product {
...
public function __toString()
{
return $this->title; // <-- add here a real property which
} // describes your product

executing a sql code for creating a table and database in zend framework

I wrote a sql script and in it I created a table ;
Now I need to know ,how I can execute this script? (with which codes?)
And I have another question : where? where I must write this codes?(which folder in zend project?)
if it is possible for you please explain with an example.thanks
Creating tables in the database
Zend Framework is not supposed to be the one creating the tables, thus, my suggestion is to run those scripts in other environment.
The fastest one is, probably, the very own SQL shell, but you can use another software such as MySQLWorkbench if you are using MySQL.
Once the tables are created, the access to the tables is made this way:
Introduction
When you are using Zend Framework, you are making use of the MVC pattern. I suggest you to read what is that: Wikipedia MVC
If you read the Wikipedia link, you probably know now that the acess to the database is going to be made by the model.
Thus, if you followed the recommended project structure that Zend provides you will have a models folder under your application folder. There, you are supposed to implement the classes that will make access to the DB.
But well... you now know where to locate those classes but you will ask me: how? It's easy if you know where to search. ZF provides an abstract class called Zend_Db_Table_Abstract that has all the methods that will make your life easier talking about interaction with your database's tables. This is the class that your classes should implement.
Example
Let's suppose you've got a page in your website in which you want to show to the user a list of products of your local store. You have a table in your database called "products" in which you have all the useful information such us name, price and availability.
You will have a controller with an action called indexAction() or listAction() this action is prepared to send the data to your view and will look like:
class Store_ProductsController extends Zend_Controller_Action {
public function indexAction(){
//TODO: Get data from the DataBase into $products variable
$this->view->products = $products;
}
}
And your view file will that that products variable and do sutff with it.
But now comes the magic, you will have a class that will access to the database as I've said, it'll be like:
class Model_Store_Products extends Zend_Db_Table_Abstract{
protected $_name = 'products';
public function getAllProducts(){
$select = $this->$select()
->from(array('P'=>$this->_name),
array('id', 'name', 'price', availability));
$productsArray = $this->fetchAll($select);
return $productsArray;
}
}
And ta-da, you have your array of products ready to be used by the controller:
class Store_ProductsController extends Zend_Controller_Action {
public function indexAction(){
$model = new Model_Store_Products();
$products = $model->getAllProducts();
$this->view->products = $products;
}
}
It can be said that, since fetchAll is public function, and our select does basically nothing but set which columns do we want (it doesn't even have a where clause), in this case, it would be easier to call the fetchAll directly from the controller with no where and it will recover the whole table (all columns):
class Store_ProductsController extends Zend_Controller_Action {
public function indexAction(){
$model = new Model_Store_Products();
$products = $model->fetchAll();
$this->view->products = $products;
}
}
Thus, our function in the model is not even needed.
This is the basic information of how to access to the database using Zend Framework. Further information of how to create the Zend_Db_Table_Select object can be found here.
I hope this helps.

OOP web application class design

I'm trying to build a web application using OOP.
In my application i have Courses and Subscribers.
Each Course can have multiple Subscribers (1-N relation).
Now i need to perform some operations on Courses (check some expire dates and perform actions on it's subcribers, send some emails to admins) and, after performing them, perform other operations on each Subscriber (send emails).
I created a Course class and a Subscriber class.
Course class contain course data like title, dates, current status and a group of Subscriber objects (those who partecipate to it).
Subscriber class contains name, last name, subscription status etc.
I have a problem.
My Course class need to be aware of it's Subscribers.
My Subscriber class need to be aware of the Course it belongs to (to exctract data like title, dates...) and aware of how much subscribers are and their status.
How can i redesign my class structure to solve this?
I was thinking about using some kind of observer pattern...
PS. i'm using PHP
No need for a special design pattern, this is a normal bidirectional association. I get from your description that any subscriber only subscribes to one course, otherwise there should be two classes Student and CourseSubscription instead.
How to simply construct the association in PHP:
class Course
{
/**
* #var Subscriber[]
*/
protected $subscribers = array();
public function addSubscriber(Subscriber $subscriber)
{
$this->subscribers[] = $subscriber;
}
}
class Subscriber
{
/**
* #var Course
*/
protected $course;
public function __construct(Course $course, $name, ...)
{
$this->course = $course;
$course->addSubscriber($this);
$this->name = $name;
...
}
}
A subscriber object can only exist with a course, so you pass the course as parameter to the constructor. There the newly created subscriber registers itself for the course.
it sounds like an observer pattern till the point you said
and aware of how much subscribers are and their status.
You need a version of Observer Pattern which expose limited information of its observers.
This point is something like for each subscriber of a course , you need to get all of the subscribers from the course object so you can create a method in Course object which will give you the limited information for each subscriber of the course.

Why Doctrine 2 not have basic validate method that validate if all values fit entities attributes?

I am new with doctrine 2.
Why Doctrine 2 not have basic validate method that validate if all values fit entities attributes?
My question target to understand more how doctrine 2 works and why without say that something wrong in doctine 2. (Mostly because i am new i miss some understanding about doctrine 2 way of design)
Example:
<?php
// entities/User.php
/**
* #Entity #Table(name="users")
**/
class User
{
/**
* #Id #GeneratedValue #Column(type="integer")
* #var int
**/
protected $id;
/**
* #Column(type="string")
* #var string
**/
protected $name;
}
code example of use of build in validate(not need connect to db, only validate #Column(type="integer") ) basic function that not exist in doctrine 2:
$user=new User();
$user->setId('trtr');
$user->setName("goodname");
if($user->validate()){
echo 'ok';
}
else{
echo $user->validateError();
}
//output: id of User should be integer and not string
Thanks
Doctrine ORM assumes that entities you're persisting are in a valid state. That's the only job of the persistence layer, and adding validation to it would just be wrong. If you have entities with invalid data in them, you already have an invalid object graph that should not be saved.
So please keep in mind that if you ever had some API like
$someEntity->isValid();
Then something is probably wrong, since the entity should always be valid, and any dependencies of it should be set at construction time and handled in setters/getters so that the object never reaches an inconsistent state.
The main reason is separation of concerns. Since entities are fairly dumb objects that don't know much about the rest of the world, their ability to do validations is limited to begin with.
For instance, there's no way that your typical entity could validate that a particular property is unique.
That said, if you just want to do basic validations, just do them in the setters.
<?php
class MyEntity {
// ...
/**
* #ORM\Column(length="32")
*/
protected $myProperty;
public function setMyProperty($prop){
if (! is_string($prop))
throw new \InvalidArgumentException('MyEntity::setMyProperty() expects a string!';
if (strlen($prop) > 32)
throw new \LengthException('Argument passed to MyEntity::setMyProperty() is too long!');
$this->myProperty = $prop;
}
}
This approach can be used to enforce data types, lengths, etc. Anything beyond that is better handled somewhere other than inside your entity.
It's not good idea to mix entity and validation, but it make sense to have this rules in entity as annotation and validation logic in separated aspect validator class.
Check how it's done in Spring framework -
http://www.abtosoftware.com/blog/form-validation-using-aspect-oriented-programming-aop-in-spring-framework
and how to implement it with doctrine2 and go -
http://go.aopphp.com/blog/2013/07/21/implementing-logging-aspect-with-doctrine-annotations/

Mapping two tables to one entity in Doctrine2

I'm looking at using doctrine for an application I'm working on - but after reading the documentation I'm having trouble conceptualizing how to represent the database structure we have in terms of entities.
I have many tables which have partner tables which hold translation data like the following....
Where I would like to have one Entity (Navigation Element) which had access to the 'label' field depending on what Language I set in my application. The following from the Doctrine documentation seems to suggest that you need to define one (single) table which is used to persist an entity
http://www.doctrine-project.org/docs/orm/2.0/en/reference/basic-mapping.html
By default, the entity will be
persisted to a table with the same
name as the class name. In order to
change that, you can use the #Table
annotation as follows:
Or do I need to define two entities and link them (or allow the translation table to inherit from the element table).
And what strategy would I use to always insert a language_id clause to the Join (to ensure I'm pulling the right label for the currently set language). Is this something I would define in the entity itself, or elsewhere?
This seems to suit a One-To-Many Bidirectional association. This is the scenario from that page translated to your situation:
/** #Entity */
class NavigationElement
{
// ...
/**
* #OneToMany(targetEntity="NavigationElementTranslation", mappedBy="navigationElement")
*/
private $translations;
// ...
public function __construct() {
$this->translations = new \Doctrine\Common\Collections\ArrayCollection();
}
}
/** #Entity */
class NavigationElementTranslation
{
// ...
/**
* #ManyToOne(targetEntity="NavigationElement", inversedBy="translations")
* #JoinColumn(name="navigation_element_id", referencedColumnName="id")
*/
private $navigationElement;
// ...
}
You could add a getLabel($languageId) method to the NavigationElement entity that searches through the translations to get the correct label:
public function getLabel($languageId) {
foreach($this->translations as $trans) {
if($trans->languageId == $languageId)
return $trans->label;
}
throw new InvalidArgumentException();
}
And you could use the following DQL to ensure you only load the translation you want into the $translations property:
$query = $em->createQuery(
"SELECT ne, net
FROM Entity\NavigationElement ne
JOIN ne.translations net WITH net.languageId = :langId"
);
$query->setParameter('langId', $languageId);
$navigationElements = $query->execute();
This situation sounds like one where you would want to cache aggressively. Make sure you look into Doctrine 2's caching mechanisms too.
Also, internationalization can be handled reasonably well in PHP with gettext if you find join tables for translations start to become unmanageable.
I would also direct anyone who has to tackle this same problem to take a look at the following doctrine extension.
http://www.gediminasm.org/article/translatable-behavior-extension-for-doctrine-2