Full text search in mongodb in Symfony 3.4 - mongodb

I'm trying to use full text search in mongodb:
db.Product.createIndex({"name": "text"})
db.Product.find({$text: {$search: "xxxxx"}})
how to use this in controller to symfony?

First of all create Product entity(adjust to your needs)
<?php
/**
* #Document
* #Index(keys={"name"="text"})
*/
class Product
{
/** #Id */
public $id;
/** #Field(type="string") */
public $name;
/** #Field(type="float") */
public $price;
}
Look at $name and #Index annotation
Then use query builder text() method
// Run a text search against the index
$qb = $dm->createQueryBuilder('Product')
->text('words you are looking for');
More info you can find here
The other way is to create native query with expr() from doctrine query builder

Thank you for all the answers. In summary, the controller for the search engine looks like the following:
class SearchController extends Controller
{
public function searchBarAction()
{
$form = $this->createFormBuilder(null)
->setMethod('GET')
->add('search', TextType::class)
->getForm();
return $this->render('AppBundle:Components:_searchBar.html.twig', [
'form' => $form->createView()
]);
}
/**
* #param Request $request
*/
public function handleSearchAction(Request $request)
{
$searchData = $request->query->get('form')['search'];
$dbName = 'ece';
$connection = $this->container->get('doctrine_mongodb')->getConnection();
$mongo = $connection->getMongo();
$db = $mongo->selectDB($dbName);
$resultSetProduct = $db->Product->find([
'$text' => ['$search' => $searchData]
]);
$resultSet = $db->MainData->find([
'$text' => ['$search' => $searchData]
]);
$itemProduct = $resultSetProduct->count();
$itemSet = $resultSet->count() + $itemProduct;
return $this->render('search/index.html.twig', [
'searchData' => $searchData,
'resultSetProduct' => $resultSetProduct,
'itemProduct' => $itemProduct,
'itemSet' => $itemSet,
'resultSet' => $resultSet
]);
}
}

Related

Symfony ValidatorComponent > AnnotationMapping in FormComponent

Im working on a project where I'm using some Symfony Components. My problem is how to make the Form Component's validation of Forms use AnnotationMapping to find the constraints.
SetUp:
global $loader; //composer - autoload
AnnotationRegistry::registerLoader([$loader, 'loadClass']);
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator();
$formFactory = Forms::createFormFactoryBuilder()
[...]
->addExtension(new ValidatorExtension($validator))
->getFormFactory();
Entity
/**
* #ORM\Entity
* #ORM\Table(name="..")
*/
class Conductor extends AbstractEntity {
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue
*/
protected $id;
/**
* #Assert\NotBlank()
* #ORM\Column(type="string")
*/
protected $pattern;
[...]
}
Building the Form
$builder = $App->getFormFactory()->createBuilder(FormType::class, $entity_data);
foreach ($fields as $field) {
$builder->add(
$field,
null,
[
"attr" => array("class" => "..."),
]
);
}
$builder->getForm();
FormSubmit / Validation
if($request->isMethod('POST')) {
$formTable = $this->createFormTable( array() );
$form = $formTable->buildForm($entity);
$form->submit($this->dataMapper->formDataFromPost());
/*
$entity = $this->dataMapper->mapFromPost();
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator();
*/
if($form->isValid()) {
[...]
} else {
[...]
}
}
Im trying to make the NotBlank() Constraints work. But my form passes the validation in any case. If I use a new validator and validate with it, it will show me the correct Errors. But the Form->isValid() function does not. Maybe it is not configured correctly to use AnnotationMapping? Thank you very much in advance for tipps or solutions!
Problem localization
The form handleRequest / submit and validation are working as expected!
The form does not have any constraints!!
-> Mapping the Constraints from Annotation is not happening / working.
I did find a similar question: Why does Symfony form not validate my DTO with constraint annotations?
I wasn't able to find a solution to enable the mapping that should happen inside the FormComponent with the ValidatorExtension.
But I did find a functional workaround. My approach is to get the Constraints from the readPropertyMetadata function of the validator:
use Symfony\Component\Validator\Validation;
public function buildForm(AbstractEntity $entity) {
$validator = Validation::createValidatorBuilder()
->enableAnnotationMapping()
->getValidator();
$fields = [*ENTITY PRPERTIES*];
$classMeta = $validator->getMetadataFor($entity);
foreach ($fields as $field) {
$metadata = $classMeta->getPropertyMetadata($field);
if(is_array($metadata) && count($metadata) > 0) {
$constraints = $classMeta->getPropertyMetadata($field)[0]->constraints;
} else {
$constraints = [];
}
$builder->add(
$field,
null,
[
"attr" => array("class" => "..."),
"constraints" => $constraints
]
);
}
}
As now the constraints are added to the form the validation finally works as expected.

how to add "target lists" to my custom module

i have create a module and named: Custom_module by Developer Tools --> Module Builder
I trired to add "target lists" to Custom_module like module Campaign, but i can not find the way the do that
everyone can help you to find the best way to add "target lists" to my module.
thanks
You Just need to create a custom sub panel in your custom module.
target list is ProspectLists module.
Follow this link to create custom module.
http://shanedowling.com/sugarcrm-7-custom-subpanels
https://developer.sugarcrm.com/2015/05/18/creating-subpanels-with-custom-results-in-sugar-7-5/
1. Create a new link class
This should go into custom/modules//YourNewLink.php and this class will act as the custom functionality that will build your link between the two records.
<?php
/**
* Custom filtered link
*/
class YourNewLink extends Link2
{
/**
* DB
*
* #var DBManager
*/
protected $db;
public function __construct($linkName, $bean, $linkDef = false)
{
$this->focus = $bean;
$this->name = $linkName;
$this->db = DBManagerFactory::getInstance();
if (empty($linkDef)) {
$this->def = $bean->field_defs[$linkName];
} else {
$this->def = $linkDef;
}
}
/**
* Returns false if no relationship was found for this link
*
* #return bool
*/
public function loadedSuccesfully()
{
// this link always loads successfully
return true;
}
/**
* #see Link2::getRelatedModuleName()
*/
public function getRelatedModuleName()
{
return '<Your_Module>';
}
/**
*
* #see Link2::buildJoinSugarQuery()
*/
public function buildJoinSugarQuery($sugar_query, $options = array())
{
$joinParams = array('joinType' => isset($options['joinType']) ? $options['joinType'] : 'INNER');
$jta = 'active_other_invites';
if (!empty($options['joinTableAlias'])) {
$jta = $joinParams['alias'] = $options['joinTableAlias'];
}
$sugar_query->joinRaw($this->getCustomJoin($options), $joinParams);
return $sugar_query->join[$jta];
}
/**
* Builds main join subpanel
* #param string $params
* #return string JOIN clause
*/
protected function getCustomJoin($params = array())
{
$bean_id = $this->db->quoted($this->focus->id);
$sql = " INNER JOIN(";
$sql .= "SELECT id FROM accounts WHERE id={$bean_id}"; // This is essentially a select statement that will return a set of ids that you can match with the existing sugar_query
$sql .= ") accounts_result ON accounts_result.id = sugar_query_table.id";
return $sql;
}
2. Add a new vardef entry for the link field.
For this example, I'm going to create the custom link on the contacts module. So this code goes in custom/Extension/modules/Contacts/Ext/Vardefs/your_field_name.php
<?php
$dictionary["Contact"]["fields"]["your_field_name"] = array(
'name' => 'active_other_invites',
'type' => 'link',
'link_file' => 'custom/modules/<YourModule>/YourNewLink.php',
'link_class' => 'YourNewLink',
'source' => 'non-db',
'vname' => 'LBL_NEW_LINK',
'module' => '<YourModule>',
'link_type' => 'many',
'relationship' => '',
);
3. Add the new link as a subpanel
This goes under custom/Extension/modules/Contacts/Ext/clients/base/layouts/subpanels/your_subpanel_name.php
<?php
$viewdefs['Contacts']['base']['layout']['subpanels']['components'][] = array (
'layout' => 'subpanel',
'label' => 'LBL_NEW_LINK',
'context' =>
array (
'link' => 'your_field_name',
),
);
4. Add the label
Under custom/Extension/modules/Contacts/Ext/Language/en_us.new_link.php
<?php
$mod_strings['LBL_ACTIVE_OTHER_INVITES'] = 'Your New Link';
5. Quick Repair and Rebuild

Custom Form Editing Setting Conent in Symfony

I created the following Custom Form Type
<?php
namespace UserBundle\Form\Type;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\HttpFoundation\Request;
use UserBundle\Entity\Users;
class UserType extends AbstractType
{
const FORM = 'user';
/**
* #var
*/
protected $UserContext;
/**
* Construct
* #param $uc
*/
public function __construct($uc)
{
$this->UserContext = $uc;
}
/**
* Build Form
* #param \Symfony\Component\Form\FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('username','text',array('label'=>'username'))
->add('password','text',array('label'=>'password'))
->add('firstname','text',array('label'=>'firstname','required'=>false))
->add('lastname','text',array('label'=>'lastname','required'=>false))
->add('email','email',array('label'=>'email','required'=>true));
$roles = array(
'Guest'=>array(
'ROLE_GUEST' =>'ROLE_GUEST',
),
'Users'=>array(
'ROLE_USER' =>'ROLE_USER',
),
'Customers'=>array(
'ROLE_CUSTOMER' =>'ROLE_CUSTOMER',
),
);
if($this->UserContext->isGranted('Role_SUPERVISOR'))
{
$roles['Staff']['ROLE_STAFF'] = 'ROLE_STAFF';
$roles['Staff']['ROLE_SUPPORT'] = 'ROLE_SUPPORT';
}
if($this->UserContext->isGranted('ROLE_ADMIN'))
{
$roles['Staff']['ROLE_SUPERVISOR'] = 'ROLE_SUPERVISOR';
}
if($this->UserContext->isGranted('ROLE_SUPER_ADMIN'))
{
$roles['Staff']['ROLE_ADMIN'] = 'ROLE_ADMIN';
}
if($this->UserContext->isGranted('ROLE_GOD'))
{
$roles['Staff']['ROLE_SUPER_ADMIN'] = 'ROLE_SUPER_ADMIN';
$roles['Staff']['ROLE_GOD'] = 'ROLE_GOD';
}
$builder->add('role','choice',array(
'choices'=>$roles,
'required'=>true,
'label'=>'userrole'
))
->add('status','choice',array(
'choices'=>array(
'1'=>'account active',
'0'=>'account inactive',
),
'required'=>true,
'label'=>'status'
));
}
/**
* get Form Name
* #return string
*/
public function getName()
{
return self::FORM;
}
/**
* persist Form
* #param \Symfony\Component\HttpFoundation\Request $request
* #param \UserBundle\Entity\Users $user
* #param \Doctrine\ORM\EntityManager $em
*
* #return \UserBundle\Entity\Users
*/
public static function storeFormContent(Request $request,Users $user, EntityManager $em)
{
$formData = $request->request->get(self::FORM);
$isNew = (int)$user->getId()<1;
$user->setFirstname($formData['firstname']);
$user->setLastname($formData['lastname']);
$user->setUsername($formData['username']);
if(!empty($formData['password']) || $isNew)
{
$user->setPassword($formData['password']);
}
$user->setEmail($formData['email']);
$user->setRole($formData['role']);
$user->setActive($formData['status']);
if($isNew)
{
$em->persist($user);
}
$em->flush();
return $user;
}
}
In my Controller I added this method to edit a User:
/**
* #Route("/Administration/Users/Edit", name="admin_users_edit")
* #Template()
*/
public function editAction()
{
$this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!');
$request = Request::createFromGlobals();
$userid = (int)$request->query->get('id', null);
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
$session = new Session();
$session->start();
$session->set('currentRoute',array('call'=>'admin_users_edit','parameters'=>array('id'=>$userid)));
throw $this->createAccessDeniedException();
}
$em = $this->getDoctrine()->getManager();
/** #var Users $user */
$user = $this->getDoctrine()
->getRepository('UserBundle\Entity\Users')
->find($userid);
if(empty($user) || !($user instanceof Users) || $user->getId() < 0)
{
return $this->redirectToRoute('admin_users_index', array('status' => 'user_does_not_exist'));
}
if($user->getRole()=='ROLE_ADMIN')
{
$this->denyAccessUnlessGranted('ROLE_SUPER_ADMIN', null, 'Unable to access this page!');
}
if($user->getRole()=='ROLE_SUPER_ADMIN' or $user->getRole()=='ROLE_GOD')
{
$this->denyAccessUnlessGranted('ROLE_GOD', null, 'Unable to access this page!');
}
if(!($user instanceof Users))
{
return $this->redirectToRoute('admin_users_index', array('status' => 'not_found'));
}
$form = $this->createForm(new UserType($this->get('security.context'),$user));
$form->handleRequest($request);
if($form->isValid())
{
UserType::storeFormContent($request,$user,$this->getDoctrine()->getManager());
return $this->redirectToRoute('admin_users_index', array('status' => 'create_success'));
}
return array(
'activeMenu'=>'users',
'error'=>$request->query->get('error'),
'form'=>$form->createView(),
);
}
Everything works fine so far.
Creating Users Work without an issue.
But Editing them leaves me blank fields.
I can't see where the issue is comming from.
I appreceate any help.
Chris
P.S.:
I have to seperate the Form into a Custom Type, because I will need to reuse it on several locations.
I will also reuse the twig part of the form for this.
^^
I just discovered that $form->setData() works for you, because you forgotten to add setDefaultOptions method to your form type:
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
...
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'UserBundle\Entity\Users',
));
}
You can remove $form->setData();

Unit Test Form WIth Repository Method

I am attempting to unit test one of my forms that I have which includes an entity form type on it. I would like to test the full form, but I keep on running into the error message - Expected argument of type "Doctrine\ORM\QueryBuilder", "NULL" given
Which is obvious, I need to somehow mock Doctrine\ORM\QueryBuilder as the return type for the entity form type. I am not quiet sure how I go about doing that though.
Here is the code of the Form -
<?php
namespace ICS\BackEnd\BoardBundle\Form;
use Doctrine\ORM\EntityRepository;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class BoardCollectionType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', 'text', array(
'disabled' => TRUE
))
->add('member', 'entity', array(
'class' => 'MemberBundle:Members',
'property' => 'fullName',
'query_builder' => function(EntityRepository $er) {
return $er->findAllActiveMembers();
},
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'ICS\BackEnd\BoardBundle\Entity\Board'
));
}
/**
* #return string
*/
public function getName()
{
return 'ics_boardbundle_board';
}
}
This is the test I am running on it -
<?php
namespace ICS\BackEnd\BoardBundle\Tests\Form;
use Doctrine\ORM\QueryBuilder;
use ICS\BackEnd\BoardBundle\Entity\Board;
use ICS\BackEnd\BoardBundle\Form\BoardCollectionType;
use Symfony\Component\Form\Forms;
use Symfony\Component\Form\PreloadedExtension;
use Symfony\Component\Form\Test\TypeTestCase;
class BoardCollectionTypeTest extends TypeTestCase {
protected $repository;
protected function setUp()
{
parent::setUp();
$this->factory = Forms::createFormFactoryBuilder()
->addExtensions($this->getExtensions())
->getFormFactory();
}
public function testSubmittedValueData()
{
$formData = array(
'member' => NULL,
);
$type = new BoardCollectionType();
$form = $this->factory->create($type);
$object = new Board();
$object->createFromArray($formData);
// submit the data to the form directly
$form->submit($formData);
$this->assertTrue($form->isSynchronized());
$this->assertEquals($object, $form->getData());
$view = $form->createView();
$children = $view->children;
foreach (array_keys($formData) as $key) {
$this->assertArrayHasKey($key, $children);
}
}
protected function getExtensions()
{
$this->repository = $this->getMockBuilder('Doctrine\ORM\EntityRepository')
->disableOriginalConstructor()
->getMock();
$mockEntityManager = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$mockEntityManager->expects($this->any())
->method('getRepository')
->will($this->returnValue($this->repository));
$classMetadata = $this->getMockBuilder('\Doctrine\Common\Persistence\Mapping\ClassMetadata')
->disableOriginalConstructor()
->getMock();
$mockEntityManager->expects($this->any())
->method('getClassMetadata')
->will($this->returnValue($classMetadata));
$mockRegistry = $this->getMockBuilder('Doctrine\Bundle\DoctrineBundle\Registry')
->disableOriginalConstructor()
->setMethods(array('getManagerForClass'))
->getMock();
$mockRegistry->expects($this->any())
->method('getManagerForClass')
->will($this->returnValue($mockEntityManager));
$mockEntityType = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\Type\EntityType')
->setMethods(array('getName'))
->setConstructorArgs(array($mockRegistry))
->getMock();
$mockEntityType->expects($this->any())
->method('getName')
->will($this->returnValue('entity'));
$this->assertQueryBuilderCalled();
return array(new PreloadedExtension(array(
$mockEntityType->getName() => $mockEntityType,
), array()));
}
protected function assertQueryBuilderCalled()
{
$em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalConstructor()->getMock();
$repo = $this->getMockBuilder('ICS\BackEnd\MemberBundle\Entity\Repository\MembersRepository')
->disableOriginalConstructor()->getMock();
$repo->expects($this->once())->method('findAllActiveMembers')
->will($this->returnValue(new QueryBuilder($em)));
/*$qb = $this->getMockBuilder('Doctrine\ORM\QueryBuilder')
->disableOriginalConstructor()
->getMock();
$query = $this->getMockBuilder('Doctrine\ORM\AbstractQuery')
->disableOriginalConstructor()
->setMethods(array('execute'))
->getMockForAbstractClass();
$query->expects($this->any())
->method('execute')
->will($this->returnValue(array()));
$qb->expects($this->any())
->method('getQuery')
->will($this->returnValue($query));
$this->repository->expects($this->any())
->method('findAllActiveMembers')
->will($this->returnValue($query));
$this->repository->expects($this->any())
->method('createQueryBuilder')
->will($this->returnValue($qb));*/
}
}
Thanks for any help!
I resolved the issue by changing the entity form type to choice. It made the test much easier to read and do. I injected the "choices" into the options of the form type.

Testing symfony 2 forms

I develop new type, but I don't know how I can test it.
Assert annotation is not load and validations is not called.
Could any one please help me?
class BarcodeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->
add('price');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Bundles\MyBundle\Form\Model\Barcode',
'intention' => 'enable_barcode',
));
}
public function getName()
{
return 'enable_barcode';
}
}
A have following model for storing form data.
namepspace Bundles\MyBundle\Form\Model;
class Barcode
{
/**
* #Assert\Range(
* min = "100",
* max = "100000",
* minMessage = "...",
* maxMessage = "..."
* )
*/
public $price;
}
I develop some test like this, the form didn't get valid data but it is valid! (Because annotation is not applied)
I try adding ValidatorExtension but I dont know how can I set constructor paramaters
function test...()
{
$field = $this->factory->createNamed('name', 'barcode');
$field->bind(
array(
'price' => 'hello',
));
$data = $field->getData();
$this->assertTrue($field->isValid()); // Must not be valid
}
Not sure why you need to unit-test the form. Cant You unit test validation of Your entity and cover controller with your expected output?
While testing validation of entity You could use something like this:
public function testIncorrectValuesOfUsernameWhileCallingValidation()
{
$v = \Symfony\Component\Validator\ValidatorFactory::buildDefault();
$validator = $v->getValidator();
$not_valid = array(
'as', '1234567890_234567890_234567890_234567890_dadadwadwad231',
"tab\t", "newline\n",
"Iñtërnâtiônàlizætiøn hasn't happened to ", 'trśżź',
'semicolon;', 'quote"', 'tick\'', 'backtick`', 'percent%', 'plus+', 'space ', 'mich #l'
);
foreach ($not_valid as $key) {
$violations = $validator->validatePropertyValue("\Brillante\SampleBundle\Entity\User", "username", $key);
$this->assertGreaterThan(0, count($violations) ,"dissalow username to be ($key)");
}
}
Functional test. Given that you generate a CRUD with app/console doctrine:generate:crud with routing=/ss/barcode, and given that maxMessage="Too high" you can:
class BarcodeControllerTest extends WebTestCase
{
public function testValidator()
{
$client = static::createClient();
$crawler = $client->request('GET', '/ss/barcode/new');
$this->assertTrue(200 === $client->getResponse()->getStatusCode());
// Fill in the form and submit it
$form = $crawler->selectButton('Create')->form(array(
'ss_bundle_eavbundle_barcodetype[price]' => '12',
));
$client->submit($form);
$crawler = $client->followRedirect();
// Check data in the show view
$this->assertTrue($crawler->filter('td:contains("12")')->count() > 0);
// Edit the entity
$crawler = $client->click($crawler->selectLink('Edit')->link());
/* force validator response: */
$form = $crawler->selectButton('Edit')->form(array(
'ss_bundle_eavbundle_barcodetype[price]' => '1002',
));
$crawler = $client->submit($form);
// Check the element contains the maxMessage:
$this->assertTrue($crawler->filter('ul li:contains("Too high")')->count() > 0);
}
}
Include this line must be in Model and try it after include look like your model.
/* Include the required validators */
use Symfony\Component\Validator\Constraints as Assert;
namespace Bundles\MyBundle\Form\Model;
class Barcode
{
/**
* #Assert\Range(
* min = "100",
* max = "100000",
* minMessage = "min message here",
* maxMessage = "max message here"
* )
*/
public $price;
}