Saturday, 10 June 2017

Developing With VueJS and PHP

In this tutorial, we will make use of VueJS and PHP to build a really cool keyword density tool. On the Vue side, we’ll make use of components, templates, and root elements, and more. We will use PHP to generate the form we need, as well as to handle form processing, in addition to making use of the substr_count() function to provide the data we need. Let’s see how we can do this, it should be fun.

Declare The Vue Component

The first step that we will take is to declare a component for our application. In this instance, we are creating a keywordcounter component as shown by the first argument passed to the .component() method. We pass an object as the second parameter to this method. It has properties of template, props, data, and methods. The template is a string which serves as the actual markup for the Vue component. In this example, it begins with a hashtag, which means that Vue will treat this string as a querySelector for which that innerHTML will be used as the template string. Our props property is an object, which in this case contains to properties, data and columns. The values of these properties are arrays, and we will fill them dynamically a little later on. The data property holds a function, or rather references a function. There is a bit of magic happening here, as Vue actually turns any properties into getters and setters which is what gives the framework it’s reactive nature. Finally, we have the methods property, which is an object that contains methods to be used in the Vue instance. It is a means of keeping all of your functionality neat and tidy. Methods in the methods property have their this context set to the Vue instance.
<script>
Vue.component('keywordcounter', {
template: '#keywordcounter-template',
props: {
data: Array,
columns: Array
},
data: function () {
var sortOrders = {};
this.columns.forEach(function (key) {
sortOrders[key] = 1
});
return {
sortKey: '',
sortOrders: sortOrders
}
},
methods: {
sortBy: function (key) {
this.sortKey = key;
this.sortOrders[key] = this.sortOrders[key] * -1;
}
}
});
</script>

Present a form to enter a haystack and keyword(s) to search

In this step we will use a simple combination of HTML and PHP to present a form for which we can collect some data. First off, we have a form element with the action set to substr_count.php and the method is post. What this means is that we will use the post http method to submit any data we collect to the PHP file named substr_count.php. In our case, this is literally a single page application, so all snippets on this page can be assembled in order to create your own working example. Inside of the form tag, we have a textarea which will accept the data to be known as haystack, and a text input which will collect a comma separated list of keywords that we will analyze in the haystack data. Our inputs make use of the isset PHP function in order to repopulate the inputs on each successive testing of data. This way, you wouldn’t have to re enter all of the information into the form in order to search on say a different set of keywords. Finally we have just a simple button which allows us to submit the form.
<form action="substr_count.php" method="post">
    <label for="haystack">Enter text to analyze here.</label>
    <textarea name="haystack" id="haystack" class="form-control" rows="7"><?php if (isset($_POST['haystack'])) {
            echo $_POST['haystack'];
        } ?></textarea>
    <label for="keyword">Enter comma separated keywords to search for here.</label>
    <input name="keyword" id="keyword" type="text" class="form-control" value="<?php if (isset($_POST['keyword'])) {
        echo $_POST['keyword'];
    } ?>">
    <button type="submit">Submit</button>
</form>

Define the keywordcounter-template template

In the section above where we talked about the string template, and how it is used as a querySelector when prefixed with a hashtag. Below, we now find ourselves making use of <script type="x-template"> to define our template. This is how the component finds it’s template. This section here contains the markup and logic that will define the data we present to the user. In our case we have a simple table with some bootstrap styling. You’ll notice that the th and tr tags hold some special markup. This is the markup of VueJS which is able to turn our plain HTML into markup capable of logic processing. In the th tag, we use v-for to loop over any available data, give it a nice style of a hand pointer, attach a click handler which fires the sortBy() method, apply an active class if the current table is active, capitalize the first letter, and determine if the sort is ascending or descending. In short, this markup allows us to click on the table header to sort by that column. When we run our little application, we will be able to sort by the Term, or by the Count of each term.
You’ll notice that the tr tag also makes use of Vue’s custom markup. What it is doing there is dynamically populating each row of the table with two td elements. One for the search Term, and one for the Number of times, or Count of how often that search term appeared in the haystack. Behind the scenes, we are actually making use of substr_count() to find this data for use, then we use Vue to display the results in a beautiful interactive table with sorting capabilities.


<script type="text/x-template" id="keywordcounter-template">
    <table class="table table-hover">
        <thead>
        <tr>
            <th v-for="key in columns"
                style="cursor:pointer;"
                @click="sortBy(key)"
                :class="{active: sortKey == key}">
                {{key | capitalize}}
          <span class="arrow"
                :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
          </span>
            </th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="
        entry in data
        | orderBy sortKey sortOrders[sortKey]">
            <td v-for="key in columns">
                {{entry[key]}}
            </td>
        </tr>
        </tbody>
    </table>
</script>

Define the root element

This markup corresponds to the name we gave to the component we registered in the first step. Now we can reference it with these custom HTML tags like so.
<div id="findkeywords">
    <keywordcounter
        :data="keywordcounterData"
        :columns="keywordcounterColumns">
    </keywordcounter>
</div>

Fill the data that populates the component

In this step, we actually have to use PHP to generate portions of the script in our pages, since this is the data that will be dynamic based on the information that we fill out in the form and submit to the application. We actually have two cases here, if the data submitted results in several terms and counts, the first branch is taken. If only one term and count is found, we take the second branch.
<?php
if (isset($_POST['haystack']) and isset($_POST['keyword'])) {
    $haystack = $_POST['haystack'];
    $keyword = $_POST['keyword'];
    if (strstr($keyword, ',')) {
        $i = 1;
        $keywords = explode(',', $keyword);
        ?>
        <script>
            // fill the data that populates the component
            var action = new Vue({
                el: '#findkeywords',
                data: {
                    searchQuery: '',
                    keywordcounterColumns: ['term', 'count'],
                    keywordcounterData: [
                        <?php
                        foreach ($keywords as $keyword) {
                            echo ' { term: "' . $keyword . '", count: ' . substr_count($haystack, $keyword) . ' },';
                        }
                        ?>
                    ]
                }
            });
        </script>
    <?php
    } else {
    ?>
        <table class="table table-hover">
            <thead>
            <tr>
                <th style="cursor:hand;"> Term <span class="arrow asc"> </span></th>
                <th style="cursor:hand;" class="active"> Count <span class="arrow asc"> </span></th>
            </tr>
            </thead>
            <tbody>
            <tr>
                <td><?php echo $keyword ?></td>
                <td><?php echo substr_count($haystack, $keyword); ?></td>
            </tr>
            </tbody>
        </table>
        <?php
    }
}
?>

Testing out our application

Finally, we are ready to take our little application for a spin. Enter a bunch of text into the text area, and a collection of terms that are comma separated into the text input field, then click submit.

Sort By Term

After submitting the data to our application, we can click on the Term table header to sort our results via Term name.
sort by term


Sort By Count

After submitting the data to our application, we can click on the Count table header to sort our results via count.
sort by count

Developing With VueJS and PHP Summary

This was a fun little experiment with hacking together a random application in VueJS and PHP working in concert. Please share if you liked it!