דיזיין פאטרן facade: פישוט הממשק של כל פונקציה/קלאס לכדי פקודה פשוטה בשם apply filters שבה מציינים את שם הממשק ומעבירים את הפרמטרים הדרושים, אם לא מגדירים אחרת אז פשוט פרמטר אחד, שאחרי שמפעילים את ה- facade הוא עובר עיבוד ומוחזר כערך לאחר שהופעלה עליו הפונקציה.

דיזיין פאטרן decorator: והיה אם אתה רוצים לשפר את ההתנהגות של הפילטר המדובר או לשנות אותה בזמן ריצה, אם אתם רוצים לעשות עיבוד לפני ביצוע הפונקציה המקורית של הפילטר, אתם מוסיפים פונקציה בפריוריטי נמוך מ-10, אם אתם רוצים לעשות עיבוד לאחר ביצוע הפונקציה המקורית, אתם מוסיפים פונקציה בפריוריטי גבוה מ-10. וכך הרווחתם שני דברים: א. אתם לא צריכים לכתוב יותר מהשינוי שאתם רוצים, ב. לא מעניין אתכם מה התבצע בתוך הקופסה השחורה שאתם רוצים לשפצר, רק מה יתבצע אחרי או לפני.

איך עושים את זה?

ראשית, נגדיר קלאס שבאמצעותו ניתן להעביר שמות של קלאסים ופונקציות סטטיות. כך אוכל באמצעות פונקציה סטטית לבנות builder לאובייקט מהקאלס, לבצע עליו פעולה, להחזיר את התוצאה או לבצע על האובייקט פעולה, ולאחר סיום הפעולה האובייקט ימות. כלומר, הקלאס יהפוך כל פונקציה סטטית לפילטר בן אותו שם, שמסוגל להעביר אליו כמה משתנים שארצה בהתאם למס' הפרמטרים שהפונקציה מקבלת.

class filters
{
    protected $buffer;
    protected $params;

    public function __construct( $array,$params=0 )
    {
        if(!is_array($array)){
            throw new \Exception('$array must be an array');
        }

        if($params && !is_numeric($params)){
            throw new \Exception('$params must be an numeric');
        }

        $this->buffer = $array;
        $this->params=$params;
    }

    public function generate_filter( $name )
    {
        foreach ( $this->buffer as $function=>$priority ) {
            if(is_numeric($function)){
                $function=$priority;
                $priority=10;
            }
            
            if(strpos($function,'::')!==false){
            	$function=explode('::',$function);
            	if(isset($function[0]) && isset($function[1])) {
		            $condition = method_exists( $function[ 0 ], $function[ 1 ] );
	            } else {
            		$condition=false;
	            }
            } else {
            	$condition=function_exists($function);
            }

            global $wp_filter;
            $isset=isset($wp_filter[$name]);
            if($condition && !$isset) {
                if ( $this->params ) {
                    add_filter( $name, $function, $priority, $this->params );
                } else {
                    add_filter( $name, $function, $priority );
                }
            }
        }
    }
}

כל אובייקט שייפתח מהקלאס צריך שתופעל עליו הפונקציה generate_filter, שמקבלת שם של פילטר. באמצעות פונקציה חיצונית נוכל ליצור את הפילטר אוטומטית לפי השם של הפונקציה אך עקרונית אנו יכולים לתת איזה שם שנרצה בשימוש ישיר בקלאס. הפונקציה מחלצת את הנתיב המלא של הקלאס ואת שם הפונקציה הסטטית, כמו כן את מס' הפרמטרים הדרושים. אם זה 1, לא צריך אפילו להעביר מס' פרמטרים ולכן מעבירים רק מפתח ללא ערך. הוא שולח את הפוינטר לפונקציה כ- callback ביחד עם הפרמטרים לפי ה-API המקורי של הפילטרים בוורדפרס. יש לציין ש- actions הם filters לכל דבר, בהבדל הפשוט ש- action לא מחזיר שום דבר, ו- filter כן, כך שאפשר לשרשר פעולות כי אינן מחזירות שום ערך ופילטרים שכן מחזירים.

הפונקציה החיצונית מבחינתנו יכולה להיות פילטר בפני עצמו. אנו נכניס לפילטר מערך שנגדיר כ- $pairs, ובכל פעם שנפעיל את הפילטר תופעל עליו הפונקציה שתשלח לבד את הפרמטרים לקלאס הפילטרים שהגדרנו. מהבחינה הזו מדובר ב- factory של פילטרים, והגדרתו להלן:

add_filter( 'filter_generator_pairs', 'generate_filters');

function generate_filters( $pairs ) {
	if ( is_array( $pairs ) ) {
		foreach ( $pairs as $class => $methods ) {
			if ( is_array( $methods ) ) {
				$priorities = array_map( function ( $key, $value ) {
					return is_numeric( $key ) ? 0 : $value;
				}, array_keys( $methods ), array_values( $methods ) );
					$methods = array_map( function ( $key, $value ) {
					return is_numeric( $key ) ? $value : $key;
				}, array_keys( $methods ), array_values( $methods ) );
					$priorities = array_combine( array_values( $methods ), $priorities );
					$array = array_combine( array_map( function ( $method ) use ( $class ) {
					return $class ? "$class::$method" : '';
				}, array_values( $methods ) ), array_values( $methods ) );
					if ( ! is_array( $array ) ) {
					return;
				}

				foreach ( $array as $path => $name ) {
					$params = isset( $priorities[$name])?$priorities[$name]:0;
					( new filters( array(
						$path
					), $params ) )->generate_filter( $name );
				}
			}
		}
	}
}

כעת, נבחן קלאס שבנינו עם שלושה סוגי פונקציות סטטיות:

class test_class {
	
	protected $value;
	
	public function __construct($value){
		$this->value=$value;
	}
	
	public function action_on_value(){
		return "{$this->value}+++++";
	}
	
	static public function test_method1( $input ) {
		return "{$input} string";
	}

	static public function test_method2( $a=1, $b=1 ) {
		return $a + $b;
	}
	
	static public function test_method3( $input ) {
		$instance=new static($input);
		return $input->action_on_value();
	}
}

כעת נעביר את ההודעה: "הפוך את הפונקציות הסטטיות לפילטרים". המערך כולל מפתח בשם הקלאס, בגלל שזה בגלובאל סקופ אני אפילו לא מעביר את הניימספייס. בתור הערים אני שולח מערך שבו שלושה אלמנטים, שניים מהם, פונקציה מס' 1 ופונקציה מס' 3 מקבלת רק פרמטר אחד אז אני אפילו לא מצרף ערך, והשלישית, פונקציה מס' 2, מקבלת שני פרמטרים ולכן אני מעביר אותה כמפתח עם ערך 2.

$pairs = array(
	'test_class' => array(
		'test_method1',
		'test_method2' => 2,
		'test_method3',
	)
);


apply_filters( 'filter_generator_pairs',$pairs );

לסיום, נפעיל את הפילטרים:

apply_filters( 'filter_generator_pairs',$pairs );

// with all parameters
echo apply_filters('test_method2',1,2);

// with only one parameter
echo apply_filters('test_method2',1);

// "original"
echo apply_filters('test_method1','eee');

// decorator
function alter_test_method1($input){
	return str_replace('string','hh',$input);
}

add_filter('test_method1','alter_test_method1',11);

// using decorator
echo apply_filters('test_method1','eee');

echo apply_filters('test_method3','klklkl');

הפלט שנקבל:
עבור פונקציה מס' 2 הכנסנו שני ערכים, וקיבלנו את סכומם, 3. לאחר מכן הכנסנו רק ערך אחד, והשני הוא החשיב כאחד, לכן קיבלנו 2.
עבור פונקציה מס' 1, בהתחלה הכנסתי סתם מחרוזת, קיבלתי את אותה המחרוזת עם המילה string אחריה. לאחר שהפעלתי את ה- decorator, במקום string קיבלתי מחרוזת אחרת hh.
עבור פונקציה מס' 3, הפעלתי את הפונקציה הפרטית והמוגנת על אובייקט חדש. אקבל את הערך שהכנסתי עם +++++ אחריו.

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *