Coder Social home page Coder Social logo

search's Introduction

CakePHP Search

Build Status Coverage Status Latest Stable Version Total Downloads License

Search provides a simple interface to create paginate-able filters for your CakePHP application.

This branch is for CakePHP 5.x. For details see version map.

Installation

  • Install the plugin with composer from your CakePHP project's ROOT directory (where composer.json file is located)
php composer.phar require friendsofcake/search
  • Load the plugin by running command
bin/cake plugin load Search

Documentation

See Documentation section.

search's People

Contributors

admad avatar bravo-kernel avatar burzum avatar cake17 avatar carusogabriel avatar ceeram avatar cewi avatar dakota avatar davidspeijer avatar davidyell avatar dereuromark avatar dilab avatar inoas avatar jadb avatar jaywalker512 avatar jippi avatar johanmeiring avatar josegonzalez avatar lordsimal avatar lorenzo avatar marlinc avatar ndm2 avatar powtac avatar raul338 avatar steefaan avatar stickler-ci avatar stmeyer avatar swiffer avatar thinkingmedia avatar vonboth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

search's Issues

Add a helper to generate search form

I wrote a helper that automagically creates a complete search form based on the table's searchConfiguration() fields. I think it would be useful to include in this plugin.

use Cake\View\Helper;
use Cake\ORM\TableRegistry;

/**
 * SearchForm helper
 */
class SearchFormHelper extends Helper
{

    public $helpers = ['Form', 'Html'];

    /**
     * Default configuration.
     *
     * @var array
     */
    protected $_defaultConfig = [];

    /**
     * Output a complete search form, based on the search configurations set up
     * in the specified table
     *
     * @param $model string The Table to load
     * @return null|string An formatted FORM with inputs.
     */
    public function form($model)
    {
        $table = TableRegistry::get($model);

        // make sure the table has the behavior and has implemented the searchConfiguration method
        if (
            ! $table->behaviors()->has('Search') ||
            ! method_exists($table, 'searchConfiguration')
        ) {
            return null;
        }

        $searchConfig = $table->searchConfiguration()->all();

        $output = $this->Html->tag('h3', __('Search'));
        $output .= $this->Form->create();

        foreach ($searchConfig as $object) {
            $config = $object->config();

            // you can add stuff like `'multiple' => true` or `'empty' => ' '`
            // to the individual searchConfiguration field calls to be passed to
            // the form input
            $output .= $this->Form->input($config['name'], $config);
        }

        $output .= $this->Form->submit();
        $output .= $this->Form->end();

        return $output;
    }
}

The helper is loaded into the view, as normal, and is called in the template like this

<?= $this->SearchForm->form('Articles') ?>

(or if you want to be lazy, and copy-paste the same thing in all of your templates, you can call it like this)

<?= $this->SearchForm->form($this->request->params['controller']) ?>

search-form

Better handling of pagination query string keeping

Refs #114

The docs example is wrong and overcomplicated

    foreach (\Cake\Utility\Hash::flatten($this->request->query) as $param => $value) {
        echo $this->Form->hidden($param, compact('value'));
    }

is missing the page omission needed, and it is quite overcomplicated.
The search plugin of cakedc handled this a bit better.
Can we maybe find a configure way to not needing the overhead here in the templates?

Can not load CrudView.Search and Crud.Search listeners at the same time

After following the docs on how to use the search plugin with crud-view. I've run into an issue where a controller can not load two listeners in crud that have the same alias.

I'll show an example by loading the crud component and dumping the config.

        $this->loadComponent('Crud.Crud', [
            'actions' => [
                'Crud.Index',
                'Crud.Add',
                'Crud.Edit',
                'Crud.View',
                'Crud.Delete'
            ],
            'listeners' => [
                'Crud.Search',
                'Crud.Redirect',
                'CrudView.View',
                'CrudView.Search',
                'Crud.RelatedModels'
            ]
        ]);

        debug($this->Crud->config());die;

Will output this.

[
    'actions' => [
        'index' => [
            'className' => 'Crud.Index'
        ],
        'add' => [
            'className' => 'Crud.Add'
        ],
        'edit' => [
            'className' => 'Crud.Edit'
        ],
        'view' => [
            'className' => 'Crud.View'
        ],
        'delete' => [
            'className' => 'Crud.Delete'
        ]
    ],
    'eventPrefix' => 'Crud',
    'listeners' => [
        'search' => [
            'className' => 'CrudView.Search'
        ],
        'redirect' => [
            'className' => 'Crud.Redirect'
        ],
        'view' => [
            'className' => 'CrudView.View'
        ],
        'scaffoldFields' => [
            'className' => 'ScaffoldFields'
        ],
        'relatedModels' => [
            'className' => 'RelatedModels'
        ]
    ],
    'messages' => [
        'domain' => 'crud',
        'invalidId' => [
            'code' => (int) 400,
            'class' => 'Cake\Network\Exception\BadRequestException',
            'text' => 'Invalid id'
        ],
        'recordNotFound' => [
            'code' => (int) 404,
            'class' => 'Cake\Network\Exception\NotFoundException',
            'text' => 'Not found'
        ],
        'badRequestMethod' => [
            'code' => (int) 405,
            'class' => 'Cake\Network\Exception\MethodNotAllowedException',
            'text' => 'Method not allowed. This action permits only {methods}'
        ]
    ],
    'eventLogging' => false
]

Listeners has duplicate key for search so only one listener is loaded.

Seems to be a limitation by crud, but it leaves me wondering how anyone is getting the search and crud-view to work together?

search for CONCAT

Hello,
I have the age old issue of trying to search a user's full name. With this plugin, I'm trying to do it as so:

$search
            ->like('search', [
                'before' => true,
                'after' => true,
                'field' => [
                    $this->aliasField('username'),
                    "CONCAT(" . $this->aliasField('last_name') . ", ' ', " . $this->aliasField('first_name') . ")",
                ],
            ]);

The problem is, in the SQL query it becomes:
CONCAT(
Users.last_name, ' ', users.first_name
) like '%name%'

For some reason, it always removes capitalization from the second Users, and therefore throws an SQLSTATE[42S22]: Column not found error.

Filter 2 args at the same time

Hi
I want to process the search by having 2 arguments at the same time. Both arguments (but not necessary fields)

// URL:   example.com/articles?q=test&f=testing
$search = new Manager($this);

// Option A: results: the finder is called twice
$search->finder('q', ['finder' => 'custom']);
$search->finder('f', ['finder' => 'custom']);

// Option B: have a dummy function
$search->callback('q', [
        'callback' => function ($query, $args, $manager) {
            // do nothing
        }
    ])->callback('f', [
        'callback' => function($query, $args, $manager) {
            // debug($args);
            // apply logic
        }
    ]
);

Is there anyway to keep code clean or to avoid calling the finder twice? Something like

$search->finder(['q', 'f'], ['finder' => 'custom']);

Thanks for the plugin

how to implement DateBetween filter?

I want to implements all my search using this module, I want to implement all my search filters using this module, my problem is that I can't implement "DateBetween" filter.

View Question

Hello!

Not an issue but more of a newbie CakePHP 3.x question. How do I pass the search results to another view? Let's say, I have the search form on my index.ctp and want the results to display on search.ctp view.

Thanks,
Lyman

Mind the casing

The composer file states

"name": "friendsofcake/search",

The readme

require FriendsOfCake/search "dev-master"

Casing needs to be 100% in sync in order to not run into issues.

SearchBehavior unable to use non default filters collection.

The SearchManager has the ability to maintain multiple filter collections. For e.g. you can have separate collections for backend and frontend. But when using the search finder there's no way to tell it to which collection to use. It always uses the "default" collection.

The fix seems easy enough. Just allow passing a collection key to finder options and update the behavior to use SearchBehavior::getFilters() passing in the collection name instead of calling SearchBehavior::all() which always returns the default collection.

Search after pagination sort

When I open a new page (without a querystring) and sorts the content using PaginatorHelper::sort, it's being sorted fine. But when I now search something, the params of the sort are being removed from the querystring at the redirect stage (in the POST the URL querystring is still there).

I've updated $request->params['pass'] to $request->query in PrgComponent, which seems to work. But I'm not sure if this is the right fix.

RFC: Returning to search results after form action

Use-case
You are browsing a filtered set of results, and you edit a single item. The return url from the edit action should include the search params and page.

Implementation
This can be implemented by a developer in their add and edit actions. I think it might be nice if the plugin could provide a cleaner api for developers to use somehow. Perhaps the PrgComponent could have a method which returns the referring url?

Sidestep
It might just be as simple as return $this->redirect($this->referrer()) in which case it might be worth just adding it to the documentation.

Thoughts
I've created this as an RFC, just to gether some other peoples thoughts on the implementation, the value of the addition, and if it's worth just updating the docs instead.

Release readme mismatch

Regression introduced in #92

Currently the readme has been changed, but the details provided in the new version are not compatible with the latest 1.2.4 release.

So if like me you copy and paste from the readme into new projects, none of your code works until you figure out that you need the readme for the tag you're using.

Specifically, the change from filterParams() to _search

If it was me, I'd just do a new release with change notes and some guidance on what users of the plugin need to do to upgrade their application code.

Simplify the find('search') call

Why do I have to explicitly call filterParams() here?

->find('search', $this->Articles->filterParams($this->request->query))

I would move the call of filterParams() inside the behaviors findSearch() method. If desired it can be still made configurable. This would remove the need to add the filterParams() call manually in the controller.

Another thing I don't think that is ideal is this inside findSearch():

        if (isset($options['search'])) {
            $options = $options['search'];
        }

I would prefix the search with an _ like the core does it with _serialize, _ext and a few others as well. Because search is a term that is likely to get used in a filter form.

[Question] Does the search require POST or GET request?

I have set up this way

I have a CompaniesController under the namespace App\Controller\Api
like this:

class CompaniesController extends AppController
{

    public $components = [
        'Crud.Crud' => [
            'actions' => [
                'Crud.Index',
                'Crud.Add',
                'Crud.Edit',
                'Crud.View',
                'Crud.Delete',
            ],
            'listeners' => [
                'Crud.Api',
                'Crud.RelatedModels',
                'Crud.Search',
            ],
        ]
    ];
    /**
     * Index method
     *
     * @return void
     */
    public function index()
    {
        if (in_array($this->request->action, ['index', 'lookup'])) {
            $this->loadComponent('Search.Prg');
        }

        $this->Crud->on('beforePaginate', function(Event $event) {
            $this->paginate['conditions']['tessi_account_id'] = 2;
        });
        return $this->Crud->execute();
    }

My routes are:

Router::defaultRouteClass('DashedRoute');

Router::extensions(['json']);

// for prefix api
Router::prefix('api', function ($routes) {
    // All routes here will be prefixed with `/api`
    // And have the prefix => api route element added.
    $routes->resources('Companies');
    $routes->fallbacks('InflectedRoute');
});

since Search.Prg is used, does this mean I must use POST on /api/companies/index?q=abc?

What is the ideal way to proper do a search via API?

  1. GET or POST request ?
  2. the paramter q should be a query parameter or a form parameter?
  3. Should the url be /api/companies/index or simply /api/companies?

Note that I am also using crud plugin. If I should post this question in the crud repo, let me know and I will move this issue there.

Problems to install followiing the README

Hi, i am new to cakePHP, so this question is a beginner's one:

I installed CRUD and CRUD-view (nice work on that, by the way)

In the readme to install Search, it is told to configure the Table class
But what table class? I must create a new file in /src/Model/Table with the table name I want to apply the Search Plugin? or is it in vendor\cakephp\cakephp\src\ORM\Table.php ?

Also, is there any incompabilities with Crud and Crud-view?

Form not working

Hey, I got the plugin working but the form does not. I need to put manually the URL and then it works. (example: .../clients?dni=123)

This is the form code
echo $this->Form->create();
echo $this->Form->input('dni');
echo $this->Form->button('Filter', ['type' => 'submit']);
echo $this->Html->link('Reset', ['action' => 'index']);
echo $this->Form->end();

Improve test coverage

Would be nice to get test coverage in the 90s, currently it's around 82%. Contributions from the community welcome.

Docs improvement (or SearchHelper) to enable query-string persistence

If this is okay for you I could add this to the docs. It already supports scopes and will set all existing query parameters as default so that PRG will persist it through.

Example

    <?= $this->Form->create(null, ['id' => 'LanguagesFilterForm']) ?>
    <?php foreach (\Cake\Utility\Hash::flatten($this->request->query) as $param => $value): ?>
        <?= $this->Form->hidden($param, compact('value')) ?>
    <?php endforeach ?>
    <?= $this->Form->end() ?>

    <?php $this->Paginator->options(['defaultModel' => 'Languages']) ?>

    <table>
        <thead>
            <tr>
                <th>
                    <?= $this->Paginator->sort('code') ?>
                    <?= $this->Form->input('Languages.code', ['form' => 'LanguagesFilterForm', 'label' => false]) ?>
                </th>
                <th>
                    <?= $this->Paginator->sort('label') ?>
                    <?= $this->Form->input('Languages.label', ['form' => 'LanguagesFilterForm', 'label' => false]) ?>
                </th>
                <th class="actions">
                    <?= $this->Form->button('Filter', ['type' => 'submit', 'form' => 'LanguagesFilterForm']) ?>
                    <?= $this->Html->link('Reset', ['action' => 'index']) ?>    
                </th>
            </tr>
        </thead>

Minimal Example for the docs

<?= $this->Form->create() ?>
<?php foreach (\Cake\Utility\Hash::flatten($this->request->query) as $param => $value): ?>
    <?= $this->Form->hidden($param, compact('value')) ?>
<?php endforeach ?>
<?= $this->Form->input('Languages.code') ?>
<?= $this->Form->input('Languages.label') ?>
<?= $this->Form->button('Filter', ['type' => 'submit', 'form' => 'LanguagesFilterForm']) ?>
<?= $this->Form->end() ?>

Note: ยดHash::flatten()` is required because of nesting/scopes.

unknown method: searchConfiguration

I get the following error message

{
    "success": false,
    "data": {
        "message": "Unknown method \u0022searchConfiguration\u0022",
        "url": "\/api\/companies?q=wuhan",
        "code": 500,
        "trace": [
            {
                "file": "\/var\/virtual\/WebApps\/tessi\/cakephp3\/vendor\/friendsofcake\/search\/src\/Model\/Behavior\/SearchBehavior.php",
                "line": 70,
                "function": "__call",
                "class": "Cake\\ORM\\Table",
                "type": "-\u003E",
                "args": [
                    "searchConfiguration",
                    [

                    ]
                ]
            },
          //.......
        "exception": {
            "class": "BadMethodCallException",
            "code": 0,
            "message": "Unknown method \u0022searchConfiguration\u0022"
        }
    }
}

I did the following in my CompaniesTable

class CompaniesTable extends Table
{

    /**
     * Initialize method
     *
     * @param array $config The configuration for the Table.
     * @return void
     */
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->table('companies');
        $this->displayField('name');
        $this->primaryKey('id');

        $this->belongsTo('CompanyGroups', [
            'foreignKey' => 'company_group_id'
        ]);
        $this->hasMany('ContactPeople', [
            'foreignKey' => 'company_id'
        ]);
        // Add the behaviour to your table
        $this->addBehavior('Search.Search');

        $this->searchManager()
        ->add('company_id', 'Search.Value')
        // Here we will alias the 'q' query param to search:
        //     1. `Companies.name`
        // both before and after.
        ->add('q', 'Search.Like', [
            'before' => true,
            'after' => true,
            'field' => [$this->aliasField('name')]
        ]);
    }

I am using 1.1 version.

I followed the readme, so I didn't use the searchConfiguration method as it is the old way.

Should I use it anyway?

Proper LIKE syntax for wildcards

I would like to see this plugin also handle the LIKE syntax better than currently,
similar to the former cakedc one ( https://github.com/CakeDC/search/blob/master/Model/Behavior/SearchableBehavior.php#L31-L32 )

Users do not expect the sql syntax, nor should the plugin directly expose this sql specific one IMO.
Usually - like search engines do - they abstract it into a meta language, in this case using the well known * for any and ? for a specific single char.

This is especially important as right now, if you need to look for those specific % or _ chars, you get a lot of false positives here, e.g. when trying to find all that contain 22% discount etc, as those are not escaped either and directly enter the DB search as wildcards.

And if you ever need * and ? to be searchable (more unlikely as the other ones), then this would be configurable so you can adjust it on project level to be different ones.

I would like to know if there is an interest in implementing this in this plugin (only in the Like class of course).
If so I could look into fixing that in the near future.

Add Search.Boolean

<?php
namespace Search\Model\Filter;

class Boolean extends Base
{

    /**
     * Default configuration.
     *
     * @var array
     */
    protected $_defaultConfig = [
        'truthy' => [1, true, '1', 'true',  'yes', 'on'],
        'falsy' => [0, false, '0', 'false', 'no',  'off']
    ];

    /**
     * Check if a value is truthy/falsy and pass as condition.
     *
     * @return void
     */
    public function process()
    {
        if ($this->skip()) {
            return;
        }

        $value = strtolower($this->value());
        $bool = null;
        if (in_array($value, $this->config('truthy'), true)) {
            $bool = true;
        } elseif (in_array($value, $this->config('falsy'), true)) {
            $bool = false;
        }

        if ($bool !== null) {
            $this->query()->andWhere([$this->field() => $bool]);
        }
    }
}

Could also use FILTER_VALIDATE_BOOLEAN http://php.net/manual/de/filter.filters.validate.php... nopes, would return false for "".

... however through Session injection Search.Boolean could translate boolean representations coming from the user.

No documentation on how to filter?

So I've completed the readme and got everything setup, but the readme doesn't contain any instructions on how to actually use the code I've created to filter my data.

Do I need to post a form? Pass query params?

RFC: Default action settings for the PRG component

It is pretty annoying that by default the component is used for all actions. This can lead to funny issues and if you forgot about the Prg component, you'll have a nice "WTF?" moment when using actions with POST that are not supposed to use PRG.

IMHO it is wrong that the component makes use of PRG for all actions by default. It would be better if the user would have to specify them explicitly.

Remove csrfToken in PrgComponent

Do you think it would make sense to remove the _csrfToken in the PrgComponent? In general it's not necessary but it would keep the URL clean. What do you think? If you agree I will create a PR.

Ability to alias a finder in the url

example.com/index?availability=1

$search->finder('state');

How would I map my availability url param to my findState finder? Is this possible? I know from the docs you can use aliasField but I can't see a way to alias a finder.

[RFC] Add a method to get the manager to the behavior

A common thing that is annoying is that you have to add the manager class and create the method and everything.

Here is a BC compatible approach that will allow me to simply declare filters in my initialize() method right after I instantiated the behavior or in other methods:

Feel free to take the code from this ticket or close it, I won't do a PR.

    public function findSearch(Query $query, array $options)
    {
        if (!isset($options['filterCollection'])) {
            $options['filterCollection'] = 'searchConfiguration';
        }
        // For backward compatibility
        if (method_exists($this->_table, $this->config('filterCallback'))) {
            $manager = $this->_table->{$this->config('filterCallback')}();
        } else {
            $manager =  $this->searchFilter();
        }
        foreach ($manager->getFilters($this->config('filterCollection')) as $config) {
            $config->args($options);
            $config->query($query);
            $config->process();
        }

        return $query;
    }

    /**
     * Returns the search filter manager.
     *
     * @return \Burzum\Search\Search\Manager;
     */
    public function searchFilter()
    {
        if (empty($this->_manager)) {
            $this->_manager = new Manager($this->_table);
        }
        return $this->_manager;
    }

Can you make search fields optional?

Scenario
I have a blog with posts, tags and categories. A post doesn't have to be in a category. My filter form includes a like match for the title, and a dropdown of categories with 'empty' => true, using a value match on category_id.

Generated url possibilities
example.com/posts?q=welcome - Return posts containing 'welcome'
example.com/posts?q=welcome&category=8 - Return posts in category 8 with welcome in the title
example.com/posts?q=welcome&category= - Returns no results

Sidestep
So far the only way I can find to sidestep this is to use a custom find and check the $options array param for empty() and ignore it if it's empty.

Ideally
The CakeDC/search had a nice way of just marking a filter field as allowed to be optional, which would exclude it from searches if it was empty. Something like this would be ideal for scenarios where you want to filter using optionally null data.

Search.Prg killing request data

What I did
Added the Search.Prg component to my AppController.

What I expected to happen
I could save an edit form and the data would be saved and updated.

What actually happened
The form said it saved, yet no change to the data occurred.

How I fixed it
I removed the Search.Prg component and my form saved and updated as expected.

What I think the problem is
https://github.com/FriendsOfCake/search/blob/master/src/Controller/Component/PrgComponent.php#L20
An edit action is put, so this will wipe out the request data.

There should be a "isSearch" bool

The CakeDC search has a bool flag "isSearch" to be passed down to the view so the form knows if a "reset" button or alike is needed.
This is currently not possible with this one.
You cannot just use !empty(querystring) because that could contain some order/page params etc.

Is there an idea on how to get this implemented?
Then I can take a look into this.

Unable to redirect to named route

My project makes use of named routes in the front-end, and now I have a requirement to filter some data in the front-end of my project.

Unfortunately I hit a bug with the redirect, because it assumes that fallback routes are enabled, and doesn't specify the route.

https://github.com/FriendsOfCake/search/blob/master/src/Controller/Component/PrgComponent.php#L50

This will cause a Missing Route exception in projects which use named routes and do not have fallback routes enabled.

Also, just to compound matters I am using the same controller action on two routes to display two different sets of the same data. Open questions and closed questions.

    $routes->connect(
        '/users/my-predictions',
        ['controller' => 'UserAnswers', 'action' => 'index', 'type' => 'open'],
        ['pass' => ['type'], '_name' => 'userOpenPredictions']
    );
    $routes->connect(
        '/users/past-predictions',
        ['controller' => 'UserAnswers', 'action' => 'index', 'type' => 'expired'],
        ['pass' => ['type'], '_name' => 'userPastPredictions']
    );

Search on concatenated fields

Currently, I'm trying to search on two fields that are concatenated (in my case first_name and last_name merged into name). However, this setting doesn't work since it ignores Search.Like entirely (normal search on single field does work). I have the following code in my initialize method in my model:

$this->searchManager()
->add('id', 'Search.Value')
->add('q', 'Search.Like', [
'before' => true,
'after' => true,
'field' => [$this->aliasField('username'), $this->aliasField('name')]
])
->add('q', 'Search.Callback', [
'callback' => function ($query, $args, $manager) {
return $query->select(['name' => $query->func()->concat(
['first_name' => 'identifier', ' ' , 'last_name' => 'identifier']
)]);
}
]);

The controller function that calls the search plugin uses the crud plugin v4 and is nothing special:

public function index(){
$this->Crud->on('beforePaginate', function(\Cake\Event\Event $event) {
$event->subject()->query->select(['id', 'username']);
});
return $this->Crud->execute();
}

How can I search on concatenated fields?

Filtering ZIP/POST code not work

I implement this plugin and everything works great (full names, location, job titles), except for the filtering zip / post code that contain a combination of letters and numbers, example: BL6 2TZ

If I put in the filter only letters (BL) or numbers (6), plugin return results.

How to solve this problem?

<?= $this->Form->input('zipcode',['class' => 'form-control','label' => 'Postcode / Zipcode']); ?>

//
        $this->searchManager()
            ->add('name', 'Search.Like', [
                'before' => true,
                'after' => true,
                'field' => [$this->aliasField('name')]
            ])
            ->add('job_title', 'Search.Like', [
                'before' => false,
                'after' => true,
                'field' => [$this->aliasField('job_title')]
            ])
            ->add('location', 'Search.Like', [
                'before' => false,
                'after' => true,
                'field' => [$this->aliasField('city')]
            ])
            ->add('zipcode', 'Search.Like', [
                'before' => true,
                'after' => true,
                'field' => [$this->aliasField('zipcode')]
            ])
            ->add('country', 'Search.Like', [
                'before' => false,
                'after' => true,
                'field' => [$this->aliasField('country')]
            ]);


Like filter not using aliasField()

When using the like filter the fields are not being wrapped by Base::field() because they're instead using Base::fields() which doesn't call field() and thus the configuration for using aliasField() isn't respected.

This is contrary to the release notes, https://github.com/FriendsOfCake/search/releases/tag/2.0.1

This means that the following produce different results for my setup,

// Ambiguous field error
        $search
            ->like('name', [
                'before' => true,
                'after' => true,
                'field' => 'name'
            ])

// Works as expected
        $search
            ->like('name', [
                'before' => true,
                'after' => true,
                'field' => $this->aliasField('name')
            ])

tagged release / semver

Will there be a tagged release that makes clear that it is BC compatible according to semver and specifies a minimum cakephp versions?

Bug: aliasField is run twice for some Filter rules

Result is that the built query may look like this: Countries.Countries.code IN (:c0)

E.g. for Search.Like it is not, as like uses Base::fields() which extract out of (array)$this->config('field')
However for Search.Value it is being reapplied.

E.g. a setup like this

$this->searchManager()
    ->add($this->aliasField('code'), 'Search.Value', [
        'before' => true,
        'after' => true,
    ])
    ->add($this->aliasField('label'), 'Search.Like', [
        'before' => true,
        'after' => true,
    ])

Fails at the first add() call. When adding 'field' => $this->aliasField('code') it works again.
Thus:

EITHER Base::field() should be taught to only apply the alias/table name if not yet applied. Then Base::fields() should be made to work like Base::field() so that Search.Like works like the rest
OR Search.Value and all the others should work like Search.Like.

Filter by one argument with both field and callback

Hi,

I have a table with this searchConfiguration:

    public function searchConfiguration() {
        $search = new Manager($this);

        $search
            ->like('q', [
                'before' => true,
                'after' => true,
                'field' => [
                    $this->aliasField('code'),
                    $this->aliasField('company_name'),
                    $this->aliasField('first_name'),
                    $this->aliasField('last_name'),
                ],
            ])
            ->callback('q', [
                'callback' => function ($query, $args, $manager) {
                    $query
                        ->orWhere([
                            'Clients.id IN' => $this->Contacts->find('search', $this->Contacts->filterParams($args))
                                ->select([
                                    'Contacts.foreign_id',
                                ]),
                        ]);
                }
            ]);

        return $search;
    }

The second filter callback('q') overwrites the first filter like('q').
Is it possible to have both working at the same time?

Add namespace prefix FoC

I have the problem that we have a more or less huge application which was using the CakeDC search plugin initially. Due to the fact that both are using the Search namespace I'm getting a problem by loading both plugins side by side.

Can't we prefix the namespace of the plugin? Sure I could fork it and change it, but this is a good example of why vendor namespaces are useful.

defaultConfig[mode] missing from Compare?

I think it's not a big deal to implement "mode" config into Compare. When you would like to compare multiple values with same field but with "OR" relation, now you can't.
For example you would like to search in a webshop for products with prices wich are stored in different coulumns.
Thanks! I love this plugin!

[QUESTION] Breaking the parameter to search for more words in one input

I'm using this plugin for my search needs in CakePHP and I think it's really awesome, but I'm having trouble when the search uses more than one word. I'd like to know if there's an easy solution that breaks the parameter to search individually for them.

For example, "test1 test2" searches only for the whole string. I'd like to search for "test1" and "test2" independently.

Multiple values

What do you think about the support of multiple values ?

For example, if i need the following configuration :

$this->addBehavior('Search.Search');
$this->searchManager()
    ->add('place', 'Search.Like', [
        'before'=>true,
        'after'=>true,
        'field' => [$this->aliasField('ZipCode'), $this->aliasField('City')]
]);

As the Like filter only supports single value, I have created a child filter to supports arrays.

namespace App\Model\Filter;

use Cake\ORM\Query;

class LikeMultiple extends \Search\Model\Filter\Like
{

    /**
     * Process a LIKE condition ($x LIKE $y).
     * Allow multiple values
     *
     * @return void
     */
    public function process()
    {
        if ($this->skip()) {
            return;
        }

        $conditions = [];
        foreach ($this->fields() as $field) {
            $left = $field . ' ' . $this->config('comparison');

            if(is_array($this->value())) {
                foreach($this->value() as $value) {
                    $right = $this->_wildCards($value);
                    $conditions[] = [$left => $right];
                }
            }
            else {
                $right = $this->_wildCards($this->value());
                $conditions[] = [$left => $right];
            }
        }

        $this->query()->andWhere([$this->config('mode') => $conditions]);
    }
}

I think we can add this functionnality to Like filter directly. This can be extended to Compare too.
I can make a PR if needed.

What do you think about it and about security concerns ?

[RFC] new interface for searching

(Originally posted by @burzum on the wiki)

Instead of relying on the presence of searchConfiguration() in the table class I think a trait that adds a filters() method that returns a manager instance would be better. The interface could be similar to validation:

# Inside the Table instance

// Add filters to the "index" collection
$this->filters('index')
    ->add('field_name', 'like', $options)
    ->add('other_field', 'value', $options)

// Add filters to "otherName"
$this->filters('otherName')
    ->add('field_name', 'compare', $options);

// Returns all filters for the "index" collection
$this->filters('index')->get();

# Inside the Controller instance

// The find call could look like this then for example
 $query = $this->Country
    ->find('search', [$this->request->query, 'index'])
    ->where(['name !=' => null])
    ->order(['Country.id' => 'asc'])
    ->contain([
        'Cities'
    ]);

// Or maybe this?
 $query = $this->Country
    ->applyFilter('index', $this->request->query)
    ->where(['name !=' => null])
    ->order(['Country.id' => 'asc'])
    ->contain([
        'Cities'
    ]);

Find matching

I'm not sure if it is possible now or not, but i don't see it in documentation.

I need search by associated models, like this:

$this->ContentPages->find()->contain(['Tags'])->matching('Tags', function ($q) {
                return $q->where(['Tags.name' => 'test']);
            })

Is it possible? If not, would be possible to add it?

Thank you.

Feedback / RFC: Setup / Docs

I got some issues setting up search:

  1. For search to work like in the docs one must composer require dev-master. require friendsofcake/search will get you 1.1 which will not work with the new configuration way.
  2. As for an example how to reference an exact value this is what to do:
        $this->searchManager()
            ->add('id', 'Search.Value', [
                'field' => $this->aliasField('id'),
            ]);

If you don't specify field and do not use aliasField() you might get ambiguity errors in SQL queries
The example utilizing 'field' hashkey however suggests that it takes an array of fieldnames. This is not the case for Search.Value. Is this intentional? Is this a bug? Generates a query like WHERE Array IN (:c0) with the error "Notice (8): Array to string conversion [CORE/src/Database/Expression/Comparison.php, line 136]"

It seems, @hmic experienced similar issues for 1. and 2. implementing/integration search. Onces these issues are cleared it runs like a charm (for now ;)

Questions:

  • Should I change the docs to reflect that dev-master is requried (interim) - how would the composer command look (I changed the composer.json and ran compser update)?
  • Should I change the docs adding the above code snipplet (set to your articles example)?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.