Conditions | 78 |
Paths | > 20000 |
Total Lines | 285 |
Lines | 19 |
Ratio | 6.67 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.
There are several approaches to avoid long parameter lists:
1 | <?php |
||
457 | function &search($criteria,$only_keys=True,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join='',$need_full_no_count=false) |
||
458 | { |
||
459 | //error_log(__METHOD__.'('.array2string(array_combine(array_slice(array('criteria','only_keys','order_by','extra_cols','wildcard','empty','op','start','filter','join','need_full_no_count'), 0, count(func_get_args())), func_get_args())).')'); |
||
460 | |||
461 | // if no CFs are defined OR used and became unavailable (deleted or permissions changed) |
||
462 | if (!$this->customfields && strpos($order_by, self::CF_PREFIX) === false && |
||
463 | (empty($filter) || strpos(implode(',', array_keys($filter)), self::CF_PREFIX) === false)) |
||
464 | { |
||
465 | return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count); |
||
466 | } |
||
467 | if ($only_keys === false) |
||
468 | { |
||
469 | $only_keys = $this->table_name.'.*'; |
||
470 | } |
||
471 | $extra_join_added = $join && strpos($join, $this->extra_join) !== false; |
||
472 | if ($criteria && is_string($criteria)) |
||
473 | { |
||
474 | $extra_join_added = true; // we have NOT added the join, as we use a sub-query and therefore not need it |
||
475 | |||
476 | $criteria = $this->search2criteria($criteria, $wildcard, $op); |
||
477 | } |
||
478 | if ($criteria && is_array($criteria)) |
||
479 | { |
||
480 | // check if we search in the custom fields |
||
481 | if (isset($criteria[$this->extra_value])) |
||
482 | { |
||
483 | // we should check if the CF is (still) available, but that makes the slow search even slower :( |
||
484 | if (($negate = $criteria[$this->extra_value][0] === '!')) |
||
485 | { |
||
486 | $criteria[$this->extra_value] = substr($criteria[$this->extra_value],1); |
||
487 | } |
||
488 | $criteria[] = $this->extra_table.'.'.$this->extra_value . ' ' .($negate ? 'NOT ' : ''). |
||
489 | $this->db->capabilities[Db::CAPABILITY_CASE_INSENSITIV_LIKE]. ' ' . |
||
490 | $this->db->quote($wildcard.$criteria[$this->extra_value].$wildcard); |
||
491 | unset($criteria[$this->extra_value]); |
||
492 | } |
||
493 | // replace ambiguous auto-id with (an exact match of) table_name.autoid |
||
494 | if (isset($criteria[$this->autoinc_id])) |
||
495 | { |
||
496 | View Code Duplication | if ($criteria[$this->autoinc_id]) |
|
497 | { |
||
498 | $criteria[] = $this->db->expression($this->table_name,$this->table_name.'.', |
||
499 | array($this->autoinc_id => $criteria[$this->autoinc_id])); |
||
500 | } |
||
501 | unset($criteria[$this->autoinc_id]); |
||
502 | } |
||
503 | // replace ambiguous column with (an exact match of) table_name.column |
||
504 | foreach($criteria as $name => $val) |
||
505 | { |
||
506 | // only add extra_join, if we really need it |
||
507 | if (!$extra_join_added && ( |
||
508 | is_int($name) && strpos($val, $this->extra_value) !== false || |
||
509 | is_string($name) && $this->is_cf($name) |
||
510 | )) |
||
511 | { |
||
512 | $join .= $this->extra_join; |
||
513 | $extra_join_added = true; |
||
514 | } |
||
515 | $extra_columns = $this->db->get_table_definitions($this->app, $this->extra_table); |
||
516 | if(is_string($name) && $extra_columns['fd'][array_search($name, $this->db_cols)]) |
||
517 | { |
||
518 | $criteria[] = $this->db->expression($this->table_name,$this->table_name.'.',array( |
||
519 | array_search($name, $this->db_cols) => $val, |
||
520 | )); |
||
521 | unset($criteria[$name]); |
||
522 | } |
||
523 | elseif (is_string($name) && $this->is_cf($name)) |
||
524 | { |
||
525 | if ($op != 'AND') |
||
526 | { |
||
527 | $name = substr($name, 1); |
||
528 | if (($negate = $criteria[$name][0] === '!')) |
||
529 | { |
||
530 | $val = substr($val,1); |
||
531 | } |
||
532 | $cfcriteria[] = '(' . $this->extra_table.'.'.$this->extra_value . ' ' .($negate ? 'NOT ' : ''). |
||
533 | $this->db->capabilities[Db::CAPABILITY_CASE_INSENSITIV_LIKE]. ' ' . |
||
534 | $this->db->quote($wildcard.$val.$wildcard) . ' AND ' . |
||
535 | $this->extra_table.'.'.$this->extra_key . ' = ' . $this->db->quote($name) . |
||
536 | ')'; |
||
537 | unset($criteria[self::CF_PREFIX.$name]); |
||
538 | } |
||
539 | else |
||
540 | { |
||
541 | // criteria operator is AND we remap the criteria to be transformed to filters |
||
542 | $filter[$name] = $val; |
||
543 | unset($criteria[$name]); |
||
544 | } |
||
545 | } |
||
546 | } |
||
547 | if ($cfcriteria && $op =='OR') $criteria[] = implode(' OR ',$cfcriteria); |
||
548 | } |
||
549 | if($only_keys === true) |
||
550 | { |
||
551 | // Expand to keys here, so table_name can be prepended below |
||
552 | $only_keys = array_values($this->db_key_cols); |
||
553 | } |
||
554 | // replace ambiguous column with (an exact match of) table_name.column |
||
555 | if(is_array($only_keys)) |
||
556 | { |
||
557 | foreach($only_keys as $key => &$col) |
||
558 | { |
||
559 | if(is_numeric($key) && in_array($col, $this->db_cols, true)) |
||
560 | { |
||
561 | $col = $this->table_name .'.'.array_search($col, $this->db_cols).' AS '.$col; |
||
562 | } |
||
563 | } |
||
564 | } |
||
565 | // check if we order by a custom field --> join cf table for given cf and order by it's value |
||
566 | if (strpos($order_by,self::CF_PREFIX) !== false) |
||
567 | { |
||
568 | // if $order_by contains more then order by columns (eg. group by) split it off before |
||
569 | if (($pos = stripos($order_by, 'order by')) !== false) |
||
570 | { |
||
571 | $group_by = substr($order_by, 0, $pos+9); |
||
572 | $order_by = substr($order_by, $pos+9); |
||
573 | } |
||
574 | // fields to order by, as cutomfields may have names with spaces, we examine each order by criteria |
||
575 | $fields2order = explode(',',$order_by); |
||
576 | foreach($fields2order as $v) |
||
577 | { |
||
578 | if (strpos($v,self::CF_PREFIX) !== false) |
||
579 | { |
||
580 | // we found a customfield, so we split that part by space char in order to get Sorting Direction and Fieldname |
||
581 | $buff = explode(' ',trim($v)); |
||
582 | $orderDir = array_pop($buff); |
||
583 | $key = substr(trim(implode(' ',$buff)), 1); |
||
584 | if (!isset($this->customfields[$key])) |
||
585 | { |
||
586 | $order_by = preg_replace('/'.preg_quote($v, '/').',?/', '', $order_by); |
||
587 | continue; // ignore unavaiable CF |
||
588 | } |
||
589 | switch($this->customfields[$key]['type']) |
||
590 | { |
||
591 | View Code Duplication | case 'int': |
|
592 | $order_by = str_replace($v, 'extra_order.'.$this->extra_value.' IS NULL,'. |
||
593 | $this->db->to_int('extra_order.'.$this->extra_value).' '.$orderDir, $order_by); |
||
594 | break; |
||
595 | View Code Duplication | case 'float': |
|
596 | $order_by = str_replace($v, 'extra_order.'.$this->extra_value.' IS NULL,'. |
||
597 | $this->db->to_double('extra_order.'.$this->extra_value).' '.$orderDir, $order_by); |
||
598 | break; |
||
599 | default: |
||
600 | $order_by = str_replace($v, 'extra_order.'.$this->extra_value.' IS NULL,extra_order.'. |
||
601 | $this->extra_value.' '.$orderDir, $order_by); |
||
602 | } |
||
603 | // postgres requires that expressions in order by appear in the columns of a distinct select |
||
604 | if ($this->db->Type != 'mysql') |
||
605 | { |
||
606 | if (!is_array($extra_cols)) |
||
607 | { |
||
608 | $extra_cols = $extra_cols ? explode(',', $extra_cols) : array(); |
||
609 | } |
||
610 | $extra_cols[] = 'extra_order.'.$this->extra_value; |
||
611 | $extra_cols[] = 'extra_order.'.$this->extra_value.' IS NULL'; |
||
612 | } |
||
613 | $join .= $this->extra_join_order.' AND extra_order.'.$this->extra_key.'='.$this->db->quote($key); |
||
614 | } |
||
615 | } |
||
616 | // add group by again |
||
617 | if (isset($group_by)) |
||
618 | { |
||
619 | $order_by = $group_by.$order_by; |
||
620 | } |
||
621 | } |
||
622 | // check if we filter by a custom field |
||
623 | if (is_array($filter)) |
||
624 | { |
||
625 | $_cfnames = array_keys($this->customfields); |
||
626 | $extra_filter = null; |
||
627 | foreach($filter as $name => $val) |
||
628 | { |
||
629 | // replace ambiguous auto-id with (an exact match of) table_name.autoid |
||
630 | if (is_string($name) && $name == $this->autoinc_id) |
||
631 | { |
||
632 | View Code Duplication | if ((int)$filter[$this->autoinc_id]) |
|
633 | { |
||
634 | $filter[] = $this->db->expression($this->table_name,$this->table_name.'.',array( |
||
635 | $this->autoinc_id => $filter[$this->autoinc_id], |
||
636 | )); |
||
637 | } |
||
638 | unset($filter[$this->autoinc_id]); |
||
639 | } |
||
640 | // replace ambiguous column with (an exact match of) table_name.column |
||
641 | elseif (is_string($name) && $val!=null && in_array($name, $this->db_cols)) |
||
642 | { |
||
643 | $extra_columns = $this->db->get_table_definitions($this->app, $this->extra_table); |
||
644 | if ($extra_columns['fd'][array_search($name, $this->db_cols)]) |
||
645 | { |
||
646 | $filter[] = $this->db->expression($this->table_name,$this->table_name.'.',array( |
||
647 | array_search($name, $this->db_cols) => $val, |
||
648 | )); |
||
649 | unset($filter[$name]); |
||
650 | } |
||
651 | } |
||
652 | elseif (is_string($name) && $this->is_cf($name)) |
||
653 | { |
||
654 | $cf_name = $this->get_cf_name($name); |
||
655 | if (!isset($this->customfields[$cf_name])) |
||
656 | { |
||
657 | unset($filter[$name]); |
||
658 | continue; // ignore unavailable CF |
||
659 | } |
||
660 | if (!empty($val)) // empty -> dont filter |
||
661 | { |
||
662 | if ($val[0] === '!') // negative filter |
||
663 | { |
||
664 | $sql_filter = 'extra_filter.'.$this->extra_value.'!='.$this->db->quote(substr($val,1)); |
||
665 | } |
||
666 | else // using Db::expression to allow to use array() with possible values or NULL |
||
667 | { |
||
668 | if($this->customfields[$cf_name]['type'] == 'select' && |
||
669 | $this->customfields[$cf_name]['rows'] > 1) |
||
670 | { |
||
671 | // Multi-select - any entry with the filter value selected matches |
||
672 | $sql_filter = str_replace($this->extra_value,'extra_filter.'. |
||
673 | $this->extra_value,$this->db->expression($this->extra_table,array( |
||
674 | $this->db->concat("','",$this->extra_value,"','").' '.$this->db->capabilities[Db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote('%,'.$val.',%') |
||
675 | )) |
||
676 | ); |
||
677 | } |
||
678 | elseif ($this->customfields[$cf_name]['type'] == 'text') |
||
679 | { |
||
680 | $sql_filter = str_replace($this->extra_value,'extra_filter.'.$this->extra_value, |
||
681 | $this->db->expression($this->extra_table,array( |
||
682 | $this->extra_value.' '.$this->db->capabilities[Db::CAPABILITY_CASE_INSENSITIV_LIKE].' '.$this->db->quote($wildcard.$val.$wildcard) |
||
683 | )) |
||
684 | ); |
||
685 | } |
||
686 | else |
||
687 | { |
||
688 | $sql_filter = str_replace($this->extra_value,'extra_filter.'. |
||
689 | $this->extra_value,$this->db->expression($this->extra_table,array($this->extra_value => $val))); |
||
690 | } |
||
691 | } |
||
692 | // need to use a LEFT JOIN for negative search or to allow NULL values |
||
693 | $need_left_join = $val[0] === '!' || strpos($sql_filter,'IS NULL') !== false ? ' LEFT ' : ''; |
||
694 | $join .= str_replace('extra_filter','extra_filter'.$extra_filter,$need_left_join.$this->extra_join_filter. |
||
695 | ' AND extra_filter.'.$this->extra_key.'='.$this->db->quote($cf_name). |
||
696 | ' AND '.$sql_filter); |
||
697 | ++$extra_filter; |
||
698 | } |
||
699 | unset($filter[$name]); |
||
700 | } |
||
701 | elseif(is_int($name) && $this->is_cf($val)) // lettersearch: #cfname LIKE 's%' |
||
702 | { |
||
703 | $_cf = explode(' ',$val); |
||
704 | foreach($_cf as $cf_np) |
||
705 | { |
||
706 | // building cf_name by glueing parts together (, in case someone used whitespace in their custom field names) |
||
707 | $tcf_name = ($tcf_name?$tcf_name.' ':'').$cf_np; |
||
708 | // reacts on the first one found that matches an existing customfield, should be better then the old behavior of |
||
709 | // simply splitting by " " and using the first part |
||
710 | if ($this->is_cf($tcf_name) && ($cfn = $this->get_cf_name($tcf_name)) && array_search($cfn,(array)$_cfnames,true)!==false ) |
||
711 | { |
||
712 | $cf = $tcf_name; |
||
713 | break; |
||
714 | } |
||
715 | } |
||
716 | unset($filter[$name]); |
||
717 | $cf_name = $this->get_cf_name($cf); |
||
718 | if (!isset($this->customfields[$cf_name])) continue; // ignore unavailable CF |
||
719 | $join .= str_replace('extra_filter','extra_filter'.$extra_filter,$this->extra_join_filter. |
||
720 | ' AND extra_filter.'.$this->extra_key.'='.$this->db->quote($cf_name). |
||
721 | ' AND '.str_replace($cf,'extra_filter.'.$this->extra_value,$val)); |
||
722 | ++$extra_filter; |
||
723 | } |
||
724 | } |
||
725 | } |
||
726 | // add DISTINCT as by joining custom fields for search a row can be returned multiple times |
||
727 | if ($join && strpos($join, $this->extra_join) !== false) |
||
728 | { |
||
729 | if (is_array($only_keys)) |
||
730 | { |
||
731 | $only_keys = array_values($only_keys); |
||
732 | $only_keys[0] = 'DISTINCT '.($only_keys[0] != $this->autoinc_id ? $only_keys[0] : |
||
733 | $this->table_name.'.'.$this->autoinc_id.' AS '.$this->autoinc_id); |
||
734 | } |
||
735 | else |
||
736 | { |
||
737 | $only_keys = 'DISTINCT '.$only_keys; |
||
738 | } |
||
739 | } |
||
740 | return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join,$need_full_no_count); |
||
741 | } |
||
742 | |||
788 |