Monday, 19 June 2017

Topic 22 - Generic Repositories ( FilterBy )

Introduction


In java, generic methods and classes enable programmers to specifiy, with a single method declaration, a set of related methods , or with a single class single class declaration , a set of related type, respectively. 

However inside laravel , we can do some generic repositories to filter out based on business logic that we can imply . Such as to extract all data / find specific data of a member inside society.


Repository

  public function filterBy($filter, $joins = NULL, $columns = array('*')) {
        $repository_filter = new RepositoryFilter($this->model, $filter, $joins);

        return $repository_filter->filter()->get($columns);
    }
Repository Filter

class RepositoryFilter {

    /**
    * @var
    */
    private $model;

    /**
    * @var
    */
    private $filter;

    /**
    * @var
    */
    private $join;

    /**
    * @param string $attribute
    * @param int $operator
    * @param mixed $value
    */
    public function __construct($model, $filter, $join)
    {
        $this->setModel($model);
        $this->setFilter($filter);
        $this->setJoin($join);
    }

    public function setModel($model)
    {
        $this->model = $model;
    }

    public function setFilter($filter)
    {
        $filter = collect($filter);
        $filtered = $filter->groupBy('group');

        $this->filter = $filtered->all();
    }

    public function setJoin($join)
    {
        $this->join = $join;
    }

    /**
    * @return \Illuminate\Database\Eloquent\Builder
    * @throws RepositoryFilterException
    */
    public function filter()
    {
        // Generate JOIN clause
        $this->_join();

        // Generate WHERE clause
        $this->_filter();

        return $this->model;
    }

    private function _join()
    {
        if (!empty($this->join)) {
            foreach ($this->join as $class => $type) {
                $model = new $class;
                $join = ($type == TABLE_JOIN_LEFT) ? 'leftJoin' : 'join';

                $this->model->$join($model->getTable(), $this->model->getQuery()->from . '.' . str_singular($model->getTable()) . '_id', '=', $model->getTable() . '.id');
            }
        }
    }

    private function _filter()
    {
        if (!empty($this->filter)) {
            foreach ($this->filter as $group => $filters) {
                if ($group > 0) {
                    $where = ($filters[0]->getLogic() == LOGICAL_OR) ? 'orWhere' : 'where';

                    $this->model->$where(function ($query) use ($filters){
                        foreach ($filters as $filter) {
                            $query = $this->_filterCriteria($filter, $query);
                        }
                    });
                } else {
                    foreach ($filters as $filter) {
                        $this->model = $this->_filterCriteria($filter, $this->model);
                    }
                }
            }
        }
    }

    private function _filterCriteria($filter, $model)
    {
        if (!$filter instanceof Filter) {
            throw new RepositoryFilterException("Class {$this->model()} must be an instance of App\\Repositories\\Eloquent\\Filter");
        }

        if (!empty($filter->getValue()) || $filter->getValue() != '') {
            $where = ($filter->getLogic() == LOGICAL_OR) ? 'orWhere' : 'where';

            switch ($filter->getOperator()) {
                case OPERATOR_EQUAL_TO:
                    if (is_array($filter->getValue())) {
                        $where .= 'In';
                        $model->$where($filter->getAttribute(), $filter->getValue());
                    } else {
                        $model->$where($filter->getAttribute(), '=', $filter->getValue());
                    }

                    break;
                case OPERATOR_GREATER_THAN:
                    $model->$where($filter->getAttribute(), '>', $filter->getValue());

                    break;
                case OPERATOR_LESS_THAN:
                    $model->$where($filter->getAttribute(), '<', $filter->getValue());

                    break;
                case OPERATOR_GREATER_THAN_OR_EQUAL_TO:
                    $model->$where($filter->getAttribute(), '>=', $filter->getValue());

                    break;
                case OPERATOR_LESS_THAN_OR_EQUAL_TO:
                    $model->$where($filter->getAttribute(), '<=', $filter->getValue());

                    break;
                case OPERATOR_NOT_EQUAL_TO:
                    if (is_array($filter->getValue())) {
                        $where .= 'NotIn';
                        $model->$where($filter->getAttribute(), $filter->getValue());
                    } else {
                        $model->$where($filter->getAttribute(), '!=', $filter->getValue());
                    }

                    break;
                case OPERATOR_CONTAIN_PHRASE:
                    $model->$where($filter->getAttribute(), 'like', '%' . $filter->getValue() . '%');

                    break;
                case OPERATOR_START_WITH_PHRASE:
                    $model->$where($filter->getAttribute(), 'like', $filter->getValue() . '%');

                    break;
                case OPERATOR_END_WITH_PHRASE:
                    $model->$where($filter->getAttribute(), 'like', '%' . $filter->getValue());

                    break;
                case OPERATOR_IN_BETWEEN:
                    $where .= 'Between';
                    $model->$where($filter->getAttribute(), $filter->getValue());

                    break;
                case OPERATOR_NOT_IN_BETWEEN:
                    $where .= 'NotBetween';
                    $model->$where($filter->getAttribute(), $filter->getValue());

                    break;
            }
        }

        return $model;
    }

Controller

public function postData(Request $request)
    {
      // Retrieve POST data(request) - to be use in the $filter array
       $patron_name = $request->get('patron');

       $filter = array(
       Filter::create('patrons.name', OPERATOR_CONTAIN_PHRASE, $patron_name),
      );

      // Filter option with target column
      $patron = $this->patron->filterBy($filter);

      // Instantiate Datatable Entity
      $datatables = Datatables::of($patron)
          ->addIndexColumn()
          ->add_column('namelink', function($patron){
            return
            '<a href="' . route('patron.show', $patron->id) .'">'.$patron->name.'</a>';
          })

          ->add_column('statuselection', function($patron){
            return
              $patron->StatusName;
          })

          ->add_column('studentselection', function($patron){
            return
              $patron->student->id_no;
          })

          ->add_column('applicantselection', function($patron){
              if((!empty($patron->libraryProfile->profile_name)) )
              {
                return $patron->libraryProfile->profile_name;
              }
          })
          ->add_column('action', function ($patron){
              return
              Form::iconUpdate(route('patron.edit', $patron->id))." ".
              Form::iconDelete(route('patron.destroy', $patron->id))." ";
          })
          ->rawColumns(['action','namelink','programselection','statuselection','applicantselection']);


          return $datatables->make(true);
    }

View

<script>

  var table = $('#patron-table').DataTable({
        {!! Config::get('datatable.setting') !!}
        ajax: {
          url: '{!! url("library/patron/data") !!}',
          method: 'POST',
          headers: {
              'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
          },
          data: function (d) {
                d.patron = $('input[name="patron"]').val();
                // d.patron_applicant = $('#patron_applicant').val();
                // d.patron_status = $('#patron_status').val();
          },
          error: function(data){
              // Error...
              var errors = data.responseJSON;
              $('html').html(data.responseText);
              console.log(data.responseText);
          }
        },
        columns: [
          { sTitle: 'No' , data:'DT_Row_Index', width: '5%' },
          { sTitle: 'Name', data: 'namelink', name:'name' , width: '15%'}, //data is database name // name is modelName for relationship
          { sTitle: 'ID Number', data: 'studentselection' , width: '10%' }, //data is database name // name is modelName for relationship
          { sTitle: 'Profile', data: 'applicantselection' , width: '10%'}, //data is database name // name is modelName for relationship
          { sTitle: 'Status', data: 'statuselection' , width: '10%'},
          { sTitle: 'Action', data: 'action', width: '10%'},
        ]
    });

    $('#B3-filter-box').on('submit', function(e) {
        table.draw();
        e.preventDefault();
    });

</script>





No comments:

Post a Comment