I want to make a json field of an order to our API. The issue is, that it can't find productNumber.
I've made search of an order with the association:
$this->context = $context;
$criteria = new Criteria([$orderId]);
$criteria->addAssociation(OrderExtension::DSM_INTEGRATION_ORDER);
$criteria->addAssociation('addresses');
$criteria->addAssociation('billingAddress.country');
$criteria->addAssociation('transactions.paymentMethod');
$criteria->addAssociation('deliveries.shippingMethod');
$criteria->addAssociation('deliveries.shippingOrderAddress.country');
$criteria->addAssociation('lineItems.product');
$criteria->addAssociation('lineItems.product.tags');
$criteria->addAssociation('lineItems.product.options');
$criteria->addAssociation('orderCustomer.customer');
$result = $this->orderRepository->search($criteria, $context);
However, the result has no productNumber, when I receive the type "customized-products"
enter image description here
it use uses OrderEntity.
I want the productNumber, when the order is a type "customized-products". I expect, the association is something like "lineItems.product.customized_product", but I have yet to find the correct one.
Note. We use "productOswag_customized_products_templateptions"
To retrieve the product number starting from the order entity, via the order line items, you would have to proceed similar to this:
$criteria = new Criteria();
$criteria->addAssociation('lineItems.product');
$result = $this->orderRepository->search($criteria, $context);
/** #var OrderEntity|null $order */
$order = $result->first();
/** #var OrderLineItemCollection|null $lineItems */
$lineItems = $order->getLineItems();
/** #var OrderLineItemEntity|null $lineItem */
$lineItem = $lineItems->first();
/** #var ProductEntity|null $product */
$product = $lineItem->getProduct();
$productNumber = $product->getProductNumber();
Note the getters might return null at any point, e.g. due to the product having been deleted in the meanwhile or the line item being a discount, so add some checks for that case.
Related
I'm working on a plugin for showing all users completed courses.
But I only get 10 records, when I place the SQL inside my database I get 40+. I think there is a limit or it does only return 1 course from every user.
Any tips?
externallib.php file:
/**
* External Web Service Template
*
* #package specialist_in_websites
* #copyright 2011 Moodle Pty Ltd (http://moodle.com)
* #license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once($CFG->libdir . "/externallib.php");
class specialist_in_websites_users_courses_external extends external_api
{
/**
* Returns description of method parameters
* #return external_function_parameters
*/
public static function hello_world_parameters()
{
return new external_function_parameters(
array()
);
}
/**
* Returns welcome message
* #return string welcome message
*/
public static function hello_world()
{
global $DB;
$sql = 'SELECT u.id as user_id, c.id as course_id, DATE_FORMAT(FROM_UNIXTIME(p.timecompleted),"%Y-%m-%d") AS completed_time
FROM mdl_course_completions AS p
JOIN mdl_course AS c ON p.course = c.id
JOIN mdl_user AS u ON p.userid = u.id
WHERE c.enablecompletion = 1 ORDER BY u.id';
$datas = $DB->get_records_sql($sql);
return (array)$datas;
}
/**
* Returns description of method result value
* #return external_description
*/
public static function hello_world_returns()
{
return new external_multiple_structure(
new external_single_structure(
array(
'user_id' => new external_value(PARAM_INT, 'user id'),
'course_id' => new external_value(PARAM_INT, 'course id'),
'completed_time' => new external_value(PARAM_TEXT, 'Time of Completed'),
)
)
);
}
}
and response code:
string(510) "[{"user_id":2,"course_id":12,"completed_time":null},{"user_id":3,"course_id":10,"completed_time":null},{"user_id":4,"course_id":9,"completed_time":null},{"user_id":5,"course_id":41,"completed_time":null},{"user_id":6,"course_id":14,"completed_time":null},{"user_id":7,"course_id":10,"completed_time":null},{"user_id":8,"course_id":9,"completed_time":null},{"user_id":9,"course_id":9,"completed_time":null},{"user_id":10,"course_id":10,"completed_time":null},{"user_id":11,"course_id":10,"completed_time":null}]"
As stated in the docs the $DB->get_records_*() functions get a hashed array of records, indexed by the first field returned.
So, if you return more than one record with the same user_id field, then they will overwrite the previous record in the array.
Make sure you turn on debugging when developing for Moodle and you will see warning messages about this.
Solutions - either find a different field to be the first field returned (e.g. course_completions.id) or use $DB->get_recordset_sql() and then loop through the results.
Also, do not use the 'mdl_' prefix in your code, as that will break on any site with a different prefix, or if you try to run any behat or unit tests on your site. As stated in the docs, write:
FROM {course_completions} p
JOIN {course} c ON p.course = c.id
etc.
(and don't use AS with tables, as that's not compatible with all DB types)
I have an association like this :
Chatroom >----< User
So a Chatroom can contains multiple users, and a User can belong to multiple Chatrooms.
Now I want to select all the chatrooms that contains a couple of user, and only this couple.
I tried some solutions, like this one :
public function findByUsers($firstUser, $secondUser){
$qb = $this->createQueryBuilder('c');
$qb
->select('c')
->where('c.users LIKE :firstUser')
->andwhere('c.users LIKE :secondUser')
->setParameters(array(
'firstUser' => $firstUser,
'secondUser' => $secondUser
));
return $qb->getQuery()->getResult();
}
But It doesn't work and return me that kind of error :
[Semantical Error] line 0, col 52 near 'users LIKE :firstUser': Error: Invalid PathExpression. Must be a StateFieldPathExpression.
Some users encountering this error resolved it by adding IDENTITY before the query selector, but I don't understand how to apply it in my case.
So, did someone know how I can get all the chatrooms containing my couple of users ?
Thanks a lot !
EDIT : Adding the doctrine relation annotations
User.php
/**
*
* #ORM\ManyToMany(targetEntity="Chatroom", inversedBy="users")
* #ORM\JoinTable(name="chatrooms_users",
* joinColumns={#ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="chatroom_id", referencedColumnName="id")}
* )
*/
private $chatrooms;
Chatroom.php :
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="chatrooms")
*/
private $users;
My final solution was :
public function findByUsers($ids)
{
$count = count($ids);
$qb = $this->createQueryBuilder('chatroom');
$qb->select('chatroom')
->join('chatroom.users', 'u')
->addSelect('COUNT(u) AS HIDDEN ucount')
->groupBy('chatroom.id')
->having('ucount = :count')
->setParameter('count', $count);
foreach ($ids as $key => $id) {
$qb->andWhere(':id' . $key . ' MEMBER OF chatroom.users')
->setParameter('id'.$key, (int) $id);
}
return $qb->getQuery()->getOneOrNullResult();
}
Pass an array of users id (or simply users with some modifications), and the function returns the list of chatrooms that contains only these users
I would like to sort the products by its sku. How would that be possible ?
I tried to add in ProductRepository.php:
...
$queryBuilder = $this->getCollectionQueryBuilder();
$queryBuilder
->innerJoin('product.taxons', 'taxon')
->innerJoin('product.variants', 'variant')
->andWhere('taxon = :taxon')
->setParameter('taxon', $taxon)
;
foreach ($criteria as $attributeName => $value) {
$queryBuilder
->andWhere('product.'.$attributeName.' IN (:'.$attributeName.')')
->setParameter($attributeName, $value)
;
}
$queryBuilder->orderBy('variant.sku');
...
but got:
Cannot select distinct identifiers from query with LIMIT and ORDER BY
on a column from a fetch joined to-many association. Use output
walkers.
Finally what I did: Sorted the products just before output in a custom twig function:
macros.html.twig
{% set products = skusort(products) %}
In my SkusortExtenstion.php (as of PHP 5.3)
$product->getIterator()->uasort(function($a, $b){
return $a->getMasterVariant()->getSku() > $b->getMasterVariant()->getSku();
});
return $product;
Was afraid of performance issue as there's a lot of products but seems to be very fast.
Another way is to reload method getPaginator() of class Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository. In that case we must instantinate DoctrineORMAdapter with $useOutputWalkers flag (the latest constructor argument).
So, put the folowing code in your ProductRepository.php:
/**
* {#inheritdoc}
*/
public function getPaginator(QueryBuilder $queryBuilder)
{
return new Pagerfanta(new DoctrineORMAdapter($queryBuilder, true, true));
}
I need to select all products, but currently my code is:
$products = $category->getProducts((int)($params['cookie']->id_lang), 1, ($nb ? $nb : 10),NULL,NULL,false,true,true /*Random*/, ($nb ? $nb : 10));
How can I reshape this so that the products do not depend on a $category. Is there a getProducts() function that is not child of $category?
Yes, in products class there is a function getProducts, which can get you all the products in your shop. You can call that function as below:
$productObj = new Product();
$products = $productObj -> getProducts($id_lang, 0, 0, 'id_product', 'DESC' );
First argument is your site current id language, second is for start, used for pagination purpose, which we kept 0. Third argument is for limit, which limits the number of products to fetch. We also kept it 0, so that no limit clause is applied. Fourth is for order by , and fifth is order way, which you can keep as you need.
Note: This code is not tested, it is just to give you idea. You will need to adjust the arguments according to your needs and where you use this code.
Thank you
please, check function description in classes/Product.php:
/**
* Get all available products
*
* #param integer $id_lang Language id
* #param integer $start Start number
* #param integer $limit Number of products to return
* #param string $order_by Field for ordering
* #param string $order_way Way for ordering (ASC or DESC)
* #return array Products details
*/
public static function getProducts($id_lang, $start, $limit, $order_by, $order_way, $id_category = false,
$only_active = false, Context $context = null) {...}
Regards
I hava relations Many-to-Many with Product entity and Feature entity
Product entity:
/**
* #ORM\ManyToMany(targetEntity="Feature")
* #ORM\JoinTable(name="Product_Feature",
* joinColumns={#ORM\JoinColumn(name="Product_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="Feature_id", referencedColumnName="id")}
* )
*/
private $features;
Feature entity:
/**
* #ORM\ManyToMany(targetEntity="Product", mappedBy="features")
* #ORM\OrderBy({"position" = "ASC"})
*/
private $products;
ProductRepository.php:
public function updateFeatures($id, $featuresIds)
{
return $this->getEntityManager()->createQueryBuilder()
->update('TestCatalogBundle:Product', 'p')
->set('p.features', ':features')
->where('p.id = :id')
->setParameter('features', $featuresIds)
->setParameter('id', $id)
->getQuery()
->getResult();
}
But when I call updateFeatures I get error:
features = :features': Error: Invalid PathExpression.
StateFieldPathExpression or SingleValuedAssociationField expected
How can I update Product_Feature table? Also I can't delete all features from Product_Feature by product's id.
I changed my controller in next way:
$em = $this->getDoctrine()->getEntityManager();
$features = $em->getRepository('TestCatalogBundle:Feature')->findBy(array('id' => $featureIds));
$product = $em->getRepository('TestCatalogBundle:Product')->find($id);
$product->getFeatures()->clear();
foreach ($features as $feature) {
$product->addFeature($feature);
}
$em->persist($product);
$em->flush();
But if I use native sql I need 2 queries for deleting features and insert new features. But here I need 2 select queries. Maybe I made this task wrong?
You're doing it the wrong way. You should read this chapter of the documentation: Working with associations. You should add an "inversedBy" keyword in the $features field of the Product class.
When you have a bi-directional many-to-many relation, the usual way to do this is:
$product->getFeatures()->add($feature); // Or $product->setFeatures($features);
$feature->getProducts()->add($product);
$em->persist($product);
$em->persist($feature);
$em->flush();