Filter Productcollection by sku - collections

I tried to get all products with suitable skus in Magento 2.
What i did:
$currentSku = $_product->getSku();
$currentSku = substr($currentSku, 0, 3);
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
/** #var \Magento\Catalog\Model\ResourceModel\Product\Collection $productCollection */
$productCollection = $objectManager->create('Magento\Catalog\Model\ResourceModel\Product\Collection');
$productCollection->addFieldToFilter('sku', array('like' => ''.$currentSku.' %'));
/** Apply filters here */
$productCollection->load();
The collection is always empty but there are suitable products.
I tried to filter the collection by name and this worked.

There is a space after your SKU.
Change it to
$productCollection->addFieldToFilter('sku', array('like' => ''.$currentSku.'%'));

Try this,
public function __construct(
\Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
....
) {
$this->_productCollectionFactory = $productCollectionFactory;
...
}
public function getProducts($currentSku)
{
/** #var $collection \Magento\Catalog\Model\ResourceModel\Product\Collection */
$collection = $this->_productCollectionFactory->create()
->addAttributeToSelect('*')
->addAttributeToFilter('status', array('eq' => 1))
->addAttributeToFilter('sku', array('like' => $currentSku.'%'))
->addStoreFilter()
->load();
return $collection;
}

Related

Method not found in entity Paginator from doctrine bundle

I'm trying to clean up some code done in a messy way and right now I'm having trouble with doctrine's paginator.
When I'm accessing a page that handle paginator in order to show all different articles of my blog I'm getting this error:
Neither the property "id" nor one of the methods "id()", "getid()"/"isid()"/"hasid()" or "__call()" exist and have public access in class "Doctrine\ORM\Tools\Pagination\Paginator".
In doctrine vendor bundle those methods are not set but my entity have them and I know that it is forbidden to edit a vendor file. I'm missing something because I don't know if I should extend my paginator entity and add those missing methods or is there a little bit more to do ?
I just started symfony and I know that my bases are not enough to understand it all by myself.
Thank you very much for you time and attention.
Here is my Article controller for route category:
/**
* #Route("/categorie/{id}", name="categorie")
*
* #param Request $request
* #param Helper $helper
* #param AuthorizationCheckerInterface $authChecker
* #param DocumentCategory $categorie
* #param TwitterService $twitterService
*
* #return RedirectResponse|Response
*/
public function categorie(
Request $request,
Helper $helper,
AuthorizationCheckerInterface $authChecker,
DocumentCategory $categorie,
TwitterService $twitterService
) {
if (!$authChecker->isGranted('IS_AUTHENTICATED_FULLY')
&& !$authChecker->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
return $this->redirectToRoute('login');
}
$page = (int) ($request->get('page'));
if (0 === $page) {
$page = 1;
}
$userType = $this->getDoctrine()->getRepository('App:User')
->getManagerExpertCollabo($this->getUser());
$articleAlaUneListe = [];
$articleIdListe = $helper->getArticleIdAuth($authChecker);
$articleListe = $this->getDoctrine()
->getRepository('App:Document')
->getPage(
self::ITEM_PER_PAGE * ($page - 1),
self::ITEM_PER_PAGE,
'document.dateCreated',
'DESC',
'(documentCategory.id = \''.$categorie->getId().'\' and '.$helper->baseRequestArticle().')',
7,
[],
$articleIdListe
);
[$articlePopulaireListe, $categorieListe, $totalPage] = $this->getPopularArticleList(
$articleListe,
$helper,
$articleIdListe
);
$articlesList->getDocuments();
$feedData = $twitterService->getTwitterFeed();
return $this->render('article/list.html.twig', [
'pageClass' => 'backoffice withFooterLarge dashboard',
'totalPage' => $totalPage,
'page' => $page,
'feedData' => $feedData,
'categorieListe' => $categorieListe,
'categorie' => $categorie,
'articleAlaUneListe' => $articleAlaUneListe,
'articlePopulaireListe' => $articlePopulaireListe,
'articleListe' => $articleListe, ]);
}
Here is the document entity for categories field:
/**
* #ORM\JoinTable(name="ht_lk_document_category"),
* #ORM\ManyToMany(targetEntity="App\Entity\DocumentCategory", inversedBy="documents")
*/
private $categories;
/**
* #return Collection|array<DocumentCategory>
*/
public function getCategories(): Collection
{
return $this->categories;
}
public function setCategories($category): self
{
$this->categories = $category;
return $this;
}
Here is the DocumentCategory entity :
/**
* #ORM\ManyToMany(targetEntity="App\Entity\Document", mappedBy="categories")
*/
private $documents;
/**
* #return Collection|Document[]
*/
public function getDocuments(): Collection
{
return $this->documents;
}
Here is the Document Repository :
public function getPage($first_result, $max_results, $orderby, $direction, $criteria, $documentType = null, $searchWordArray = [], $articleIdListe = '')
{
$qb = $this->createQueryBuilder('docArticle');
$qb->select('docArticle')
->addSelect('documentCategory', 'documentCategory')
->addSelect('user', 'user')
/*
if(sizeof($searchWordArray) > 0){
$fieldIndice = 1;
foreach($searchWordArray as $searchWord){
$qb->andWhere('(document.name_fr LIKE ?'.$fieldIndice.' or document.name_en LIKE ?'.$fieldIndice.' or document.content_fr LIKE ?'.$fieldIndice.' or document.content_en LIKE ?'.$fieldIndice.')');
$qb->setParameter($fieldIndice++, '%'.$searchWord.'%');
}
} */
->leftJoin('docArticle.categories', 'documentCategory')
->leftJoin('docArticle.author', 'user')
->setFirstResult($first_result)
->setMaxResults($max_results);
if (!empty($criteria)) {
$qb->where('('.$criteria.')');
}
if (!empty($orderby)) {
$qb->orderBy($orderby, $direction);
}
$pag = new Paginator($qb->getQuery());
$qb->setFirstResult(0);
$qb->setMaxResults(PHP_INT_MAX);
$sql = $qb->getQuery()->getSql();
if ('()' !== $articleIdListe) {
$qb->where('(docArticle.id IN '.$articleIdListe);
}
$compte = \count($qb->getQuery()->getScalarResult());
return ['page' => $pag, 'compte' => $compte];
}
And finally here is the Document Category Repository :
/**
* #param $first_result
* #param $max_results
* #param $orderby
* #param $direction
* #param $criteria
* #param int|null $documentType
* #param array $searchWordArray
* #param string $articleIdListe
*
* #return array
*/
public function getPage(
$first_result,
$max_results,
$orderby,
$direction,
$criteria,
$documentType = null,
$searchWordArray = [],
$articleIdListe = ''
) {
$qb = $this->createQueryBuilder('document');
$qb->select('document')
->addSelect('documentCategory', 'documentCategory')
->addSelect('user', 'user')
->addSelect('documentType', 'documentType');
if (\count($searchWordArray) > 0) {
$fieldIndice = 1;
foreach ($searchWordArray as $searchWord) {
$qb->andWhere(
'('
.'document.name_fr LIKE ?'.$fieldIndice
.' or document.name_en LIKE ?'.$fieldIndice
.' or document.content_fr LIKE ?'.$fieldIndice
.' or document.content_en LIKE ?'.$fieldIndice
.')'
);
$qb->setParameter($fieldIndice++, '%'.$searchWord.'%');
}
}
if ($documentType) {
if (\mb_strlen($articleIdListe) > 3) {
$qb->andWhere('(documentType.id = :documentType OR document.id IN '.$articleIdListe.')')
->setParameter('documentType', $documentType);
} else {
$qb->andWhere('(documentType.id = :documentType)')
->setParameter('documentType', $documentType);
}
}
$qb->leftJoin('document.categories', 'documentCategory')
->leftJoin('document.documentType', 'documentType')
->leftJoin('document.author', 'user')
->setFirstResult($first_result)
->setMaxResults($max_results)
->andWhere('document.documentType<>6');
if (!empty($criteria)) {
$qb->andWhere('('.$criteria.')');
}
if (!empty($orderby)) {
$qb->orderBy($orderby, $direction);
}
$sql = $qb->getQuery()->getSql();
$pag = new Paginator($qb->getQuery());
dump($pag);
$qb->setFirstResult(0);
$qb->setMaxResults(PHP_INT_MAX);
$sql = $qb->getQuery()->getSql();
$compte = \count($qb->getQuery()->getScalarResult());
return ['page' => $pag, 'compte' => $compte];
}
/**
* #param int|null $documentType
*
* #return array
*/
public function getArticleIdList($documentType = null)
{
$qb = $this->createQueryBuilder('document');
$qb->select('document.id');
if ($documentType) {
$qb->where('(document.documentType = :documentType)')
->setParameter('documentType', $documentType);
}
$compte = $qb->getQuery()->getScalarResult();
return $compte;
}
(I deleted all unnecessary method for this question)
Add the following code to the entity class from which you want to show data:
public function getId(): ?string
{
return $this->id;
}
Or
if you do not want the property "id" to be displayed in the view, comment out or delete the lines of code in your Twig template for the entity in question. For example, delete
<td>{{ Category.id }}</td>

remove duplicate values from entity reference fields

When i import feeds into an entity reference field, it creates duplicate values that look like the code below (using devel module)
$field_tags_people['und'][0]['target_id'] = 578
$field_tags_people['und'][1]['target_id'] = 578
$field_tags_people['und'][2]['target_id'] = 594
each of the target_id should have different values but turns out some are duplicates. I have tried this code
$field_tags_people['und'] = array_unique($field_tags_people['und'])
but it removes all terms except the first one. This seems strange due to the target_id key. How can I make this work?
There's probably better ways to accomplish this but here's a solution.
$unique = [];
$field_tags_people['und'] = array_filter($field_tags_people['und'],
function ($val) use (&$unique) {
if (!in_array($val['target_id'],$unique)) {
$unique[] = $val['target_id'];
return true;
}
return false;
}
);
unset($unique);
This'll trim the duplicates out for you. but be reminded that the key structure will not be reset so you could have keys going in the order like 0, 1, 6, 7, 10
Cheers
EDIT: Online Example: http://sandbox.onlinephpfunctions.com/code/9b4323a0b07ab8cd46b34a3715ea030f83e0b100
I solved this with by implementing hook_feeds_presave in a custom module.
The following checks field_my_field_name for duplicates in the array by key value and removes them before the node is imported/saved.
<?php
function my_module_feeds_presave(FeedsSource $source, $entity, $item) {
$items_array = $entity->field_my_field_name[LANGUAGE_NONE];
$entity->field_my_field_name[LANGUAGE_NONE] = unique_multidim_array($items_array,'value');
}
function unique_multidim_array($array, $key) {
$temp_array = array();
$i = 0;
$key_array = array();
foreach($array as $val) {
if (!in_array($val[$key], $key_array)) {
$key_array[$i] = $val[$key];
$temp_array[$i] = $val;
}
$i++;
}
return $temp_array;
}
?>
/**
* Delete duplicate values.
*
* #param \Drupal\Core\Entity\ContentEntityInterface $entity
* Entity.
* #param string $field_name
* Field name.
* #param bool $need_save
* Save entity or not.
*
* #throws \Drupal\Core\Entity\EntityStorageException
*/
public static function deleteDuplicateValues(ContentEntityInterface $entity, string $field_name, $need_save = FALSE) {
$result = [];
/** #var \Drupal\Core\Field\EntityReferenceFieldItemListInterface $reference_field */
$reference_field = $entity->get($field_name);
$referenced_entities = $reference_field->referencedEntities();
/** #var \Drupal\Core\Entity\ContentEntityInterface $item */
foreach ($referenced_entities as $item) {
$result[$item->id()] = $item;
}
$entity->set($field_name, $result);
if ($need_save) {
$entity->save();
}
}
And use this like :
CLASS_NAME::deleteDuplicateValues($entity, 'tags_people');

Silverstripe Model Admin for Pages

I am using the Silverstripe Swipestripe module for an online store. Because of the number of products the client has, it's not practical to nave them navigate to each individual product through the site tree when they want to make changes to a product (which happens fairly regularly) so I'd like to have a modeladmin to list all products and allow them to search for a product by name/stockcode.
I thought this would be solvable in the same way as DataObjects (and searches seem to suggest that people have done achieved this), however when I navigate to products in ModelAdmin view, I get:
Fatal Error : Call to a member function stat() on a non-object in
/path/to/folder/wwwroot/framework/model/DataObject.php on line 3192
<?php
class ProductAdmin extends ModelAdmin
{
private static $managed_models = array('Product');
private static $url_segment = 'product';
private $menu_title = 'Products';
}
Interestingly, pages and other extensions of the page class do work.
Here is the code for the Product class:
class Product extends Page {
/**
* Flag for denoting if this is the first time this Product is being written.
*
* #var Boolean
*/
protected $firstWrite = false;
/**
* DB fields for Product.
*
* #var Array
*/
private static $db = array(
'Price' => 'Decimal(19,4)',
'Currency' => 'Varchar(3)',
'StockCode' => 'Varchar(255)',
'Stock' => 'Int',
'Featured' => 'Boolean',
'YouTubeID' => 'Varchar(255)'
);
/**
* Actual price in base currency, can decorate to apply discounts etc.
*
* #return Price
*/
public function Amount() {
// TODO: Multi currency
$shopConfig = ShopConfig::current_shop_config();
$amount = new Price();
$amount->setAmount($this->Price);
$amount->setCurrency($shopConfig->BaseCurrency);
$amount->setSymbol($shopConfig->BaseCurrencySymbol);
//Transform amount for applying discounts etc.
$this->extend('updateAmount', $amount);
return $amount;
}
/**
* Display price, can decorate for multiple currency etc.
*
* #return Price
*/
public function Price() {
$amount = $this->Amount();
//Transform price here for display in different currencies etc.
$this->extend('updatePrice', $amount);
return $amount;
}
/**
* Has many relations for Product.
*
* #var Array
*/
private static $has_many = array(
'Attributes' => 'Attribute',
'Options' => 'Option',
'Variations' => 'Variation'
);
/**
* Defaults for Product
*
* #var Array
*/
private static $defaults = array(
'ParentID' => -1,
'Stock' => 999
);
/**
* Summary fields for displaying Products in the CMS
*
* #var Array
*/
private static $summary_fields = array(
'Amount.Nice' => 'Price',
'Title' => 'Title'
);
private static $searchable_fields = array(
'Title' => array(
'field' => 'TextField',
'filter' => 'PartialMatchFilter',
'title' => 'Name'
)
);
/**
* Set firstWrite flag if this is the first time this Product is written.
*
* #see SiteTree::onBeforeWrite()
* #see Product::onAfterWrite()
*/
public function onBeforeWrite() {
parent::onBeforeWrite();
if (!$this->ID) $this->firstWrite = true;
//Save in base currency
$shopConfig = ShopConfig::current_shop_config();
$this->Currency = $shopConfig->BaseCurrency;
}
/**
* Unpublish products if they get deleted, such as in product admin area
*
* #see SiteTree::onAfterDelete()
*/
public function onAfterDelete() {
parent::onAfterDelete();
if ($this->isPublished()) {
$this->doUnpublish();
}
}
/**
* Set some CMS fields for managing Products
*
* #see Page::getCMSFields()
* #return FieldList
*/
public function getCMSFields() {
$shopConfig = ShopConfig::current_shop_config();
$fields = parent::getCMSFields();
//Product fields
$fields->addFieldToTab('Root.Main', new PriceField('Price'), 'Content');
$fields->addFieldToTab('Root.Main', new TextField('StockCode'), 'Price');
$fields->addFieldToTab('Root.Main', new TextField('Stock'), 'Price');
$fields->addFieldToTab('Root.Main', new CheckBoxField('Featured'), 'Content');
$fields->addFieldToTab('Root.Images', new TextField('YouTubeID', 'YouTube Video ID (Taken from the end of the video url. ie https://www.youtube.com/watch?v=ABC123 would be ABC123)'));
//Replace URL Segment field
if ($this->ParentID == -1) {
$urlsegment = new SiteTreeURLSegmentField("URLSegment", 'URLSegment');
$baseLink = Controller::join_links(Director::absoluteBaseURL(), 'product/');
$url = (strlen($baseLink) > 36) ? "..." .substr($baseLink, -32) : $baseLink;
$urlsegment->setURLPrefix($url);
$fields->replaceField('URLSegment', $urlsegment);
}
if ($this->isInDB()) {
//Product attributes
$listField = new GridField(
'Attributes',
'Attributes',
$this->Attributes(),
GridFieldConfig_BasicSortable::create()
);
$fields->addFieldToTab('Root.Attributes', $listField);
//Product variations
$attributes = $this->Attributes();
if ($attributes && $attributes->exists()) {
//Remove the stock level field if there are variations, each variation has a stock field
$fields->removeByName('Stock');
$variationFieldList = array();
foreach ($attributes as $attribute) {
$variationFieldList['AttributeValue_'.$attribute->ID] = $attribute->Title;
}
$variationFieldList = array_merge($variationFieldList, singleton('Variation')->summaryFields());
$config = GridFieldConfig_HasManyRelationEditor::create();
$dataColumns = $config->getComponentByType('GridFieldDataColumns');
$dataColumns->setDisplayFields($variationFieldList);
$listField = new GridField(
'Variations',
'Variations',
$this->Variations(),
$config
);
$fields->addFieldToTab('Root.Variations', $listField);
}
}
//Ability to edit fields added to CMS here
$this->extend('updateProductCMSFields', $fields);
if ($warning = ShopConfig::base_currency_warning()) {
$fields->addFieldToTab('Root.Main', new LiteralField('BaseCurrencyWarning',
'<p class="message warning">'.$warning.'</p>'
), 'Title');
}
return $fields;
}
/**
* Get the URL for this Product, products that are not part of the SiteTree are
* displayed by the {#link Product_Controller}.
*
* #see SiteTree::Link()
* #see Product_Controller::show()
* #return String
*/
public function Link($action = null) {
if ($this->ParentID > -1) {
return parent::Link($action);
}
return Controller::join_links(Director::baseURL() . 'product/', $this->RelativeLink($action));
}
/**
* A product is required to be added to a cart with a variation if it has attributes.
* A product with attributes needs to have some enabled {#link Variation}s
*
* #return Boolean
*/
public function requiresVariation() {
$attributes = $this->Attributes();
return $attributes && $attributes->exists();
}
/**
* Get options for an Attribute of this Product.
*
* #param Int $attributeID
* #return ArrayList
*/
public function getOptionsForAttribute($attributeID) {
$options = new ArrayList();
$variations = $this->Variations();
if ($variations && $variations->exists()) foreach ($variations as $variation) {
if ($variation->isEnabled()) {
$option = $variation->getOptionForAttribute($attributeID);
if ($option) $options->push($option);
}
}
$options = $options->sort('SortOrder');
return $options;
}
/**
* Validate the Product before it is saved in {#link ShopAdmin}.
*
* #see DataObject::validate()
* #return ValidationResult
*/
public function validate() {
$result = new ValidationResult();
//If this is being published, check that enabled variations exist if they are required
$request = Controller::curr()->getRequest();
$publishing = ($request && $request->getVar('action_publish')) ? true : false;
if ($publishing && $this->requiresVariation()) {
$variations = $this->Variations();
if (!in_array('Enabled', $variations->map('ID', 'Status')->toArray())) {
$result->error(
'Cannot publish product when no variations are enabled. Please enable some product variations and try again.',
'VariationsDisabledError'
);
}
}
return $result;
}
}
Can anyone suggest what I'm doing wrong here or an alternative way to do what I'm trying to achieve?
Cheers
Just in case anyone still having the same problem.
So, it happens if you have installed Product Categories module for swipestripe.
The cause of this is private static $searchable_fields in ProductCategory_Extension class in ProductCategory.php file in that module. Just comment out that field and it will work.
It is because the dataobject class tries to stat Category as a class - which obviously doesnt exist.
I will fix it and push to github if I get some time. Just wanted to update here so that others dont waste time scratching head why it doesnt work.

Symfony2 - Need help setting up a doctrine query for finding tags

I've been looking far and wide and still haven't been able to find an example of how to setup a query to look for a specific 'tag' that the user selects from a sidebar which in turn will bring up all posts with that tag.
I understand how to find all tags, but not to find a specific selected by the user.
blogrepository
public function getTags($tags)
{
$qb = $this->createQueryBuilder('b');
$qb->select('b')
->join('b.tags', 'tag')
->where('b.tags LIKE ?', '%'.$tags.'%');
return $qb->getQuery()->getResult();
}
blog entity
/**
* #var string
*
* #ORM\Column(name="tags", type="text")
*/
private $tags;
/**
* Set tags
*
* #param string $tags
* #return Blog
*/
public function setTags($tags)
{
$this->tags = $tags;
return $this;
}
/**
* Get tags
*
* #return string
*/
public function getTags()
{
return $this->tags;
}
1st solution : You should use a doctrine query.
PostRepository.php
public function findByTagName($tagName)
{
$qb = $this->createQueryBuilder('post');
$qb->select('post')
->join('post.tags', 'tag')
->where('tag.name LIKE ?', '%'.$tagName.'%');
return $qb->getQuery()->getResult();
}
2nd solution : Use Many To Many relation and get directly from doctrine
Entity/Tag.php
/**
* #ORM\ManyToMany(targetEntity="YourApp\YourBundle\Entity\Post", inversedBy="tags")
* #ORM\JoinColumn(name="posts_tags")
*/
private $posts;
Entity/Post.php
/**
* #ORM\ManyToMany(targetEntity="YourApp\YourBundle\Entity\Tag", mappedBy="posts")
*/
private $tags;
So you can do $tag->getPosts(); to get all relative posts
3rd solution : Really ugly, but the tutorial is not designed to be improved ...
Get all blog post and parsing each string to find if your tag is in.
public function getBlogWithTag($tagRequested)
{
$blogs = $this->createQueryBuilder('b')
->getQuery()
->getResult();
$blogsWithTag = array();
$tags = array();
foreach ($blogs as $blog)
{
$tags = explode(",", $blog->getTags());
foreach ($tags as &$tag)
{
$tag = trim($tag);
}
if(in_array($tagRequested, $tags)) {
array_push($blogsWithTag, $blog);
}
}
return $blogsWithTag;
}
I believe this will work for you.
public function getPostsByTags($tag)
{
$query = $this->createQueryBuilder('b')
->where('b.tags like :tag')
->setParameter('tag', '%'.$tag.'%');
return $query->getQuery()->getResult();
}

Symfony2 and ParamConverter(s)

Accessing my route /message/new i'm going to show a form for sending a new message to one or more customers. Form model has (among others) a collection of Customer entities:
class MyFormModel
{
/**
* #var ArrayCollection
*/
public $customers;
}
I'd like to implement automatic customers selection using customers GET parameters, like this:
message/new?customers=2,55,543
This is working now by simply splitting on , and do a query for getting customers:
public function newAction(Request $request)
{
$formModel = new MyFormModel();
// GET "customers" parameter
$customersIds = explode($request->get('customers'), ',');
// If something was found in "customers" parameter then get entities
if(!empty($customersIds)) :
$repo = $this->getDoctrine()->getRepository('AcmeHelloBundle:Customer');
$found = $repo->findAllByIdsArray($customersIds);
// Assign found Customer entities
$formModel->customers = $found;
endif;
// Go on showing the form
}
How can i do the same using Symfony 2 converters? Like:
public function newAction(Request $request, $selectedCustomers)
{
}
Answer to my self: there is not such thing to make you life easy. I've coded a quick and dirty (and possibly buggy) solution i'd like to share, waiting for a best one.
EDIT WARNING: this is not going to work with two parameter converters with the same class.
Url example
/mesages/new?customers=2543,3321,445
Annotations:
/**
* #Route("/new")
* #Method("GET|POST")
* #ParamConverter("customers",
* class="Doctrine\Common\Collections\ArrayCollection", options={
* "finder" = "getFindAllWithMobileByUserQueryBuilder",
* "entity" = "Acme\HelloBundle\Entity\Customer",
* "field" = "id",
* "delimiter" = ",",
* }
* )
*/
public function newAction(Request $request, ArrayCollection $customers = null)
{
}
Option delimiter is used to split GET parameter while id is used for adding a WHERE id IN... clause. There are both optional.
Option class is only used as a "signature" to tell that converter should support it. entity has to be a FQCN of a Doctrine entity while finder is a repository method to be invoked and should return a query builder (default one provided).
Converter
class ArrayCollectionConverter implements ParamConverterInterface
{
/**
* #var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
function apply(Request $request, ConfigurationInterface $configuration)
{
$name = $configuration->getName();
$options = $this->getOptions($configuration);
// Se request attribute to an empty collection (as default)
$request->attributes->set($name, new ArrayCollection());
// If request parameter is missing or empty then return
if(is_null($val = $request->get($name)) || strlen(trim($val)) === 0)
return;
// If splitted values is an empty array then return
if(!($items = preg_split('/\s*'.$options['delimiter'].'\s*/', $val,
0, PREG_SPLIT_NO_EMPTY))) return;
// Get the repository and logged user
$repo = $this->getEntityManager()->getRepository($options['entity']);
$user = $this->getSecurityContext->getToken()->getUser();
if(!$finder = $options['finder']) :
// Create a new default query builder with WHERE user_id clause
$builder = $repo->createQueryBuilder('e');
$builder->andWhere($builder->expr()->eq("e.user", $user->getId()));
else :
// Call finder method on repository
$builder = $repo->$finder($user);
endif;
// Edit the builder and add WHERE IN $items clause
$alias = $builder->getRootAlias() . "." . $options['field'];
$wherein = $builder->expr()->in($alias, $items);
$result = $builder->andwhere($wherein)->getQuery()->getResult();
// Set request attribute and we're done
$request->attributes->set($name, new ArrayCollection($result));
}
public function supports(ConfigurationInterface $configuration)
{
$class = $configuration->getClass();
// Check if class is ArrayCollection from Doctrine
if('Doctrine\Common\Collections\ArrayCollection' !== $class)
return false;
$options = $this->getOptions($configuration);
$manager = $this->getEntityManager();
// Check if $options['entity'] is actually a Dcontrine one
try
{
$manager->getClassMetadata($options['entity']);
return true;
}
catch(\Doctrine\ORM\Mapping\MappingException $e)
{
return false;
}
}
protected function getOptions(ConfigurationInterface $configuration)
{
return array_replace(
array(
'entity' => null,
'finder' => null,
'field' => 'id',
'delimiter' => ','
),
$configuration->getOptions()
);
}
/**
* #return \Doctrine\ORM\EntityManager
*/
protected function getEntityManager()
{
return $this->container->get('doctrine.orm.default_entity_manager');
}
/**
* #return \Symfony\Component\Security\Core\SecurityContext
*/
protected function getSecurityContext()
{
return $this->container->get('security.context');
}
}
Service definition
arraycollection_converter:
class: Acme\HelloBundle\Request\ArrayCollectionConverter
arguments: ['#service_container']
tags:
- { name: request.param_converter}
It's late, but according to latest documentation about #ParamConverter, you can achieve it follow way:
* #ParamConverter("users", class="AcmeBlogBundle:User", options={
* "repository_method" = "findUsersByIds"
* })
you just need make sure that repository method can handle comma (,) separated values

Resources