I have number of blog posts in my database and im using doctrine criteria to filter them. If I write criteria that matches some of the posts everything works perfect.
Imagine that there are 3 users (User 1 , User 2, User 3) and there are some posts marked as private from User 1 and user 2.
This is my php code :
$criteria = Criteria::create();
$criteria->Where($criteria->expr()->eq('private', 1);
$criteria->andWhere($criteria->expr()->eq('author', $author));
$posts=$service->findPostBy($criteria);
return array(
'page' => $page,
'posts'=>$posts,
'filter' => $form->createView()
);
/*findPostBy calls Doctrine matching function*/
public function matching(Criteria $criteria)
{
$persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);
return new ArrayCollection($persister->loadCriteria($criteria));
}
If i ask for User 1 private posts it builds functional query and return posts i want. But if I ask for User 3 private posts It returns all posts in my database without any filtering. How can I tell if my criteria works if they dont return empty result in case of no matches.
Try this:
$criteria = Criteria::create()
->where(Criteria::expr()->eq('private', 1);
->andWhere(Criteria::expr()->eq('author', $author));
I'm not sure why you are using criteria in the first place for your example though. You could eliminate the Criteria altogether and accomplish what you want in one line:
$posts $service->findPostBy(array('private' => 1, 'author' => $author);
Related
In my Symfony project, I have created the table "event" and datatime field in it named start. In twig, I wish to filter and display upcoming events. So events that have passed would be visible any more.
At the moment, I used {% if event.start > date() %}. It worked to hide events that happened days before today. I wanted also to hide events that already happened today but currently it doesn't work when time has passed of the today's event.
How can I hide events that time already has passed ?
better to make a function in the repository and call it in the controller not using findAll and hide events.
// EventRepository
public function eventsList()
{
return $this->createQueryBuilder('e')
->andWhere('e.date >= :today')
->setParameter('today', new \DateTime())
->orderBy('e.id', 'DESC')
->getQuery()
->getResult()
;
}
Here is the solution :
Make sure the field is datetime.
Use {% if event.start > 'now' %}and it will take into account day (of today) and (current) time.
Here is a better solution (I precise that an address is given to events, and address has a "bigcity" registered, this why I am using LocationRepository) :
EventController.php
#[Route('/events', name: 'events')]
public function events(
Request $request,
EventRepository $eventRepository,
CategoryRepository $categoryRepository,
BigCityRepository $bigcityRepository,
LocationRepository $locationRepository
){
$category = $categoryRepository->findOneById($request->query->get('category'));
$bigcity = $bigcityRepository->findOneById($request->query->get('bigcity'));
$location = $locationRepository->findAll($request->query->get('location.bigcity'));
$events = $eventRepository->findBy(['category' => $category, 'address' => $location]);
return $this->render("front/events.html.twig", [
'events' => $events,
'category' => $category,
'bigcity' => $bigcity
]);
}
What I need to be able to do is apply a value for an attribute in the URL, so only the products match that attribute are displayed. I don't want to do any widgets or other visible filters on the page.
For this I presume I would need to use one of the webhooks, and filtering out all products that are about to be displayed.
Can anyone advise which hook will be best in this case and a simple explanation on how the triggered function will return the new array of products?
Thanks in advance!
NB: I also want to query a custom attribute, which does not have any terms, just a straight key/value.
UPDATE 1
I'm playing with two techniques; one is very reliable, and that's basically to use:
if (!$product->attributes || $product->get_attribute( 'testKey' ) != $_GET["testKey"]) {
//return;
}
at the top of content-product.php, but of course WooCommerce will still say the original value for found_posts. Certainly not ideal.
I've come across that something like this should work in functions.php:
function testFilter($meta_query) {
$meta_query[] = array (
'key' => 'testKey',
'value' => 'testVal',
'compare' => '='
);
return $meta_query;
}
add_filter( 'woocommerce_product_query_meta_query', 'testFilter', 9 );
Except it doesn't, returns no results, doesn't matter if I use LIKE, EXISTS etc. Am I using it wrong?
UPDATE 2
I'm not going to say this is the answer, as this only seems to look for one value within a group of custom attributes, but this result has helped.
add_filter( 'wpv_filter_query', 'wpv_filter_color_attribute' );
function wpv_filter_color_attribute( $query_args) {
$tax_query = array();
$tax_query['taxonomy'] = 'pa_size';
$tax_query['field'] = 'term_id';
$tax_query['terms'] = $_GET['pa_size'];
$query_args['tax_query'] = array($tax_query);
return $query_args;
}
You should replace "pa_size" with your attribute taxonomy slug, also $_GET['pa_size'] with the right URL parameter.
You can filter products by attributes using above code. I have not tried this. But, this may help you.
I want to be able to submit a form that modifies multiple entities. Let's say I've got a BulkeditFormType to change the 'active' (Boolean) or 'organisation' (EntityType with App\Entity\Organisation) fields on multiple users at once.
This is my current solution (semi-pseudo-code):
public function bulkedit(Request $request)
{
$form = $this->createForm(BulkeditFormType::class, null, [
//..options
]);
if ($request->isXmlHttpRequest()) {
// fields '_token' and empty values are unset, not shown in this example
$formData = $request->request->get($form->getName());
$entityManager = $this->getDoctrine()->getManager();
$repo = $entityManager->getRepository(App\Entity\User::class);
$entities = $repo->findBy([
'id' => [1,2,3,4,5]
]);
foreach ($entities as $entity) {
$form = $this->createForm(BulkeditFormType::class, $entity, [
//..options
]);
$clearMissing = false;
$form->submit($formData, $clearMissing);
$entityManager->persist($entity);
}
$entityManager->flush();
}
return $this->render('#User/User/bulkedit.html.twig', [
'form' => $form->createView()
]);
}
Note that I've tried to include only relevant parts of my code, so please consider this as pseudo-code, just to get an idea of my current implementation.
While this solution works, it creates a Form object for every entity. Editing 100 users will lead to a large amount of memory usage and many useless database queries.
How can I modify my code in such a way that only one form will be generated which can be re-used by all entities? I've tried to use $form->setData(), but I feel like there must be a better way. A CollectionType will create multiple subforms instead of multiple forms, so in this case it doesn't make a big difference.
I'm managing the DataObject class 'trainer' with ModelAdmin. A trainer has a many_many relation to my other class 'language'.
On my 'trainer' class I'm manipulating the 'searchableFields' function to display a ListboxField in the filters area.
public function searchableFields() {
$languagesField = ListboxField::create(
'Languages',
'Sprachen',
Language::get()->map()->toArray()
)->setMultiple(true);
return array (
'Languages' => array (
'filter' => 'ExactMatchFilter',
'title' => 'Sprachen',
'field' => $languagesField
)
);
}
That works like expected and shows me the wanted ListboxField. The Problem is, after selecting 1 or 2 or whatever languages and submitting the form, I'm receiving
[Warning] trim() expects parameter 1 to be string, array given
Is it possible here to filter with an many_many relation? And if so, how? Would be great if someone could point me in the right direction.
Update:
Full Error Message: http://www.sspaste.com/paste/show/56589337eea35
Trainer Class: http://www.sspaste.com/paste/show/56589441428d0
You need to define that logic within a $searchable_fields parameter instead of the searchableFields() which actually constructs the searchable fields and logic.
PHP would be likely to throw an error if you go doing fancy form stuff within the array itself, so farm that form field off to a separate method in the same DataObject and simply call upon it.
See my example, I hope it helps.
/* Define this DataObjects searchable Fields */
private static $searchable_fields = array(
'Languages' => array (
'filter' => 'ExactMatchFilter',
'title' => 'Sprachen',
'field' => self::languagesField()
)
);
/* Return the searchable field for Languages */
public function languagesField() {
return ListboxField::create(
'Languages',
'Sprachen',
Language::get()->map()->toArray()
)->setMultiple(true);
}
Yes, it's possible. You just need to override two methods - one in Trainer data object and one in TrainerModelAdmin. First one will make a field, second one will do filtering.
Trainer Data Object:
public function scaffoldSearchFields($_params = null)
{
$fields = parent::scaffoldSearchFields($_params);
// get values from query, if set
$query = Controller::curr()->request->getVar('q');
$value = !empty($query['Languages']) && !empty($query['Languages']) ? $query['Languages'] : array();
// create a field with options and values
$lang = ListboxField::create("Languages", "Sprachen", Language::get()->map()->toArray(), $value, null, true);
// push it to field list
$fields->push($lang);
return $fields;
}
Trainer Model Admin
public function getList()
{
$list = parent::getList();
// check if managed model is right and is query set
$query = $this->request->getVar('q');
if ($this->modelClass === "Trainer" && !empty($query['Languages']) && !empty($query['Languages']))
{
// cast all values to integer, just to be sure
$ids = array();
foreach ($query['Languages'] as $lang)
{
$ids[] = (int)$lang;
}
// make a condition for query
$langs = join(",", $ids);
// run the query and take only trainer IDs
$trainers = DB::query("SELECT * FROM Trainer_Languages WHERE LanguageID IN ({$langs})")->column("TrainerID");
// filter query on those IDs and return it
return $list->filter("ID", $trainers);
}
return $list;
}
Is there a way to list only the users that has a specific capability, such us "publish_posts" ?
To select users with certain capabilities you can use WP_User_Query with meta_query parameter, because WP stores capabilities as a serialized string in user_meta table.
Also remember that due to availability to have multisite installation capabilities name in user meta looks like wp_table_prefix_capabilities.
global $wpdb;
// meta-key name
$capabilities_field_name=$wpdb->prefix.'capabilities';
//array as argument for our query
$qargs=[
'role' => ['Customer'], // use this if you need to query by role at the same time
'meta_query'=>
[
'relation' => 'OR', // optional if you'll need to select more than
// one capability just add this and create same array
// as down below describing what are you looking for
[
'key' => $capabilities_field_name,
'value' => 'your_role_name',
'compare' => 'LIKE',
],
// here could be same array [key,value,compare]... as above with another capability
// but you'll need to add extra argument showing relationship between them see above 'relation parameter'
],
'number'=> -1 // to select all users
];
$usersQuery=new WP_User_Query($qargs); // instantiate UserQuery with $qargs
$users=$usersQuery->get_results(); // get all results as array of WPUser objects
Hope it helps somebody:)
Note [vars] could be substituted to array(vars), I like [] short syntax but it's supported only since php 5.4.
You can just retrieve all users. Then loop through them in a foreach. Check if the user has a specific capability then push the users to another array and use that array to list them.
$all_users = get_users();
$specific_users = array();
foreach($all_users as $user){
if($user->has_cap('specific_capability')){
$specific_users[] = $user;
}
}
NOTE:
It seemed a nice quick and dirty solution at the time, but now I would recommend writing a query. I do not have the time to investigate this for you, so if the one downvoting this would be so kind to answer this question instead of downvoting an answer which was an actual help to the inquirer, that would be nice.
You can list users with WP_User_Query, but afaik you can only return different roles, not permissions, maybe that's already what you want! There's also a site where you can see the different roles in the wordpress documentation.
You will first need to get all the roles that contain that capability. Then you can search users based on the roles that contain that capability.
$roles = array();
foreach ( wp_roles()->roles as $role_name => $role_obj ) {
if ( ! empty( $role_obj['capabilities']['my_capability_name'] ) ) {
$roles[] = $role_name;
}
}
$users = get_users( array( 'role__in' => $roles ) );
This does not account for if another role has "Deny" on that capability and your users can contain multiple roles. If so then you will also need to add a "user_can()" condition when looping through your Users. https://developer.wordpress.org/reference/functions/user_can/