Auto quote reserved words with Doctrine 2 - doctrine-orm

Is there a way to auto quote reserved words with Doctrine 2 when using $entityManager->find('entity', id) ?
When using the query builder this can be done but there should be a global configuration setting that does this? I don't want to have to specify it in the annotations for the reserved words.

This was an issue I raised a while back with the Doctrine team.
https://github.com/doctrine/doctrine2/issues/2409
The ticket was closed with the comment:
You have to manually escape characters with #Column(name="`integer`")
So I guess you'd need to deal with any reserved keywords in your annotations

4.6. Quoting Reserved Words
Sometimes it is necessary to quote a column or table name because of reserved word conflicts. Doctrine does not quote identifiers automatically, because it leads to more problems than it would solve. Quoting tables and column names needs to be done explicitly using ticks in the definition.
<?php
/** #Column(name="`number`", type="integer") */
private $number;
Doctrine will then quote this column name in all SQL statements according to the used database platform.
Identifier Quoting does not work for join column names or discriminator column names unless you are using a custom QuoteStrategy.
For more control over column quoting the Doctrine\ORM\Mapping\QuoteStrategy interface was introduced in 2.3. It is invoked for every column, table, alias and other SQL names. You can implement the QuoteStrategy and set it by calling Doctrine\ORM\Configuration#setQuoteStrategy().
The ANSI Quote Strategy was added, which assumes quoting is not necessary for any SQL name. You can use it with the following code:
<?php
use Doctrine\ORM\Mapping\AnsiQuoteStrategy;
$configuration->setQuoteStrategy(new AnsiQuoteStrategy());
http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/basic-mapping.html#quoting-reserved-words

It's not implemented by Doctrine just because it's too platform-depending.
All you need, is implement own QuoteStrategy.
For example, for symfony project:
Copy-paste vendor AnsiQuoteStrategy class, rename it and make some quoting:
AppBundle/ORM/QuoteStrategy.php
namespace AppBundle\ORM;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\ORM\Mapping as M;
class QuoteStrategy implements M\QuoteStrategy
{
private function quote($token, AbstractPlatform $platform)
{
// implement your quote strategy
switch ($platform->getName()) {
case 'mysql':
default:
return '`' . $token . '`';
}
}
// add quoting to appropriate methods
public function getColumnName($fieldName, M\ClassMetadata $class, AbstractPlatform $platform)
{
return $this->quote($class->fieldMappings[$fieldName]['columnName'], $platform);
}
// ... Rest methods
}
Then, register your quote strategy as a service:
src/AppBundle/Resources/config/services.yml
app.orm.quote_strategy:
class: AppBundle\ORM\QuoteStrategy
public: false
Then, use it for your entitymanager configuration:
app/config/config.yml
orm:
entity_managers:
default:
quote_strategy: app.orm.quote_strategy
That is all :)

Per the statement made by #tim-lytle, I have re-raised the issue. This really should be included with Doctrine ORM's scope of safety.
https://github.com/doctrine/doctrine2/issues/5874

Related

UploadableFilePath field in entity definition is ignored (uploadable doctrine extensions)

Summary
My problem is connected with the fact that the entity field marked with #Gedmo\UploadableFilePath annotation is ignored by Symfony3. I am using the Uploadable behavior extension for Doctrine2.
CODE
In my entity I have:
/**
* #ORM\Column
* #Gedmo\UploadableFileName
*/
private $name;
/*
* #ORM\Column
* #Gedmo\UploadableFilePath
*/
private $path;
SYMPTOMS
At first, I have noticed though that the path column is not generated in MySQL.
Then I found out that whenever I delete name field I get the following error:
[Gedmo\Exception\InvalidMappingException] Class
"AppBundle\Entity\plik" must have an UploadableFilePath or Uploadable
FileName field.
Documentation
In doctrine-uploadable documentation I see that:
#Gedmo\Mapping\Annotation\UploadableFilePath: This annotation is used
to set which field will receive the path to the file. The field MUST
be of type "string". Either this one or UploadableFileName annotation
is REQUIRED to be set.
so it seems that I should be able to set $path field only.
Help request
Please advice why is UploadableFilePath field not being generated and why can't I delete the $name field?
It seems that I have made a simple typo. There was lack of one * in the comment line.
/**
* #ORM\Column
* #Gedmo\UploadableFilePath
*/
private $path;
It seems that symfony ignores annotations in such a case.

Change feature name in gate document with JAPE or Groovy

I have a GATE document like that:
I need to change the name of a feature in the annotation. Here i need to change typeby category
Is it possible to do that with a JAPE rule or Groovy script ?
Yes, either. A JAPE rule is probably the simplest:
Phase: RenameFeature
Input: Mention
Options: control = all
Rule: Rename
({Mention}):mention
-->
:mention {
for(Annotation a : mentionAnnots) {
a.getFeatures().put("category", a.getFeatures().remove("type"));
// note Map.remove returns the value we just removed
}
}
Inside a RHS Java block labelled with :label the variable labelAnnots is an AnnotationSet containing the annotations that were matched by the label on the LHS. In this case there's only one of them but the for loop is still the most convenient way to access the individual Annotation from the set.

Annotating a document with JAPE

I have been searching for a solution to this for weeks, I have some documents(about 95) that I am trying to classify using GATE. I have put them in one corpus I called training_corpus, however, after ANNIE has annotated the corpus, I have to go back into each file, select all token in the document, and create an annotation called Mention, with feature type and value the class for the document. for example:
type Start End id Features
Mention 0 70000 2588 {type=neg}
Is there anyway to automatically do this with JAPE? Basically, I want to select all tokens and create a new annotation with feature(type=class). Also, the class is appended to the document. Since there are many documents, can JAPE extract the class from the document name and set it to the value of Mentions feature. Example document name is neg_data1.txt, so the annotation will be Mention.type = neg?
Any help will be greatly appreciated. Thanks
I think you answered to your question by yourself.If the class assignment based on just a token present in text - why not simply process text outside of GATE?
For example to create an xml file like:
text and then use it in training process.
Also you can create a simple JAPE rule which will:
a) will take a text within document boundaries (see gate.Utils.length methods AFAIR)
b) based on presence of your token will create a new Annotation instance with features necessary.
an abstract example:
Phase: Instance
Input: Token
Options: control = once
Rule:Instance
(
{Token}
):instance
-->
{
AnnotationSet instances = outputAS.get("INSTANCE_ANNOTATION");
FeatureMap featureMap = Factory.newFeatureMap();
if (instances!=null&&!instances.isEmpty()){
featureMap.put("features when annotation presented in doc");
}else{
featureMap.put("features when annotation not in doc");
}
outputAS.add(new Long(0), new Long(documentLength), "Mention", featureMap);
}

zf2 acl doctrine 2

Actually using Zend Framework 2, I am looking for a way to implement a performant ACL strategy based on a database.
The whole idea is to directly filter the DQL queries depending on the currently logged in user, and it's permissions.
I found an implementation of this mecanisme in Symfony 2 http://symfony.com/doc/current/cookbook/security/acl_advanced.html, in this case one table seems to store for each user if he has access to a single row, so we can easily dynamically load only allowed rows by joining this table.
To synthesize,I am looking for a way to define access rules to entities based on criterias, but want to be able to get results in a single query to be able to do some ordering, and pagination.
Are there any ZF2 modules to resolve this case ?
It looks like integrating the SF2 security component as standalone is not an option: Security component from Symfony 2.0 as standalone
You have to use doctrine filter for load things for current member
example of my codes adding the filter for member query :
$em = $sm->get('doctrine.entitymanager.orm_default');
$ormconfig = $sm->get('doctrine.configuration.orm_default');
$ormconfig->addFilter("member", "\PatrickCore\Script\ORM\Functional\MemberAccessFilter");
//
$currentUser = $membersService->getCurrentUser();
$uid = $currentUser->getId();
$filter = $em->getFilters()->enable("member");
$filter->setParameter('member', $uid);
and this file \PatrickCore\Script\ORM\Functional\MemberAccessFilter :
<?php
namespace PatrickCore\Script\ORM\Functional;
use Doctrine\ORM\Mapping\ClassMetaData,
Doctrine\ORM\Query\Filter\SQLFilter;
class MemberAccessFilter extends SQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
// Check if the entity implements the LocalAware interface
if (!$targetEntity->reflClass->implementsInterface('\PatrickCore\Entity\MemberAccessAware')) {
return "";
}
return $targetTableAlias.'.member_id = ' . $this->getParameter('member'); // getParameter applies quoting automatically
}
}

Doctrine2 case-sensitive query

for some reason I need to query 'case-sensitive' in MySql + doctrine 2. Is it possible?
neither
$em->find('UserEn', 'Bob')
nor
$q = $this->em->createQuery('select u from UserEn u where u.name = :name');
$q->setParameter('name', 'Bob');
$result = $q->getResult();
is working. Any idea?
Maybe you are using a MySQL collation ending with "_ci", like "utf8_general_ci". "ci" stands for "case insensitive".
If this is the case, it is not a Doctrine issue, but a MySQL issue.
See http://dev.mysql.com/doc/refman/5.0/en/case-sensitivity.html
"The default character set and collation are latin1 and latin1_swedish_ci, so nonbinary string comparisons are case insensitive by default."
For those that are unable to change their database collation, you can use the BINARY operator in order to force case sensitivity on the criteria.
The BINARY operator casts the string following it to a binary string.
This is an easy way to force a comparison to be done byte by byte
rather than character by character. BINARY also causes trailing spaces
to be significant.
See MySQL BINARY Operator for more details.
To enable the BINARY operator in Doctrine DQLs, you can install the Doctrine Extensions library.
Or create your own Binary String Function like so.
use Doctrine\ORM\Query\AST\Functions\FunctionNode,
Doctrine\ORM\Query\Lexer;
class Binary extends FunctionNode
{
private $stringPrimary;
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->stringPrimary = $parser->StringPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return 'BINARY('.$sqlWalker->walkSimpleArithmeticExpression($this->stringPrimary).')';
}
}
Next you'll need to register the binary string function with your doctrine configuration. You can do so in your configuration settings or add it as needed like so.
$em->getConfiguration()->addCustomStringFunction('binary', 'DoctrineExtensions\\Query\\Mysql\\Binary');
Then you will be able to use the binary(...) function in your DQL like so.
$q = $em->createQuery('select u from UserEn u where binary(u.name) = :name');
echo $q->getSQL();
/* SELECT ... FROM ... WHERE BINARY(u0_.name) = ? */
To add the binary string function using the Symfony Framework, in your config.yml file change the doctrine.orm.entity_managers.%entity_manager%.dql setting like so.
doctrine:
orm:
#...
entity_managers:
#...
default:
#...
dql:
#...
string_functions:
#...
binary: 'DoctrineExtensions\Query\Mysql\Binary'
See Symfony Doctrine Configuration Documentation for more details
It's not Doctrine issue you have to change table collation to binary then case sensitive would work.
Do alter table and change this
CHARSET=utf8 COLLATE=utf8_general_ci
to this
CHARSET=utf8 COLLATE=utf8_bin