will the following JAPE rule override the existing annotation or add an extra annotation? - information-retrieval

Below JAPE rule will replace the Email annotation by Address or just add an extra annotation Address ?
Rule: EmailFinal
Priority: 50
(
{Email}
)
:address
-->
:address.Address = {kind = "email", rule = "EmailFinal"}

A :label.Type = {...} will always create a new annotation, but it won't touch the existing ones. If you want to delete the input annotation then you need to add a second action to your rule:
Rule: EmailFinal
Priority: 50
(
{Email}
)
:address
-->
:address.Address = {kind = "email", rule = "EmailFinal"},
:address { inputAS.removeAll(addressAnnots); }

Related

ElasticSearch filter by wildcard

I'm trying to filter my results by wildcard character.
example of my records:
....
"_source" : {
"urlSlug" : "entry-title",
"revisions" : [
{
"title" : "Entry title",
"context" : "NKD"
}
]
}
each revision can have different context with different order.
And when I search for record I want to search only entities with context like "N". So I perform nested query with match_all and wildcard.
{"query":{"bool":{"must":[{"query_string":{"query":"*entry*"}},{"nested":{"path":"revisions","query":{"bool":{"should":[{"match_all":{}}],"filter":[{"wildcard":{"revisions.context":{"value":"*N*","boost":1}}}]}}}}]}},"size":10}
When I run query I get zero results. And Can't figure out how to restrict results.
I'm using for this FosElastica with following config:
indexes:
app:
types:
entity:
properties:
urlSlug: ~
revisions:
type: "nested"
properties:
title: { type: text,boost: 10 }
context: { type: text }
and my query builder looks like this:
$boolQuery = new ESQuery\BoolQuery();
$fieldQuery = new ESQuery\QueryString();
$fieldQuery->setQuery('*' . $query . '*');
$boolQuery->addMust($fieldQuery);
$nestedQuery = new ESQuery\Nested();
$nestedQuery->setPath('revisions');
$nestedBoolQuery = new ESQuery\BoolQuery();
$matchAllQuery = new ESQuery\MatchAll();
$nestedBoolQuery->addShould($matchAllQuery);
$filterQuery = new ESQuery\Wildcard();
$filterQuery->setValue('revisions.context','*N*');
$nestedBoolQuery->addFilter($filterQuery);
$nestedQuery->setQuery($nestedBoolQuery);
$boolQuery->addMust($nestedQuery);
$result = $finder->findHybrid($boolQuery,self::AUTOCOMPLETE_MAX_RESULTS);
ElasticSearch version 5.2.2
Well I did find out what is the problem in my query.
this is working one:
{"query":{"bool":{"must":[{"query_string":{"query":"*komi*"}}],"filter":[{"nested":{"path":"revisions","query":{"wildcard":{"revisions.context":{"value":"*n*","boost":1}}}}}]}},"size":10}
whole problem was uppercase wildcard search. I was looking for *N* and have zero results and with *n* it fine.

How to add custom property to Symfony Doctrine YAML mapping file

Can anyone tell me how to add custom property to doctrine ORM yml file?
My idea is to add a property like this:
fields:
name:
type: string
localizable: true
Then I would like to get information about this localizable property by using
protected function getEntityMetadata($entity)
{
$factory = new DisconnectedMetadataFactory($this->getContainer()->get('doctrine'));
return $factory->getClassMetadata($entity)->getMetadata();
}
and then:
$met = $this->getEntityMetadata($bundle.'\\Entity\\'.$entity);
$this->metadata = $met[0];
$fields = $this->metadata->fieldMappings;
if (isset($fields)) {
foreach ($fields as $field => $fieldMapping) {
if (isset($fieldMapping['localizable']) && $fieldMapping['localizable'] == true) {
// Do sth with it
}
}
}
The way doctrine is written makes this awkward. It seems like you'd like to keep the Yaml mapping but just add a single property. I think you can create your own custom driver extending from the one provided. The Yaml driver has mostly private methods so overriding a little bit of the functionality is difficult, but it is possible.
I created a custom driver that extends from the SimplifiedYamlDriver. The naming of the driver is important because doctrine extension will try to load one of their drivers based what comes before Driver. It also does a strpos check for Simplified in the name, so I think the safest bet is to keep the original name completely and give the original an alias.
use Doctrine\ORM\Mapping\Driver\SimplifiedYamlDriver as BaseDriver;
class SimplifiedYamlDriver extends BaseDriver
{
public function loadMetadataForClass($className, ClassMetadata $metadata)
{
parent::loadMetadataForClass($className, $metadata);
$element = $this->getElement($className);
if (!isset($element['fields'])) {
return;
}
foreach ($element['fields'] as $name => $fieldMapping) {
if (isset($fieldMapping['localizable'])) {
$original = $metadata->getFieldMapping($name);
$additional = ['localizable' => $fieldMapping['localizable']];
$newMapping = array_merge($original, $additional);
$metadata->fieldMappings[$newMapping['fieldName']] = $newMapping;
}
}
}
}
Then I told Symfony to use this driver by overriding the class inside app/config/parameters.yml
parameters:
doctrine.orm.metadata.yml.class: MyBundle\SimplifiedYamlDriver
Then I updated the mapping like in your example inside MyBundle/Resources/config/doctrine/Foo.orm.yml
MyBundle\Entity\Foo:
type: entity
id:
id:
type: integer
generator:
strategy: IDENTITY
fields:
text:
type: string
localizable: true
And I can fetch this mapping wherever I have access to doctrine with:
$mapping = $this
->getDoctrine()
->getEntityManager()
->getClassMetadata(Foo::class)
->getFieldMapping('text');
Will give me:
Array
(
[fieldName] => text
[type] => string
[columnName] => text
[localizable] => 1
)
Unfortunately, this is impossible without rewriting a significant part of Doctrine DBAL. This would impact drivers (YAML, annotation...), meta data generator...
In your case, the simplest I see would be to add a custom type let's say LocalizableString (I guess at most you will need that and maybe LocalizableText).
Adding a type is relatively straightforward, since you can extend a base type so you don't have to write any SQL. You can refer to Doctrine documentation here and Doctrine bundle one here.
Then you can just do:
$met = $this->getEntityMetadata($bundle.'\\Entity\\'.$entity);
$this->metadata = $met[0];
$fields = $this->metadata->fieldMappings;
if (isset($fields)) {
foreach ($fields as $field => $fieldMapping) {
if ($this->getClassMetadata()->getTypeOfField($field) === 'localized_string') {
// Do sth with it
}
}
}

How to add custom condition to Sonata global search feature

I would like to add a custom condition to the queries which are generated by Sonata Search feature. The problem is that i have 'status' column which should be set as "active". On the List View i do not have any problem because I am able to set:
protected $datagridValues = array (
'status' => array ('type' => 1, 'value' => Status::ACTIVE)
);
and then all queries check if the status field is set properly.
But the problem is with global search. I can override SearchHandler and force desired behavior, but i can't change any files from vendor/ directory, so i have two questions.
How can i inject my own SearchHandler, which configuration file i need to change and how
Maybe there is a simpler way to develope needed solution?
SOLUTION:
I have figure out how can i inject my own SearchHandler. The following code is used for that:
1. Just edit your services.yml file and put something like that:
cmsbundle.search.handler:
class: XXX\CmsBundle\Search\SearchHandler
arguments:
- #sonata.admin.pool
sonata.admin.block.search_result:
class: XXX\CmsBundle\Search\AdminSearchBlockService
tags:
- { name: sonata.block }
arguments:
- sonata.admin.block.search_result
- #templating
- #sonata.admin.pool
- #cmsbundle.search.handler
Create the file "XXX\CmsBundle\Search\AdminSearchBlockService" and change SearchHandler instance to yours own
Create the file "XXX\CmsBundle\Search\SearchHandler" and change implementation. It can be something like that:
foreach ($datagrid->getFilters() as $name => $filter) {
/** #var $filter FilterInterface */
if ($filter->getOption('global_search', false)) {
if ($filter->getName() !== 'status') {
$filter->setCondition(FilterInterface::CONDITION_OR);
$datagrid->setValue($name, null, $term);
} else {
$filter->setCondition(FilterInterface::CONDITION_AND);
$datagrid->setValue($name, null, 'active');
}
$found = true;
}
}
IMPORTANT
'status' field must be added to configureDatagridFilters method in Admin class.
I thought I'd add my solution to this problem.
My problem was similar, my Admin class would modify the Admin Entities' respective createQuery. This query would add in restrictions so that the user can only view their models, or only view things which are not deleted for example.
The problem is the SearchHandler.php would set ALL filters as
$filter->setCondition(FilterInterface::CONDITION_OR);
This would cause queries to look like:
( myAddedCondition OR filterCondition OR filterCondition OR filterCondition )
What I really wanted instead was:
( myAddedCondition ) AND ( filterCondition OR filterCondition OR filterCondition )
In order to achieve this, I registered a GLOBAL ASTWalker which iomplements the walkWhereClause method.. Then in the Walker I would manually edit the generated SQL to suit my requirements.

Symfony2: how to set url only with the slug [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Custom symfony routing based on doctrine
I have several url in my project related to each object type. Ex.
For products:
/product/product-1
/product/product-2
But now I created a controller for general info management. Ex. terms of use, about us ..etc.
I want urls that only contains the page slug.
/terms-use
/about-us
Not:
/page/terms-use
/page/about-us
How to define this in routing.yml?
Venu is right, Custom symfony routing based on doctrine provides a way to do this, the only complication comes if your slug parameter is built by adding slugs of parent pages such that the grandchild page has a slug like grandparent-slug/parent-slug/child-slug in which case an exception would be thrown.
We used routing to match slugs like the example I gave and it required some regex in the annotations:
/**
* #Route("{slug}", name="page_index", defaults={"slug" = false}, requirements={"slug" = "[0-9a-zA-Z\/\-]*"})
* #Template()
*/
public function indexAction($slug)
{
if ($slug !== false) {
$page = $this->findPage($slug);
The above requirements annotation means that the slug can be alphanumeric with forward slashes and hyphens. You then need to implement a method findPage($slug) that explodes the slug on forward slashes and finds the correct child page.
Because the route matches so many other routes, it is important to include this controller last in the routing.yml file and this action last of the public actions in the controller so that all other routes are matched first.
EDIT
This is the findPage method that we wrote to find a page from the above slug:
protected function findPage($slug_string, $first_page = false)
{
$slug_array = explode("/", $slug_string);
$slug = array_shift($slug_array);
$page = $this->em->getRepository("PagesBundle:Page")->getPageBySlug($slug, $this->site_id);
if (!$page) {
return false;
}
// if only the first matched page is required return it
if ($first_page) {
return $page;
}
// Otherwise loop through the slug array and match recursive
//children until slug array is empty or no match found
while (!empty($slug_array)) {
if ($page->getChildren()) {
$slug = array_shift($slug_array);
foreach ($page->getChildren() as $child_page) {
if ($child_page->getSlug() == $slug) {
$page = $child_page;
break;
}
}
} else {
return false;
}
}
return $page;
}

Symfony Localized Routes - Optional Locale

I'd like the following urls to serve the appropriate actions:
/ - indexAction
/fr - indexAction
/foo - detailsAction (slug = foo)
/fr/foo - detailsAction (slug = foo)
I have added the following action methods:
/**
* #Route("/{_locale}", name="home", defaults={"_locale": ""}, requirements={"_locale": "fr|es"})
*/
public function indexAction() {
...
}
/**
* #Route("/{_locale}/{slug}", name="details", defaults={"_locale": ""}, requirements={"_locale": "fr|es"})
*/
public function detailsAction($slug) {
...
}
This works fine if I go to /, /fr and /fr/foo. However when I go to /foo it doesn't find a matching route. I'd appreciate it if someone could show me how to this.
Please note that ideally i'd like to achieve this without having to add multiple #Route annotations for a particular action method. That way I can use the UrlGenerator and point to the same name to produce the localized and none localized route whether I pass the _locale parameter or not.
I have managed to get this to work although my solution is slightly hacky. First I removed {_locale} part of the path, the defaults and requirements from my routes above.
Then when I created my routes I said:
$routes = new RouteCollection();
// Load the routes
...
$routes->addPrefix('/{_locale}', ['_locale' => ''], ['_locale' => '|fr|es']);
This automatically adds the localization bits (removed above) to the routes so it can easily be configured in one place. I changed RouteCollection to my own type with the following:
use Symfony\Component\Routing\RouteCollection as BaseRouteCollection;
class RouteCollection extends BaseRouteCollection {
public function addPrefix($prefix, array $defaults = [], array $requirements = []) {
foreach ($this->all() as $route) {
$route->setPath($prefix . rtrim($route->getPath(), '/'));
$route->addDefaults($defaults);
$route->addRequirements($requirements);
}
}
}
This makes sure the localized home page route doesn't end with a forward slash e.g. /fr/.
Finally I had to override the Route class with the following:
use ReflectionProperty;
use Symfony\Component\Routing\Route as BaseRoute;
class Route extends BaseRoute {
public function compile() {
// Call the parent method to get the compiled route
$compiledRoute = parent::compile();
// Override the regex property
$property = new ReflectionProperty($compiledRoute, 'regex');
$property->setAccessible(true);
$property->setValue($compiledRoute, str_replace('^/', '^/?', $compiledRoute->getRegex()));
return $compiledRoute;
}
}
This is particularly hacky but does save you from having to add a heap more code. All it does is replace the regular expression so that the first forward slash is optional which allows the /foo url to work. Note: You will have to make sure your RouteCollection is a collection of this class and not the Symfony Route class.
Hope this helps.

Resources