martin-georgiev / postgresql-for-doctrine

PostgreSQL enhancements for Doctrine. Provides support for advanced data types (json, jssnb, arrays), text search, array operators and jsonb specific functions.

Home Page:https://packagist.org/packages/martin-georgiev/postgresql-for-doctrine

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Adding ILIKE support

llaakkkk opened this issue · comments

Hello Martin,

I use your package in my project, and I want to say BIG thanks for your work. Your package is really helpful.

And I want to suggest to you to add ILIKE function support.
I can do it by myself, but it would be great if you will help me with understanding what is inside your package.

Released in v1.1

public function restFindBy(array $criteria)
{
    $queryBuilder = $this->createQueryBuilder('shipping_segment');
    $queryBuilder->andWhere('shipping_segment.name ILIKE :filter OR shipping_segment.description ILIKE :filter');
    $queryBuilder->setParameter('filter', '%'.$criteria['filter'].'%');

    $pagerfanta = new Pagerfanta(new DoctrineORMAdapter($queryBuilder, false, false));
    return $pagerfanta->getCurrentPageResults();
}

error:

{
    "message": "[Syntax Error] line 0, col 102: Error: Expected =, <, <=, <>, >, >=, !=, got 'ILIKE'",
    "class": "Doctrine\\ORM\\Query\\QueryException",
    "trace": [
        {
            "namespace": "",
            "short_class": "",
            "class": "",
            "type": "",
            "function": "",
            "file": "S:\\OSPanel\\domains\\saas-shipping-backend.loc\\vendor\\doctrine\\orm\\lib\\Doctrine\\ORM\\Query\\QueryException.php",
            "line": 54,
            "args": []
        },
        {
            "namespace": "Doctrine\\ORM\\Query",
            "short_class": "QueryException",
            "class": "Doctrine\\ORM\\Query\\QueryException",
            "type": "::",
            "function": "syntaxError",
            "file": "S:\\OSPanel\\domains\\saas-shipping-backend.loc\\vendor\\doctrine\\orm\\lib\\Doctrine\\ORM\\Query\\Parser.php",
            "line": 456,
            "args": [
                [
                    "string",
                    "line 0, col 102: Error: Expected =, <, <=, <>, >, >=, !=, got 'ILIKE'"
                ],
                [
                    "object",
                    "Doctrine\\ORM\\Query\\QueryException"
                ]
            ]
        }
    ]
}

but LIKE works correctly

Which Doctrine version do you use @Gemorroj ?

Did you may try to trick Doctrine to parse with construction like (shipping_segment.name ILIKE :filter) = TRUE?

@martin-georgiev
doctrine/orm: v2.6.3

if add = TRUE, i got error:
[Syntax Error] line 0, col 103: Error: Expected Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS, got 'LIKE'

Can you upload your Doctrine configuration and entity mapping to debug?

this is Symfony 4 project

> php.exe S:\OSPanel\domains\saas-shipping-backend.loc\bin\console doctrine:mapping:info

 Found 16 mapped entities:

 [OK]   App\Entity\Admin
 [OK]   App\Entity\EmailToken
 [OK]   App\Entity\FlatRate
 [OK]   App\Entity\Origin
 [OK]   App\Entity\Platform
 [OK]   App\Entity\ResetPasswordToken
 [OK]   App\Entity\Settings
 [OK]   App\Entity\ShippingOption
 [OK]   App\Entity\ShippingRule
 [OK]   App\Entity\ShippingRuleCondition
 [OK]   App\Entity\ShippingSegment
 [OK]   App\Entity\ShippingSegmentAttribute
 [OK]   App\Entity\User
 [OK]   App\Entity\Website
 [OK]   Shapecode\Bundle\CronBundle\Entity\CronJob
 [OK]   Shapecode\Bundle\CronBundle\Entity\CronJobResult

Process finished with exit code 0 at 13:12:55.
Execution time: 970 ms.
> php.exe S:\OSPanel\domains\saas-shipping-backend.loc\bin\console debug:config doctrine

Current configuration for extension with alias "doctrine"
=========================================================

doctrine:
    orm:
        resolve_target_entities:
            Shapecode\Bundle\CronBundle\Entity\CronJobInterface: Shapecode\Bundle\CronBundle\Entity\CronJob
            Shapecode\Bundle\CronBundle\Entity\CronJobResultInterface: Shapecode\Bundle\CronBundle\Entity\CronJobResult
        default_entity_manager: default
        entity_managers:
            default:
                naming_strategy: doctrine.orm.naming_strategy.underscore
                auto_mapping: true
                mappings:
                    App:
                        is_bundle: false
                        type: annotation
                        dir: 'S:\OSPanel\domains\saas-shipping-backend.loc/src/Entity'
                        prefix: App\Entity
                        alias: App
                        mapping: true
                dql:
                    string_functions:
                        ALL_OF: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\All
                        ANY_OF: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Any
                        CONTAINS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Contains
                        IS_CONTAINED_BY: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\IsContainedBy
                        OVERLAPS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Overlaps
                        GREATEST: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Greatest
                        LEAST: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Least
                        ARRAY_APPEND: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayAppend
                        ARRAY_CARDINALITY: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayCardinality
                        ARRAY_CAT: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayCat
                        ARRAY_DIMENSIONS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayDimensions
                        ARRAY_LENGTH: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayLength
                        ARRAY_NUMBER_OF_DIMENSIONS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayNumberOfDimensions
                        ARRAY_PREPEND: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayPrepend
                        ARRAY_REMOVE: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayRemove
                        ARRAY_REPLACE: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayReplace
                        ARRAY_TO_JSON: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayToJson
                        ARRAY_TO_STRING: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ArrayToString
                        STRING_TO_ARRAY: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\StringToArray
                        IN_ARRAY: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\InArray
                        JSON_ARRAY_LENGTH: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonArrayLength
                        JSON_EACH: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonEach
                        JSON_EACH_TEXT: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonEachText
                        JSON_GET_FIELD: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonGetField
                        JSON_GET_FIELD_AS_INTEGER: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonGetFieldAsInteger
                        JSON_GET_FIELD_AS_TEXT: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonGetFieldAsText
                        JSON_GET_OBJECT: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonGetObject
                        JSON_GET_OBJECT_AS_TEXT: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonGetObjectAsText
                        JSON_OBJECT_KEYS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonObjectKeys
                        JSON_STRIP_NULLS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonStripNulls
                        TO_JSON: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ToJson
                        JSONB_ARRAY_ELEMENTS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbArrayElements
                        JSONB_ARRAY_ELEMENTS_TEXT: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbArrayElementsText
                        JSONB_ARRAY_LENGTH: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbArrayLength
                        JSONB_EACH: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbEach
                        JSONB_EACH_TEXT: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbEachText
                        JSONB_EXISTS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbExists
                        JSONB_INSERT: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbInsert
                        JSONB_OBJECT_KEYS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbObjectKeys
                        JSONB_SET: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbSet
                        JSONB_STRIP_NULLS: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\JsonbStripNulls
                        TO_JSONB: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ToJsonb
                        TO_TSQUERY: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ToTsquery
                        TO_TSVECTOR: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\ToTsvector
                        TSMATCH: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Tsmatch
                        ILIKE: MartinGeorgiev\Doctrine\ORM\Query\AST\Functions\Ilike
                    numeric_functions: {  }
                    datetime_functions: {  }
                query_cache_driver:
                    type: array
                    namespace: null
                    cache_provider: null
                metadata_cache_driver:
                    type: array
                    namespace: null
                    cache_provider: null
                result_cache_driver:
                    type: array
                    namespace: null
                    cache_provider: null
                class_metadata_factory_name: Doctrine\ORM\Mapping\ClassMetadataFactory
                default_repository_class: Doctrine\ORM\EntityRepository
                quote_strategy: doctrine.orm.quote_strategy.default
                entity_listener_resolver: null
                repository_factory: doctrine.orm.container_repository_factory
                hydrators: {  }
                filters: {  }
        auto_generate_proxy_classes: true
        proxy_dir: '%kernel.cache_dir%/doctrine/orm/Proxies'
        proxy_namespace: Proxies
    dbal:
        types:
            jsonb:
                class: MartinGeorgiev\Doctrine\DBAL\Types\Jsonb
                commented: true
            'jsonb[]':
                class: MartinGeorgiev\Doctrine\DBAL\Types\JsonbArray
                commented: true
            'smallint[]':
                class: MartinGeorgiev\Doctrine\DBAL\Types\SmallIntArray
                commented: true
            'integer[]':
                class: MartinGeorgiev\Doctrine\DBAL\Types\IntegerArray
                commented: true
            'bigint[]':
                class: MartinGeorgiev\Doctrine\DBAL\Types\BigIntArray
                commented: true
            'text[]':
                class: MartinGeorgiev\Doctrine\DBAL\Types\TextArray
                commented: true
            phone_number:
                class: Misd\PhoneNumberBundle\Doctrine\DBAL\Types\PhoneNumberType
                commented: true
            origin_address_type:
                class: App\DBAL\Types\OriginAddressTypeType
                commented: true
            shipping_option_type:
                class: App\DBAL\Types\ShippingOptionTypeType
                commented: true
            extra_fee_calc_type:
                class: App\DBAL\Types\ExtraFeeCalcTypeType
                commented: true
            shipping_option_error_message_action:
                class: App\DBAL\Types\ShippingOptionErrorMessageActionType
                commented: true
            shipping_rule_condition_operator:
                class: App\DBAL\Types\ShippingRuleConditionOperatorType
                commented: true
            shipping_rule_condition_additional_operator:
                class: App\DBAL\Types\ShippingRuleConditionAdditionalOperatorType
                commented: true
            shipping_segment_attribute_type:
                class: App\DBAL\Types\ShippingSegmentAttributeTypeType
                commented: true
            shipping_segment_attribute_operator:
                class: App\DBAL\Types\ShippingSegmentAttributeOperatorType
                commented: true
            shipping_segment_attribute_value:
                class: App\DBAL\Types\ShippingSegmentAttributeValueType
                commented: true
            shipping_rule_action:
                class: App\DBAL\Types\ShippingRuleActionType
                commented: true
        default_connection: default
        connections:
            default:
                driver: pdo_pgsql
                charset: UTF8
                url: '%env(resolve:DATABASE_URL)%'
                mapping_types:
                    jsonb: jsonb
                    'jsonb[]': 'jsonb[]'
                    _jsonb: 'jsonb[]'
                    'smallint[]': 'smallint[]'
                    _int2: 'smallint[]'
                    'integer[]': 'integer[]'
                    _int4: 'integer[]'
                    'bigint[]': 'bigint[]'
                    _int8: 'bigint[]'
                    'text[]': 'text[]'
                    _text: 'text[]'
                    shipping_segment_attribute_value: jsonb
                    shipping_rule_action: jsonb
                host: localhost
                port: null
                user: root
                password: null
                logging: true
                profiling: true
                options: {  }
                default_table_options: {  }
                slaves: {  }
                shards: {  }


Process finished with exit code 0 at 13:14:01.
Execution time: 3 612 ms.

ShippingSegment.php

<?php

namespace App\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Nelmio\ApiDocBundle\Annotation\Model;
use Swagger\Annotations as SWG;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Table(schema="shipping", uniqueConstraints={
 *     @ORM\UniqueConstraint(columns={"user_id", "name"})
 * })
 * @ORM\HasLifecycleCallbacks
 * @ORM\Entity(repositoryClass="App\Repository\ShippingSegmentRepository")
 */
class ShippingSegment
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     * @ORM\Column(type="integer", nullable=false, options={"unsigned": true})
     * @Groups({"default"})
     * @SWG\Property(description="Shipping segment id")
     */
    private $id;

    /**
     * @var string
     * @SWG\Property(description="Name")
     * @ORM\Column(type="string", length=255)
     * @Assert\Length(max=255)
     * @Assert\NotNull
     * @Groups({"default"})
     */
    private $name;

    /**
     * @var string|null
     * @SWG\Property(description="Description")
     * @ORM\Column(type="string", length=5000, nullable=true)
     * @Assert\Length(max=5000)
     * @Groups({"default"})
     */
    private $description;

schema

CREATE TABLE shipping.shipping_segment (id SERIAL NOT NULL, user_id INT NOT NULL, created_at TIMESTAMP(0) WITH TIME ZONE NOT NULL, updated_at TIMESTAMP(0) WITH TIME ZONE DEFAULT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(5000) DEFAULT NULL, PRIMARY KEY(id));

dump DQL:

SELECT shipping_segment FROM App\Entity\ShippingSegment shipping_segment WHERE ((shipping_segment.name ILIKE :filter) OR (shipping_segment.description LIKE :filter)) AND shipping_segment.user = :shipping_segment_user ORDER BY shipping_segment.id desc

@Gemorroj Could you please try ILIKE(shipping_segment.name,:filter) = TRUE ?

@llaakkkk Yes, it works =)