johannesschobel / dingoquerymapper

Uses Dingo/API Request Query Parameters to filter Laravel Models
MIT License
12 stars 6 forks source link

Adding more fuzzy matching #15

Open sgtwinters opened 6 years ago

sgtwinters commented 6 years ago

Well, another one @johannesschobel :)

When working with the custom filters you now have the possibility to filter on strings 'starting with' using the String* filter. I have a lot of cases where I need a bit more fuzzy matching, for example matching a part of a string: 'A beautiful song I wrote'.

I would suggest expanding the createEvaluationRule method, listening for *String*, to fit this purpose?

private function createEvaluationRule($key, $operator, $value)
    {
        // first, check the operator type!
        if ($operator == '=') {
            $operator = '==';
        }

        // escaping
        $key = addslashes($key);

        $rule = "'%s' %s '%s'"; // key, operator, value
        $rule = sprintf($rule, $key, $operator, $value);

        // now check if the operator was "(not) like"?
        if (strpos($operator, 'like') !== false) {

            // check for %value% to perform a more fuzzy match
            if (preg_match('/%(.*).{1,}?%/', $value)) {

                $value = str_replace('%', '', $value);
                $rule = "%sis_int(stripos('%s', '%s')) ? true : false";

                $expectedResult = '';

                if (stripos($operator, 'not') !== false) {
                    // it is a NOT LIKE operator
                    $expectedResult = '!';
                }

                $rule = sprintf($rule, $expectedResult, $key, $value);

            } else {
                $value = str_replace('%', '', $value);    
                $rule = "substr('%s', 0, strlen('%s')) %s '%s'"; // haystack, $needle, $comparable, $needle

                $expectedResult = '===';

                if (stripos($operator, 'not') !== false) {
                    // it is a NOT LIKE operator
                    $expectedResult = '!==';
                }

                $rule = sprintf($rule, $key, $value, $expectedResult, $value);
            }  
        }

        return $rule;
    }

If you like the idea I can send in another PR?

johannesschobel commented 6 years ago

Hey man.. thank you very much for your additional input on this package ;) I remember, that i implemented some kind of like filter back then.. It works like this: /users?name=john*..

However, i am not sure if it works in "both" ways, like this /users?name=*oh*

sgtwinters commented 6 years ago

Hey @johannesschobel. Yes you did build the like filtering indeed, it works for 'a string starting with'. My code suggestion posted above adds a filtering rule (matching *string*) so that makes it work both ways :). Would like to review my suggestion (I can PR if you want)?

Thanks again!

johannesschobel commented 6 years ago

Hey man.. haha, maybe i was just to lazy to implement it on my own back then.. ^^ sure, submti a PR, so we can discuss the changes.. That would be great! Thank you very much!