Doctrine - Get sells between two dates - php

Got this entity:
/**
* #ORM\Table(name="shop_payment_details")
* #ORM\Entity(repositoryClass="Acme\ShopBundle\Entity\PaymentRepository")
*/
class Payment extends ArrayObject
{
/**
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*
* #var integer $id
*/
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Acme\UserBundle\Entity\User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
**/
protected $user;
/**
* #ORM\ManyToOne(targetEntity="Acme\ShopBundle\Entity\Item")
* #ORM\JoinColumn(name="item_id", referencedColumnName="id")
**/
protected $item;
/**
* #ORM\Column(name="date", type="datetime", nullable=true)
*/
protected $date;
/**
* #ORM\Column(name="amount", type="float", nullable=true)
*/
protected $amount;
I need to file a sales table between two dates he selected.
The table must contain all days between two dates and reference codes of the objects in the store.
For example:
How can I get it? Can do it just with Doctrine or i must use PHP to build that table?

It is possible, what you need is the orX() function supplied by Doctrine-ORM
You will need to create two expressions using the function exp() then you can put both expressions in the orX() statement to get the wanted results.
For the expressions you need to define you will need the function gt()/lt() - greater than/ lower than
This will give you the possibility to compare two dates
For a further reference check this link:
https://doctrine-orm.readthedocs.org/en/latest/reference/query-builder.html#high-level-api-methods
PS:
For readabilty and logic it should be easier to create the expression before inserting them into your query:
$exp1 = $qb->expr()->gt('..', '?value');
$exp2 = $qb->expr()->gt('..', '?value2'),
...
$qb->where($qb->expr()->orX($exp1, $exp2));
Notice that orX can aggregate an unlimited number of expressions

Create a custom DQL (in a repository I suggest) to retrieve all payments where payment.date => yourSmallerUserDate and payment.date <= yourBiggerUserDate.
The result will be all payments between your two dates.
Within your logic you build a table with a row per day between your two dates. And whenever you have a date in your result matching your row date add it to your output.

Related

Symfony 3 and Doctrine Link Table

My goal is to create Term Tables for translations in Symfony3 and Doctrine.
One Table (TERMS) should contain a Primary Key Id and the Term.
The second Table (TermLink) should contain the Link between Term and its translation which is also a Term, like: TermId | TranslationId - Those are foreign keys of the of the same primary key - Term ID Field.
There are multiple approaches to achieve this that are described: Doctrine Documentation but none of them fits my needs.
Here are my actual Entities that I would like to implement:
Term Table:
/**
* Translation Term
*
* #ORM\Table(name="translation_term")
* #ORM\Entity‚
*/
class TranslTerm
{
/**
* #var int
*
* #ORM\Column(name="term_id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $termId;
/**
* #var string
*
* #ORM\Column(name="term", type="string", length=128)
*/
private $term;
}
Link Table:
/**
* Translation Link - One To Many/JoinTable -
*
* #ORM\Table(name="translation_link")
* #ORM\Entity‚
*/
class TranslLink
{
private $id;
private $termId;
private $translationId;
}
Any help would be appreciated, thank you in advance.
Firstly look here: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html OR https://symfony.com/doc/current/doctrine/associations.html
Secondly here's something that should be a good start:
class TranslLink
{
private $id;
/**
* #ORM\ManyToOne(targetEntity="Terms", mappedBy="trans_link")
*/
private $termId;
/**
* #ORM\ManyToOne(targetEntity="Translations", mappedBy="trans_link")
*/
private $translationId;
}
PUBLIC HEALTH WARNING about the above:
straight outta the top of my head, will not work out the box and might be off. But the principle of what you want should be able to be derived from there.

Doctrine 2 - Indirect one to many association

After a lot of searching for indirect associations, I only came up with this question. What I'd like to know is the exact opposite of that question, so I'm building up on it. Given the same entities:
class Continent {
/**
* #ORM\Id
* #ORM\Column(type="integer", name="id")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Country", mappedBy="continent")
*/
private $countries;
}
class Country {
/**
* #ORM\Id
* #ORM\Column(type="integer", name="id")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Continent", inversedBy="countries")
* #ORM\JoinColumn(name="continent_id", referencedColumnName="id")
*/
private $continent;
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\City", mappedBy="country")
*/
private $cities;
}
class City {
/**
* #ORM\Id
* #ORM\Column(type="integer", name="id")
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Country", inversedBy="cities")
* #ORM\JoinColumn(name="country_id", referencedColumnName="id")
*/
private $country;
}
Is there any way to have a collection of all cities in a continent, without having to build a custom query every time, with a field in the same fashion as the countries collection, possibly via annotations or maybe dynamic mapping?
The only way I could think of is by overriding the find... methods in the Repository - which I'm not sure how exactly I could achieve adding the field - and then either looping over the countries and adding their cities to a new collection, or using a custom query entirely.
First a comment about your mapping. Your mapping is wrong here:
inversedBy="countries" not inversedBy="country" and probably you want a column named continent_id instead of continentt_id
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Continent", inversedBy="countries")
* #ORM\JoinColumn(name="continent_id", referencedColumnName="id")
*/
private $continent;
And here it should be inversedBy="cities" not inversedBy="city":
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Country", inversedBy="cities")
* #ORM\JoinColumn(name="country_id", referencedColumnName="id")
*/
private $country;
Consider using validation for your entity model, the validation tool that ships with doctrine ORM will help you to get these things correct.
You can get such a result set by inner joining the countries with a certain continent.
Inside your CityRepository:
use Doctrine\ORM\Query\Expr\Join;
//...
public function findCitiesByContinent($params){
$queryBuilder = $this->createQueryBuilder('c')
->innerJoin('c.country', 'cc', Join::WITH, 'cc.continent = :continent')
->setParameter('continent', $params['continent']);
$query = $queryBuilder->getQuery();
return $query->getResult();
}
You can reuse the query and just pass a different value for continent to your $params array each time you want the cities for a different continent.
This code is not tested, but I think it should work. Just leave a comment if you run into issues while testing this.
You can also add methods like #Edwin suggested, but you have to realize that it will eagerly load all entities. This is killing for performance if you have a huge amount of rows in your tables (a lot of cities and countries). That is why a query in your repository would be better.
Alternatively you can do this inside your entities by using criteria and collection filtering. You can read on how to do this here in the documentation chapter 8.8. Filtering Collections
The advantage of using a filter is also well explained in the documentation:
If the collection has not been loaded from the database yet, the filtering API can work on the SQL level to make optimized access to large collections.

symfony2 - ManyToMany with duplicate rows

I currently have to Entities in my application:
Page
Block
A Page can have many Blocks, which are shared across many Pages, so it is quite obvious that the relation is a ManyToMany. However, I need to be able to add the same Block twice (or more) to the same Page. Doctrine creates the "page_block" join table automatically, but with page_id and block_id both as Primary Keys, therefore adding a duplicate throws an error.
Is it possible, without adding an additional Entity, to tell doctrine to allow duplicates on the Page--Block relation ?
Well, I'm not sure about that behavior in doctrine, but if that is the case, then you can do something that I almost always do. Represent the ManyToMany relation as two OneToMany-ManyToOne. You must create your own PageBlock entity and configure it's foreign keys.
class Page{
/**
* #var array
*
* #ORM\OneToMany(targetEntity="PageBlock", mappedBy="page", cascade={"all"})
*/
private $pageBlocks;
}
class Block{
/**
* #var array
*
* #ORM\OneToMany(targetEntity="PageBlock", mappedBy="block", cascade={"all"})
*/
private $pageBlocks;
}
class PageBlock{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var \stdClass
*
* #ORM\ManyToOne(targetEntity="Page", inversedBy="pageBlocks")
* #ORM\JoinColumn(name="id_page", referencedColumnName="id")
*/
private $page;
/**
* #var \stdClass
*
* #ORM\ManyToOne(targetEntity="Block", inversedBy="pageBlocks")
* #ORM\JoinColumn(name="id_block", referencedColumnName="id")
*/
private $block;
}
As you can see the primary key remains as ID, so problem resolved. I say almost always do because this is how I do it if I need an extra attribute in the relation(almost always it happens). I suspect that could be a way of do it with the ManyToMany annotation, but there is no difference with this approach.
Hope this help you.

Symfony Doctrine2: How do I work with limited one-to-many relation?

I have an Entity Employee
class Employee
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\OneToMany(targetEntity="WorkHour", mappedBy="employee", cascade={"persist", "remove"})
*/
private $workHours;
}
and WorkHour
class WorkHour
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Profile
*
* #ORM\ManyToOne(targetEntity="Employee", inversedBy="workHours")
* #ORM\JoinColumn(name="employee_id", referencedColumnName="id")
*/
protected $profile;
/**
* #var integer
*
* #ORM\Column(name="weekday", type="smallint")
*/
private $weekday;
/**
* #var \DateTime
*
* #ORM\Column(name="hour_from", type="time")
*/
private $hourFrom;
/**
* #var \DateTime
*
* #ORM\Column(name="hour_to", type="time")
*/
private $hourTo;
}
Now I'm confused when I'm going to add addWorkHour(), removeWorkHour() methods.
Usually one-to-many relation you can add as many relations as you want, but in my case, one employee can have only up-to-7 workHours, and for a specified weekday (from 0 to 6) can have only one (or no) record.
So I think what I need is something methods like,
public function setWorkHourByWeekday($hour_from, $hour_to, $weekday);
public function getWorkHourByWeekday($weekday);
And after set workhours for an employee, when you persist that employee,
I want doctrine delete those workhours that are no longer exist, update those workhours that are changed, and create new workhours that not exist before.
How can I implement this? Should I write these logic in class Employee or its Repository, or a WorkHourManager class?
I think WorkDay is a probably better name for your entity, so i'll use that :).
$workdays= $employee->getWorkDays();
$workdays->clear(); // Clear existing workdays
// Add new workdays
foreach(...) {
$workday = new WorkDay();
$workday ->setWeekday(0); // You could use a constant like `WorkDay::MONDAY`
$workday ->setStart('09:00');
$workday ->setEnd('17:00');
$workdays->add($workday);
}
Set orphanRemoval=true on $workHours to remove WorkHours without an Employee.
The setWeekday method in your Workday entity should throw an exception when an invalid weekday is supplied (other than 0-6). You could also use a Weekday value object in combination with Doctrine embeddables.
I'd go for a service or manager class in this case.
My advice is not to drop old workhours, maybe you don't needed now, but this data could be useful in the future. So, will be better just add workHours to the Employee and make a report the get the last workHours for today. About validations, there is a lot of ways of doing that. If you are working with forms and the rules are complex maybe you need read http://symfony.com/doc/current/cookbook/validation/custom_constraint.html , but maybe you can find alternatives in the action controller or the entity class itself.

Doctrine Array Hydration with db column names keys

Using the latest Doctrine (2.4)
Given this simple entity:
class Booking
{
/**
* #var integer
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var \DateTime
* #ORM\Column(name="from_date", type="datetime", nullable=true)
*/
protected $fromDate;
/**
* #var float
* #ORM\Column(name="deposit_price", type="float", nullable=true)
*/
protected $depositPrice;
}
If I do a simple ORM query with array Hydration the result I get back is something like this:
[
'id'=>1,
'depositPrice'=>100.5,
'fromDate'=>'2012-01-01'
]
Is there a simple way to Hydrate using the actual column fields? To get a result like this:
[
'id'=>1,
'deposit_price'=>100.5,
'from_date'=>'2012-01-01'
]
There are 3 solutions:
You can create custom hydration and do in it what you want.
You can use Native query and Result Set Mapping.
You can just rename your fields in your Entity class.
I would prefer 3rd case. It is so easy to rename your fields. You can do it on all files with regular expressions (if it is supported by your IDE).

Categories