Request in symfony return me some weird data - sql

I wanted to get data from a bdd, like I always do I create a method for add specific condition to my request, but you'll see after I tried many things else.
Here the request:
/**
* #return CongesEchangeRtt[] Returns an array of CongesEchangeRtt objects
*/
public function findByDate($agents, $date) {
return $this->createQueryBuilder('c')
->andWhere('c.eLogin IN (:val)')
->andWhere('c.eDateJour LIKE :date')
->setParameter('val', $agents)
->setParameter('date', $date . "%")
->getQuery()
->getResult()
;
}
This request had to return me every data that match with condition, right?
But we're wrong, lol, IDK why but this is not what it do, in fact I tried it, in pur SQL, in "phpMyAdmin" and it worked so I think that my problem come from symfony, anyway this request return me only one object per user (agents). Datas I get are correct, but I don't get every data that match for each user... I lost my mind here in first, but it's only the beginning.
After that I tried a simple "findBy" method with the user array in parameter, I got every date of every user in my array, but it's to mutch, I want to get only thoses with the correct dates, I mean those who are in the 'actual' month that I display in the front, 'actual' is relative.
So I generate an array with every date of the month and tried this:
findBy(["login" => $myUserArray, "dates" => $myArrayOfDates]);
You now what I got? Something weird! Right!
Duplicate content... But some that are not in the bdd, I mean, here an example:
I have many data/lines in this table that look like this:
login|date(vacation)|presence|absence|comment
so:
"xxxx.xxxx"|"2021-05-14"|etc
"xxxx.xxxxx"|"2021-05-24"|etc
And I got this in my PHP:
"xxxx.xxxx"|"2021-05-14"|etc
"xxxx.xxxx"|"2021-05-14"|etc
I have the right number of data, but they're all the same...

The problem was caused by the difference between my entity and the Table in the bdd.
'Cause this is a part of an old system, and idk why but the dev how code it add two PRIMARY KEY to this table, and when I generate my entity with symfony he didn't created it as the table was. he forgot one PRIMARY KEY, maybe beaucause it's a special case, normaly i read that a table only need one PRIMARY KEY, anyway, i fixed it by adding the right annotation to my paramater that represent the field in the database that was the second PRIMARY KEY, after that the problem was solved.
I change this :
/**
* #var \Datetime
*
* #ORM\Column(name="e_date_jour", type="date", nullable=false, options={"default"="0000-00-00"})
*/
private $eDateJour = '0000-00-00';
To this :
/**
* #var string
*
* #ORM\Column(name="e_date_jour", type="string", nullable=false, options={"default"="0000-00-00"})
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $eDateJour = '0000-00-00';
I change the get and set fonction too, 'cause symfony specified the return's type by himself when you generate the entity, it's a good practice btw.

Related

Compare two database fields in extbase repository

I am using TYPO3 8. In my extension I have a database table "company" in which I store for each company the total number of places (number_places) and the number of occupied places (occupied_places).
Now I want to limit the search to companies which have available places left.
In MySQL it would be like this:
SELECT * FROM company WHERE number_places > occupied_places;
How can I create this query in the extbase repository?
I tried to introduce the virtual property placesLeft in my model but it did not work.
I don't want to use a raw SQL statement as mentioned below, because I already have implemented a filter which uses plenty of different constraints.
Extbase query to compare two fields in same table
You can do it like this in your repository class, please note the comments inside the code:
class CompanyRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
{
public function findWithAvailablePlaces(bool $returnRawQueryResult = false)
{
// Create a QueryBuilder instance
$queryBuilder = $this->objectManager->get(\TYPO3\CMS\Core\Database\ConnectionPool::class)
->getConnectionForTable('company')->createQueryBuilder();
// Create the query
$queryBuilder
->select('*')
->from('company')
->where(
// Note: this string concatenation is needed, because TYPO3's
// QueryBuilder always escapes the value in the ExpressionBuilder's
// methods (eq(), lt(), gt(), ...) and thus render it impossible to
// compare against an identifier.
$queryBuilder->quoteIdentifier('number_places')
. \TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder::GT
. $queryBuilder->quoteIdentifier('occupied_places')
);
// Execute the query
$result = $queryBuilder->execute()->fetchAll();
// Note: this switch is not needed in fact. I just put it here, if you
// like to get the Company model objects instead of an array.
if ($returnRawQueryResult) {
$dataMapper = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper::class);
return $dataMapper->map($this->objectType, $result);
}
return $result;
}
}
Notes:
If you have lots of records to deal with, I would - for performance reasons - not use the data mapping feature and work with arrays.
If you want to use the fluid pagination widget, be sure you don't and build your own pagination. Because of the way this works (extbase-internally), you'd get a huge system load overhead when the table grows. Better add the support for limited db queries to the repository method, for example:
class CompanyRepository extends \TYPO3\CMS\Extbase\Persistence\Repository
{
public function findWithAvailablePlaces(
int $limit = 10,
int $offset = 0,
bool $returnRawQueryResult = false
) {
// ...
$queryBuilder
->setMaxResults($limit)
->setFirstResult($offset);
$result = $queryBuilder->execute()->fetchAll();
// ...
}
}
I think you cant do this using the default Extbase Query methods like equals() and so on. You may use the function $query->statement() for your specific queries like this.
You also can use the QueryBuilder since TYPO3 8 which has functions to compare fields to each other:
https://docs.typo3.org/typo3cms/CoreApiReference/latest/ApiOverview/Database/QueryBuilder/Index.html#quoteidentifier-and-quoteidentifiers
It's fine to use this QueryBuilder inside Extbase repositories. After this you can use the DataMapper to map the query results to Extbase models.
In case of using "statement()" be aware of escaping every value which may cause any kind of SQL injections.
Based on the current architecture of TYPO3, the data structure is such that comparing of two tables or, mixing results from two tables ought to be done from within the controller, by injecting the two repositories. Optionally, you can construct a Domain Service that can work on the data from the two repositories from within the action itself, in the case of a routine. The service will also have to be injected.
Note:
If you have a foreign relation defined in your table configuration, the results of that foreign relation will show in your defined table repository. So, there's that too.

Magento – Programmatically reorder multiple orders by cronjob

I would like to programmatically reorder specific orders by cronjob and send an order confirmation by mail. I have a simple php file in my root directory which is triggered by a cronjob every once in a while:
<?php
include_once 'app/Mage.php';
Mage::app();
//some existing order ids
$orderIds= array('911', '1106', '926');
foreach($orderIds as $orderId){
Mage::unregister('rule_data');
Mage::getModel('adminhtml/session_quote')
->clear();
/* #var Mage_Sales_Model_Order $order */
$order = Mage::getModel('sales/order')->load($orderId)
->setReordered(true);
/* #var Mage_Sales_Model_Quote $quote */
$quote = Mage::getModel('sales/quote')
->setStoreId($order->getStoreId())
->assignCustomer(Mage::getModel('customer/customer')->load($order->getCustomerId()))
->setUseOldShippingMethod(true);
/* #var Mage_Adminhtml_Model_Sales_Order_Create $model */
$model = Mage::getModel('adminhtml/sales_order_create')
->initFromOrder($order)
->setQuote($quote);
/* #var Mage_Sales_Model_Order $newOrder */
$newOrder = $model->createOrder();
$newOrder->setQuoteId($quote->getId())
->sendNewOrderEmail();
$model->getSession()
->clear();
}
It seems to work so far, new orders are placed and the emails are sent. But the problem I experienced is that the customer in the new orders is always the one from the first old order (in this case the order with the id 911). Of course, this also affects the order confirmation emails, so they're all sent to the same email address... Also, the order items seem to add up in the cart, so the last order which is reordered contains all the order items of the previous orders... What am I doing wrong?
I appreciate every help I can get! Thank you!
There are two problems:
You are calling Mage::getModel('adminhtml/session_quote')->clear(),
which gets a new instance of the session and tries to clear that.
But the Mage_Adminhtml_Model_Sales_Order_Create class gets the
session by using Mage::getSingleton('adminhtml/session_quote'),
which always gets the same instance from the Magento registry. So
you are trying to clear another session instance.
Even if you would try to clear the right session instance from the
Magento registry by using:
Mage::getSingleton('adminhtml/session_quote')->clear(), there would
still be a problem. As the Mage_Adminhtml_Model_Session_Quote class
doesn't define this method, it ultimately calls
Varien_Object->unsetData(), which only does this: $this->_data = array();
But the information in the Mage_Adminhtml_Model_Session_Quote class
is stored in the $_quote, $_customer, $_store and $_order properties,
so they don't actually get cleared, but persist.
I solved the problem by deleting the Mage_Adminhtml_Model_Session_Quote instance in Magento registry before each of the orders, so that it needs to create a new one for each order.
Just add this at the beginning of the loop:
Mage::unregister('_singleton/adminhtml/session_quote');
Cheers! ;)

Symfony Doctrine : Use real tablename in request

I'm using doctrine in a symfony project and I have a little problem.
I have a "Character" entity, and a "Equipment" entity.
The character can only wear 5 equipment on him.
But he could buy some other equipment, to put in his inventory. This way, he can switch one of his equipment for another one in his inventory.
So, in my "Character" entity I have :
/**
* #ORM\ManyToMany(targetEntity="rs\WelcomeBundle\Entity\Equipment", cascade={"persist"})
* #ORM\JoinTable(name="InventoryCharacter")
*/
private $inventory;
/**
* #ORM\ManyToMany(targetEntity="rs\WelcomeBundle\Entity\Equipment", cascade={"persist"})
* #ORM\JoinTable(name="EquipmentWearCharacter")
*/
private $equipementsWear;
The problem is : I want to get the list of equipment that the character don't already buy.
In fact I want to get the list of equipment that are in the complete list (findAll in equipment) but NOT IN the list of character inventory.
I try to do a request but doctrine doesn't know the table "InventoryCharacter" because there is no corresponding entity class...
So I can't do "Select p from InventoryCharacter..."
How I can do ? I want to specify to search in the real database, not in the list of entity class...
The 'ManyToMany' relationship with Doctrine is very transparent. You can not do anything more than getting entity list for the one or the other.
If you ever find yourself needing to access the 'Relation' table, either to add extra data about the relation (e.g. time created) or to apply a filter (e.g. recently created), you need to create that relationship entity yourself. i.e. CharacterInventory. and set up OneToMany and ManyToOne relationships between the 3 entities.
Hope this help.
+++++++++++Edited+++++++++++
If you simply want to retrieve all equipments user can purchase (i.e. not purchased yet), you actually dont need to create the middle entity CharacterInventory:
/**
* Add this to the Equipment Entity
*
* #ORM\ManyToMany(targetEntity="rs\WelcomeBundle\Entity\Character", cascade={"persist"})
* #ORM\JoinTable(name="InventoryCharacter")
*/
private $characters;
Then you can use this to query what you want:
$dql = "SELECT s FROM rs\WelcomeBundle\Entity\Equipment s LEFT JOIN s.characters ct WHERE ct != :character";
$found = $em->createQuery($dql)
->setParameter('character', $characterEntityObject)
->getResult();

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

kohana ORM question

i am using kohana ORM in order to get some results from the database. My problem is: even though i have consulted the documentation, i can't find a way to select only the column i am interested in. To be more explicit, i have:
$sale_stock = Model::factory('product_type')
->where('product_type_id','=', $id )
-> find_all();
var dumping it, it selects me all the "SELECT product_type.* from product_type where etc".
But i want to select only the 'stock' field from the salestock table. doing find('stock') instead find_all() returns a weired object... Where am i wrong, and how can i actually select only the column 'stock' using kohana orm?
thank you!
ORM methods find() and find_all() always select all table columns, so there is two ways to get specified fields:
Load full table rows and get columns
from it:
$sale_stock = Model::factory('product_type')
->where('product_type_id','=', $id )
-> find_all();
// get array of id=>stock values
$columns = $sale_stock->as_array('id', 'stock');
Create special method in model using
Query Builder:
// model Model_Product_Type
public function get_stocks($product_type_id)
{
return DB::select(array('stock'))
->from($this->_table_name)
->where('product_type_id', '=', $product_type_id)
->execute($this->_db);
}
I realise this isn't exactly what you're looking for, but I've pulled the following from the Kohana documentation ...
$articles = ORM::factory('article')->select_list('id', 'title');
foreach ($articles as $id => $title)
{
// Display a list of links
echo html::anchor('articles/'.$id, $title);
}
// Display a dropdown list
echo form::dropdown('articles', $articles);
You could think of it as a discount, two fields for the price of one.
It's common practice for ORMs to return a 'non-standard' object when partial model or merged model fields are requested. This prevents confusing operations using the original object (ie. how do you save an object when it contains only 2 of 8 fields, plus maybe some fields from another model?).
If you print_r the object, and give me an indication of how that looks ... it might be just what you want.
I know this is an old question, but i found maybe easier solution:
$sale_stock = ORM::factory('product_type')
->where( 'product_type_id','=', $id )
->find_all();
die($sale_stock->stock);