Cake PHP complex find 'OR' is not working properly with null and empty string

社会主义新天地 提交于 2020-01-03 16:23:08

问题


Cake PHP complex find 'OR' opertor is not working properly with null...

$conditions = array(
    'Person.id' => array(2, 4, 1, 23, 45, 11),
    'OR' => array(
    array(
        array('NOT' => array('Person.image' => null)),
        array('NOT' => array('Person.image' => '')),
    ),
    array(
        array('NOT' => array('Person.photos' => null)),
        array('NOT' => array('Person.photos' => '')),
    )
    )
);

The corresponding cake sql dump output query as below

SELECT `Person`.`id`, `Person`.`created`, `Person`.`modified` 
FROM `people` AS `Person` WHERE `Person`.`id` IN (2, 4, 1, 23, 45, 11)  AND 
((((NOT (`Person`.`image` IS NULL)) AND (NOT (`Person`.`image` = NULL))))   OR 
(((NOT (`Person`.`photos` IS NULL)) AND (NOT (`Person`.`photos` = ''))))) 
ORDER BY FIELD(`Person`.`id`, 2, 4, 1, 23, 45, 11) ASC LIMIT 3

In cake condition array, I have given Person.image is not null or '', but corresponding cake sql outputs as (NOT (Person.image IS NULL)) AND (NOT (Person.image = NULL)) where it should be like (NOT (Person.image IS NULL)) AND (NOT (Person.image = '')) .

Here Person.image both are compared with NULL itself(IS NULL and = NULL), where Person.image = NULL want to compared with empty string like Person.image = ''.

Here 'Person.image' is 'INT' and 'Person.photos' is 'VARCHAR' of type, but it is difficult to change type from current stage.

How it can be corrected ?


回答1:


You are not forced to use an associative array to define conditions. You can define it like so:

$conditions = array(
    'Person.id' => array(2, 4, 1, 23, 45, 11),
    'OR' => array(
    array(
        array('NOT' => array('Person.image' => null)),
        array('NOT' => array('Person.image = "" ')),
    ),
    array(
        array('NOT' => array('Person.photos' => null)),
        array('NOT' => array('Person.photos = "" ')),
    )
    )
);



回答2:


Perhaps there is an issue with interpreting 'Person.image <>' => null, since it is not strictly valid SQL (at least not in MySQL).

From the MySQL manual:

You cannot use arithmetic comparison operators such as =, <, or <> to test for NULL.

You could try replacing it with a negated null comparison:

array('NOT' => array('Person.image' => null))

Aside from that, your last two OR operators does nothing, since you only have one statement in each. Is your array nesting what you ment it to be? If you add newlines and indentation, your code becomes

$conditions = array(
    'Person.id' => array(2, 4, 1, 23, 45, 11),
    'OR' => array(
        array(
            'OR' => array(
                'Person.image <>' => null
            ),
            array(
                'Person.image <>' => ''
            )
        ),
        array(
            'OR' => array(
                'Person.photos <>' => ''
            ),
            array(
                'Person.photos <>' => null
            )
        )
    )
);

...which looks weird.

The full change would be:

$conditions = array(
    'Person.id' => array(2, 4, 1, 23, 45, 11),
    'OR' => array(
        array(
            array('NOT' => array('Person.image' => null)),
            array('NOT' => array('Person.image' => '')),
        ),
        array(
            array('NOT' => array('Person.photos' => null)),
            array('NOT' => array('Person.photos' => '')),
        )
    )
);



回答3:


It appears that Cake's null comparison depends on the database field type. If your field is of type integer then Cake will redefine '' as Null. Varchars will not be redefined.

Are you able to go to MySQL and change the Person.image type to varchar?

If so remember to clear your cache in app/tmp/cache/models for Cake to register changes.

UPDATE: manually changing the schema type will force cake to treat a field type as defined. So something like this prior to the query will work:

$this->Person->_schema['image']['type']='string';



回答4:


Sorry, those answers are in my opinion not 100% right, they provide workarounds but no solution.

The problem are the database column types:

Person.image is INT and Person.photos is VARCHAR of type

Well, '' (the empty string) is not a valid value for an integer, ever. I assume you have allowed NULL values on the Person.image column, so cake does the right job!

It just doesn't make any sense to ask if an integer field has the value of the empty string, it can only be NULL, 0, 1, -1, 2, -2, etc. (if signed).

What happens here is that cake knows about your data structure (note the DESCRIBE queries when the debug flag is > 0), so it tries to correct your statement to the next useful one - testing for NULL values. Moreover, even if you ask MySQL (or force cake doing so) to query your DB, there will never be any effect because of this condition (maybe because of the other ones):

SELECT * FROM table WHERE my_int_column = '' is completely legit SQL but will always return 0 results whereas SELECT * FROM table WHERE NOT(my_int_column = '') will always return all results.

Conclusion: if your app works by now with the ='' condition, it will work exactly the same without the condition.

Final note: However, you can INSERT the empty string into an integer column and it will be converted by MySQL to 0, so you might want to check for those.



来源:https://stackoverflow.com/questions/10932126/cake-php-complex-find-or-is-not-working-properly-with-null-and-empty-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!