2

I'm currently working on a project that I came into several years after it was built. The code is mostly procedural with a few objects that act more like buckets of functions than anything else. I want to start fixing it up by consolidating the database access and external API calls into domain models.

I have the general idea down, but I don't know how to handle getting lists of my data when I have multiple filters. Having methods called $HelpRequestMapper->getById($id) work fine, but what do I do when the user wants to do multiple filters?

Should I have methods for each possible case? Ie, $HelpRequestMapper->getByCompanyAndUserAssignedToAndQueueAndStatusAndPriorityAndSearchString($company_id, $user_id, $queue_id, $status, $priority, $search_string) This seems like it would get unwieldy very fast and not be much better than what we have now.

Should I pass in an array/object and build a query from it using something like $HelpRequestMapper->getMultiple($array_of_options) that does some magical query building stuff to get the data I want?

Should I do something else?

Thanks

  • Is this PHP? ... – Robert Harvey Mar 11 '15 at 16:53
  • Yes, it is in php. I don't care if the answer is in php or not, though. – hosef Mar 11 '15 at 17:19
  • 1
    PHP has libraries that emulate Linq, which might be a possible solution. – Robert Harvey Mar 11 '15 at 17:21
0

It depends a bit on the implementation of the filter, but you could look into the Decorator Pattern and Strategy Pattern and see if they are of use to you.

You could solve this by creating an abstract Filter class with a filter-method that takes a list of objects and returns a list of objects. Each type of filter (CompanyFilter, UserAssignedFilter, QueueFilter...) would be a separate class that extends filter. When creating the filter you would pass the filter criteria in the constructor, and the implementation of the filter-method would take the objects passed to it and only return the ones matching the filter.

You could then have a RequestQuery that you can push filters onto which fetches the data, runs the data through all the filters and returns the result.

Quick demo in C#

public class MyObject
{
    public string Company { get; set; }
    public string UserAssignedTo { get; set; }
}

public abstract class Filter
{
    public abstract IEnumerable<MyObject> Apply(IList<MyObject> list);
}

public class CompanyFilter : Filter
{
    private string _companyToFilter;

    public CompanyFilter(string companyToFilter)
    { 
        _companyToFilter = companyToFilter;
    }

    public override IEnumerable<MyObject> Apply(IList<MyObject> list)
    {
        return list.Where(x => x.Company == _companyToFilter);
    }
}

public class UserAssignedToFilter: Filter
{
    private string _userToFilter;

    public UserAssignedToFilter(string userToFilter)
    { 
        _userToFilter = userToFilter;
    }

    public override IEnumerable<MyObject> Apply(IList<MyObject> list)
    {
        return list.Where(x => x.UserAssignedTo == _userToFilter);
    }
}

public class RequestQuery
{
    public IEnumerable<MyObject> FindData(IList<Filter> filtersToApply)
    {
        IList<MyObject> data = null; //fetch data somewhere

        foreach(var filter in filtersToApply)
        {
            data = filter.Apply(data);
        }

        return data;
    }
}
  • That's a lot of boilerplate, isn't it? If you're already in C#, why wouldn't you just hand an IQueryable to the consumer, and let them write var myFilteredList = Companies.Where(x => x.UserAssignedTo == someUser);? – Robert Harvey Mar 11 '15 at 19:46
  • There are several ways to optimize this depending on the language, and for this specific example Linq could indeed help out a lot. But I wanted to demonstrate the idea without resorting to too much language-specific tools and libraries. This code can be ported to a lot of other languages. – JDT Mar 12 '15 at 8:19
  • Thank you. I am think I am going to go with the strategy pattern, as it seems like the best fit to go into the existing structure. – hosef Mar 13 '15 at 17:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.