Posted on Leave a comment

Undestanding PHP Namespaces

I have hard time understanding PHP namespace. So, this post is things I learn from working with it.

Namespace keyword starts the file.

When you include the class that has namespace defined, you also need to type the keyword use and the namespace you want to use follows. Without using namespace, this would work. However, with namespace, the keyword use is required.

The main purpose of namspaces in PHP is to avoid name conflict.

Namespace is used in class. You cannot declare a namespace and in that file don’t declare a class.

In one file, you can have class definition and code (functions, variables) outside of that class. This is strange for me since I learn OOP first from Java. You cannot access such functions/properties from other files though (even if you include it). However, these functions, variables are accessible in the classes of the same file. Maybe it’s a way of code sharing without declaring a class with static functions/properties.

Posted on Leave a comment

Builder Pattern In Java

Keys to remember

  • Outer class has a public static Builder class
  • Outer class has a private constructor that takes an instance of the builder
  • The Builder has method to set value to the properties
  • The Builder class has a build() method that call the outer class’ constructor (that takes one Builder instance)
  • Inside the outer’s private constructor, the outer’s properties are set to that of the Builder instance

Sample code

public class Breakfast {

    private String food, drink;

    public static class Builder
    {
        private String food, drink;

        public Builder food(String food)
        {
            this.food = food;
            return this;
        }

        public Builder drink(String drink)
        {
            this.drink = drink;
            return this;
        }

        public Breakfast build()
        {
            return new Breakfast(this);
        }
    }

    private Breakfast(Builder builder)
    {
        this.food = builder.food;
        this.drink = builder.drink;
    }

    public void stateOrder()
    {
        System.out.println(new StringBuilder("I need ").append(this.food).append(" and ").append(this.drink).toString());
    }



    public String getFood() {
        return food;
    }

    public String getDrink() {
        return drink;
    }


    public static void main(String[] args) {
        Breakfast b = new Builder().drink("Coffee").food("Beef").build();

        b.stateOrder();
    }
}

Questions

  • Is the Builder pattern only good for setting properties?
Posted on Leave a comment

[Ultimate] Guide to PHP Autoload

Calling spl_autoload_register without argument

  • spl_autoload_register() without arguments will invoke (call) another function called spl_autoload when php script tries to access an unknown class. The name of the unknown class will be passed to spl_autoload. spl_autoload first then find if there is a file name identical to the class name (lower and upper case, php 7) with the extension .php or .inc in: First, the include path then the local directory. The search will stop once the file is found (not when the class is found). Sounds confusing? Let me demonstrate:

Let’s make it clearer:

So, I have the root folder with two files: index.php and cat.php (lowercase C). One folder called animal that contains Cat.php (uppercase)

Here are the code in each file:

cat.php

<?php

class Cat
{
    function __construct($name)
    {
        echo "I am a cat in the local directory";
    }
}

Cat.php (inside animal folder)

<?php

class Cat
{
    function __construct($name)
    {
        echo "I am the cat in the ANIMAL directory";
    }
}

index.php (root folder)

<?php

set_include_path(get_include_path() . PATH_SEPARATOR . "animal");
spl_autoload_register();

$x = new Cat("jane");

When I access the index.php file in the browser, here is what I get:

As you can see, the Cat inside animal is used. It is because of this line in the index.php file

set_include_path(get_include_path() . PATH_SEPARATOR . "animal");

I set the animal to the include path. PHP will search for file names with extensions .php or .inc in those paths first. If the file name is found (in this case is Cat.php/Cat.inc/cat.php/cat.inc), then the search will stop. Remember that the search doesn’t care if the class exists. It only cares if the file exists. If I comment out the implementation of the Cat class in animal/Cat.php and access the index.php again, I’ll get an error:

Fatal error: Uncaught Error: Class ‘Cat’ not found in C:\xampp\htdocs\lab\oop\index.php:6 Stack trace: #0 {main} thrown in C:\xampp\htdocs\lab\oop\index.php on line 6

Now, if I comment out the set_include_path line in index.php, I’ll get the Cat class in the root directory:

// set_include_path(get_include_path() . PATH_SEPARATOR . "animal");
spl_autoload_register();

$x = new Cat("jane");
Posted on Leave a comment

Understanding Traits In PHP

Trait is something a class has. A trait doesn’t define a type of a class. For example, Teacher is a type. Talk a lot is a trait. A teacher can either talk a lot or not.

trait TalkALot
{
    public function talk()
    {
        echo "I talk a lot";
    }
}

class Teacher
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }
    use TalkALot;
}


$teacher = new Teacher("Oma");

$teacher->talk();

The code above will output “I talk a lot”

One class can implement multiple traits. However, those traits must not have same function name.

trait TalkALot
{
    public function talk()
    {
        echo "I talk a lot";
            }
}


trait TalkALittle
{
    public funtion talk(){
        echo "I don't talk";
    }

}

class Teacher
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }
    use TalkALot, TalkALittle;
}


$teacher = new Teacher("Oma");

$teacher->talk();

The code above will cause an error:

Fatal error: Trait method talk has not been applied, because there are collisions with other trait methods on Teacher in C:\xampp\htdocs\lab\oop\index.php on line 21

You can use the keyword insteadof as a workaround in case your traits have same method name:

trait TalkALot
{

    public function talk()
    {
        echo $this->name . " talk all days";
    }
}

trait TalkALittle
{

    public function talk()
    {
        echo $this->name . " talk a little";
    }
}



class Teacher
{
    private $name;

    use TalkALot, TalkALittle {
    TalkALittle::talk insteadof TalkALot;
    }
    public function __construct($name)
    {
        $this->name = $name;
    }
}


$teacher = new Teacher("Oma");

$teacher->talk();

What if you want to use the other method that get overridden?

 trait TalkALot
{

    public function talk()
    {
        echo $this->name . " talk all days";
    }
}

trait TalkALittle
{

    public function talk()
    {
        echo $this->name . " talk a little";
    }
}



class Teacher
{
    private $name;

    use TalkALot, TalkALittle {
    TalkALot::talk insteadof TalkALittle;
    TalkALittle::talk as modestTalk;
    }
    public function __construct($name)
    {
        $this->name = $name;
    }
}


$teacher = new Teacher("Oma");

$teacher->modestTalk();

Here, I’ve defined an alias for the talk method of TalkALittle trait. Then, I can call the talk method in TalkALittle trait as modestTalk.

Trait can have private function, just like class.

Since trait is something a class has, it has access to all class’s variable and methods

trait TalkALot
{
    public function talk()
    {
        $this->requestSayName();
    }
}



class Teacher
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function requestSayName()
    {
        echo "Say my name!";
    }
    use TalkALot;
}


$teacher = new Teacher("Oma");

$teacher->talk();

As you can see, the function talk is in the trait TalkALot. The $teacher instance call it. The talk function call the function requestSayname, which is defined in the Teacher class.

You cannot define a property in a trait then define a property with the same name in the class

The following code generates an error:

trait TalkALot
{
    private $name = "Trait";
    public function talk()
    {
        $this->requestSayName();
    }

    public function sayName()
    {
        echo $this->name;
    }
}



class Teacher
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function requestSayName()
    {
        echo "Say my name!";
    }
    use TalkALot;
}


$teacher = new Teacher("Oma");

$teacher->sayName();
Fatal error: Teacher and TalkALot define the same property ($name) in the composition of Teacher. However, the definition differs and is considered incompatible. Class was composed in C:\xampp\htdocs\lab\oop\index.php on line 20

Trait can have static method. Static method in trait can access via the classes that use it either by class name or an instance:

trait TalkALot
{

    public function talk()
    {
        echo $this->name . " talk all days";
    }

    public static function tryTalking()
    {
        echo "bla bla <br />";
    }
}

trait TalkALittle
{

    public function talk()
    {
        echo $this->name . " talk a little";
    }
}



class Teacher
{
    private $name;

    use TalkALot, TalkALittle {
    TalkALot::talk insteadof TalkALittle;
    TalkALittle::talk as modestTalk;
    }
    public function __construct($name)
    {
        $this->name = $name;
    }
}


$teacher = new Teacher("Oma");


Teacher::tryTalking();
$teacher::tryTalking();

The above code prints two lines say “bla bla”

Posted on Leave a comment

How Does add_filter Work In WordPress

Filters are the source of confusion when I first started my WP development. I only gained a better understanding of this topic until recently. Thus, I want to share with you my finding.

As you may already know (I hope), WordPress users can modify parts of WordPress website with filter. You use the add_filter function to add your own function to modify a particular item. For example, you want to add a few words before the title of every page/post of your blog, you can do like this:

add_action('the_title', 'modify_the_title');

‘modify_the_title’ is the function you need to define to do the modifications.

Think of functions like ‘modify_the_title’ as a blackbox

The $wp_filter variable

To understand how add_filter works, you need to know a global variable called $wp_filter. It’s an array. Let’s see how is it structured.

Since it’s a global variable, we can access it anywhere. Let’s verify it’s actually an array by entering this code in our current active theme’s functions.php

echo '<h1>$wp_fitler type</h1>';
echo gettype($wp_filter);

echo '<h1>Number of elements in $wp_fitler</h1>';
echo count($wp_filter);

echo '<h1>List of hooks in $wp_filter</h1>';

foreach ($wp_filter as $key => $value)
{
    echo "<p>$key</p>";
}
die();

Open the website, we’ll see this:

As you can see, it’s an array with 658 elements. With the foreach loop, you can also see that it’s an associative array with the key is the name of the hooks.

So, I want to see the details of ‘the_title’ hook. Let’s replace the above code with this one:

echo '<h1>the_title hook details</h1>';
echo '<h3>type</h3>';
echo gettype($wp_filter['the_title']);
echo '<h3>details</h3>';
dump($wp_filter['the_title']);


die();

I also installed var_dumper, a very nice library to pretty print the var_dump to the screen. Here is what we have:

As you can see, $wp_filter is an associative array where the keys are the name of the hook and the values are WP_Hook objects. The most important part here is the callbacks field. It’s an array contains the details of functions that registered to the hook.

In case you are curious, callbacks is an associative array (not indexed). What the number 10, 11 means is the order of execution.

How custom functions are added to $wp_filter

If you read the documentation of add_filter or add_action, the third argument is the priority or execution. The larger the number, the later it will be executed.

So, if I add the following function to the_title hook (notice that I set the priority to 1):

add_filter('the_title', 'my_custom_function', 1, 0);

function my_custom_function($title)
{
    return $title;
}

And we check the dump of the_title hook object again:

You can see that callbacks now has another element with key is ‘1’ that store the newly added function.

Adding functions to your own filters

I usually wonder, how filters hooked get registered at the first place. Do we have a function called ‘register_filter’?

No, there isn’t a function like that. When you call the add_filter function, if the filter name doesn’t exists in $wp_filter, it will be added to the $wp_filter array. Let me demonstrate.

add_filter('filter_hook_that_does_not_exist', 'my_custom_function', 1, 0);

function my_custom_function($input)
{
    /** code to modify the input here */
    return $input;
}

echo '<h1>hook details</h1>';
echo '<h3>type</h3>';
echo gettype($wp_filter['filter_hook_that_does_not_exist']);
echo '<h3>details</h3>';
dump($wp_filter['filter_hook_that_does_not_exist']);
die();

As you can see, we add a filter to a non-existence hook. Let’s see the result:

So, how the function ‘my_custom_function’ get executed? Well, that’ the topic of the post about apply_filters.

Conclusion

Hopefully now you are like me, understand how are custom functions get added to the $wp_filter every time we call add_filter function. If you have questions, please let me know

Posted on Leave a comment

How Are WordPress Post/Page’s Title Got Rendered

This post is another effort of mine in understanding the core of WordPress. Hopefully at the end of this post, you’ll gain something about. My goal is to have better understanding of the way WP render particular parts of the website by using the filters.

Dive into the header.php file of WP theme

I’m using store front theme on my local dev site. However, you’ll encounter the same layout/code in any other themes.

This is the part of the code that renders the header

<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2.0">
<link rel="profile" href="http://gmpg.org/xfn/11">
<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>">

<?php wp_head(); ?>
</head>

As you can see, there is no title tag. However, there is a piece of PHP code that generates the title and other stuffs. That’s wp_head()

Dive into wp_head function

The code for wp_head is surprisingly simple:

function wp_head() {
	/**
	 * Prints scripts or data in the head tag on the front end.
	 *
	 * @since 1.5.0
	 */
	do_action( 'wp_head' );
}

It calls another function called do_action with the parameter ‘wp_head’. I hope you have, at least a vague understanding of how filters and actions work in WordPress.

Now, we need to know where the title’s filters are added to the wp_head hook. With the help of PhpStorm, I was able to locate this part:

add_action( 'wp_head', '_wp_render_title_tag', 1 );

As you can see, there is a function that responsible for rendering the title called ‘_wp_render_title_tag’. Let’s see what does it do:

function _wp_render_title_tag() {
	if ( ! current_theme_supports( 'title-tag' ) ) {
		return;
	}

	echo '<title>' . wp_get_document_title() . '</title>' . "\n";
}

Once again, the function is very short since it calls other functions. Our next step would be investigating the function ‘wp_get_document_title’

function wp_get_document_title() {

	/**
	 * Filters the document title before it is generated.
	 *
	 * Passing a non-empty value will short-circuit wp_get_document_title(),
	 * returning that value instead.
	 *
	 * @since 4.4.0
	 *
	 * @param string $title The document title. Default empty string.
	 */
	$title = apply_filters( 'pre_get_document_title', '' );
	if ( ! empty( $title ) ) {
		return $title;
	}

	global $page, $paged;

	$title = array(
		'title' => '',
	);

	// If it's a 404 page, use a "Page not found" title.
	if ( is_404() ) {
		$title['title'] = __( 'Page not found' );

		// If it's a search, use a dynamic search results title.
	} elseif ( is_search() ) {
		/* translators: %s: search phrase */
		$title['title'] = sprintf( __( 'Search Results for “%s”' ), get_search_query() );

		// If on the front page, use the site title.
	} elseif ( is_front_page() ) {
		$title['title'] = get_bloginfo( 'name', 'display' );

		// If on a post type archive, use the post type archive title.
	} elseif ( is_post_type_archive() ) {
		$title['title'] = post_type_archive_title( '', false );

		// If on a taxonomy archive, use the term title.
	} elseif ( is_tax() ) {
		$title['title'] = single_term_title( '', false );

		/*
		* If we're on the blog page that is not the homepage or
		* a single post of any post type, use the post title.
		*/
	} elseif ( is_home() || is_singular() ) {
		$title['title'] = single_post_title( '', false );

		// If on a category or tag archive, use the term title.
	} elseif ( is_category() || is_tag() ) {
		$title['title'] = single_term_title( '', false );

		// If on an author archive, use the author's display name.
	} elseif ( is_author() && $author = get_queried_object() ) {
		$title['title'] = $author->display_name;

		// If it's a date archive, use the date as the title.
	} elseif ( is_year() ) {
		$title['title'] = get_the_date( _x( 'Y', 'yearly archives date format' ) );

	} elseif ( is_month() ) {
		$title['title'] = get_the_date( _x( 'F Y', 'monthly archives date format' ) );

	} elseif ( is_day() ) {
		$title['title'] = get_the_date();
	}

	// Add a page number if necessary.
	if ( ( $paged >= 2 || $page >= 2 ) && ! is_404() ) {
		$title['page'] = sprintf( __( 'Page %s' ), max( $paged, $page ) );
	}

	// Append the description or site title to give context.
	if ( is_front_page() ) {
		$title['tagline'] = get_bloginfo( 'description', 'display' );
	} else {
		$title['site'] = get_bloginfo( 'name', 'display' );
	}

	/**
	 * Filters the separator for the document title.
	 *
	 * @since 4.4.0
	 *
	 * @param string $sep Document title separator. Default '-'.
	 */
	$sep = apply_filters( 'document_title_separator', '-' );

	/**
	 * Filters the parts of the document title.
	 *
	 * @since 4.4.0
	 *
	 * @param array $title {
	 *     The document title parts.
	 *
	 *     @type string $title   Title of the viewed page.
	 *     @type string $page    Optional. Page number if paginated.
	 *     @type string $tagline Optional. Site description when on home page.
	 *     @type string $site    Optional. Site title when not on home page.
	 * }
	 */
	$title = apply_filters( 'document_title_parts', $title );

	$title = implode( " $sep ", array_filter( $title ) );
	$title = wptexturize( $title );
	$title = convert_chars( $title );
	$title = esc_html( $title );
	$title = capital_P_dangit( $title );

	return $title;
}

This function is quite lengthy since it does all of jobs of generating the title. You can also see that, while the title tag is a small part of the document, this function isn’t a simple one at all. It’s partly because WordPress offers so much flexibility for developers to modify the titles and other parts of the content.

As you read through the code, you’ll see that this function checks for what kind of page it’s currently on (whether it’s a homepage/archive page…) and render the title for such pages accordingly.

You may have some confusions regarding the apply_filters part. That’s the topic of another post which I’m going to write shortly.

Posted on Leave a comment

Adding new tab to WooCommerce Product Data Panel

Adding new tab to WooCommerce Product Data panel is simple. First, you need to add the tab item. The name of the hook is:

woocommerce_product_write_panel_tabs

So, the add_action would be:

add_action( 'woocommerce_product_write_panel_tabs', 'wc_custom_tab_head' );

And the function wc_custom_tab_head is responsible for outputting the tab’s head HTML

Here is an implementation of wc_custom_tab_head

function wc_custom_tab_head()
{
    echo '<li class="product_tabs_tab"><a href="#woocommerce-custom-tab">Custom tab</a></li>';
}

Adding content to the tab

We have successfully add the tab, however, the tab is still blank. How to add content to that tab?

To add content to the Product Data panel, you’ll need to use the following hook:

woocommerce_product_data_panels

The add_action would be:

add_action( 'woocommerce_product_data_panels', 'wc_custom_tab_content' );

The implementation of wc_custom_tab_content could be:

function wc_tab_manager_product_tabs_panel_content() {

    ?>
    <div id="woo-custom-tab" class="panel wc-metaboxes-wrapper">
        <div class="woocommerce_product_tabs wc-metaboxes">
            <!-- Tab content -->
            <h1>hello</h1>
            <!-- End tab content -->
        </div>
    </div>
<?php 
}
Posted on Leave a comment

The Ultimate Guide/Troubleshooting To Install OsTicket On Nginx

OsTicket is an awesome ticketing system. It’s better than Hesk in my opinion. However, the sad thing about this ticketing software is it doesn’t support nginx server officially. However, if you are running Nginx, you can make it work.

Nginx configuration for OsTicket

server_name server_name;
root /path-to-your-root/;
include         mime.types;
default_type    application/octet-stream;
sendfile        on;
charset         utf- ;
gzip            on;
gzip_types      text/plain application/xml text/javascript;
gzip_min_length  ;

index index.php index.html index.htm;

set $path_info "";

# Deny access to all files in the include directory
location ~ ^/include {
deny all;
return  ;
}

# Deny access to apache .ht* files (nginx doesn't use these)
location ~ /\.ht {
deny all;
}


# Requests to /api/* need their PATH_INFO set, this does that
if ($request_uri ~ "^/api(/[^\?]+)") {
set $path_info $ ;
}

# /api/*.* should be handled by /api/http.php if the requested file does not exist
location ~ ^/api/(tickets|tasks)(.*)$ {
try_files $uri $uri/ /api/http.php;
}

# /scp/ajax.php needs PATH_INFO too, possibly more files need it hence the .*\.php
if ($request_uri ~ "^/scp/.*\.php(/[^\?]+)") {
set $path_info $ ;
}


# Make sure requests to /scp/ajax.php/some/path get handled by ajax.php
location ~ ^/scp/ajax.php/(.*)$ {
try_files $uri $uri/ /scp/ajax.php;
}

# Set index.php as our directoryindex
location / {
index index.php;
}

# Send php files off to the PHP-FPM listing on localhost: 
location ~ \.php$ {
try_files $uri = ;
fastcgi_pass    php;
fastcgi_index   index.php;
fastcgi_param   SCRIPT_FILENAME         $document_root$fastcgi_script_name;
fastcgi_param   PATH_INFO               $path_info;
include fastcgi_params;
}

# Make sure requests to /ajax.php/some/path get handled by ajax.php
location ~ ^/ajax.php/(.*)$ {
try_files $uri $uri/ /ajax.php;
}

How to fix file upload undefined 400 in OSTicket

Kudos to this original post: https://github.com/osTicket/osTicket-1.7/issues/538#issuecomment-16049117

If you/your users have problem uploading files when opening a ticket like this:

Then, open the file include/class.osticket.php and find the function get_path_info. Replace its definition with the block above.

    function get_path_info() {
        if(isset($_SERVER['PATH_INFO']) && !empty($_SERVER['PATH_INFO']))
            return $_SERVER['PATH_INFO'];

        if(isset($_SERVER['ORIG_PATH_INFO']) && !empty($_SERVER['ORIG_PATH_INFO']))
            return $_SERVER['ORIG_PATH_INFO'];

        $request_uri = preg_replace('@\?.*$@', '', $_SERVER['REQUEST_URI']);

        if (strpos($request_uri, $_SERVER['SCRIPT_NAME']) !== false) {
            $guessed_pathinfo = preg_replace('#^'.preg_quote($_SERVER['SCRIPT_NAME']).'#', '', $request_uri);
        } else {
            $guessed_pathinfo = preg_replace('#^'.preg_quote(preg_replace('@/([^/]+)$@', '', $_SERVER['SCRIPT_NAME'])).'#', '', $request_uri);
        }
        if (!empty($guessed_pathinfo))
            return $guessed_pathinfo;

        return null;
    }

Save the file and you can now upload the attachment when opening a ticket.

Posted on Leave a comment

React Notes

List and keys

  • Don’t use index as key
  • Key must be unique
  • Passing key to the child of the list, not in the render function


Form

  • Textarea uses value attribute
  • Select doesn’t use selected attribute but specify the selected value in the value attribute of select opening tag
  • If passing value in as an array to a select element and multiple is set to true, select enables multiple value selected
  • What is a controlled component (vs uncontrolled component)