Select2 library solution in Yii2 part 1 – introduction

For those of you who do not know the Select2 library is a Javascript / JQuery replacement for select boxes. Although there are a few options to choose from in terms of using the Select2 field the configuration I will be looking at will be the multi select configuration.

The multi select configuration is useful for allowing the user to select things that require multiple choices, a typical example of this could be Tags but at a deeper level the multi select configuration is useful for allowing the user to create many to many relationships between models on forms.

An example Select2 field is shown below, allowing the selection of countries on a form …

Select2 Library

The above Select2 field could be on a add / edit person form allowing the many to many relation between People and Countries.

The solution I am providing in this article is all about saving and retrieving the Select2 data in a way that will streamline the process so a Select2 field can be attached to any of your forms within your web software application and it will just work out of the box.

The front-end part of the Select2 field is solved already as you can use the following Yii2 plugin for that …

http://demos.krajee.com/widget-details/select2

The above plugin displays the Select2 field on your Yii2 web forms. The above plugin passes the Select2 field data in the POST as an array. It is what to do with that data in a consistent and streamlined way that this article I am writing covers.

There are many ways the data could be handled for example the data could be JSON encoded and stored in a column in the database table then JSON decoded and displayed on the form when retrieving. Another way would be to have relationship tables for each relationship between models and store the data that way.

The way I have chosen is more like the later except that I do not have relationship tables for each relationship, I simply have 1 central Select2 relationship table that handles all Select2 relationships across the whole web software application.

What is the purpose of all this?

Most programmers would just use the Krajee Select2 plugin (link above) and leave it at that in terms of abstraction. The programmer would manually write the save / retrieve code specific to each instance of the Select2 plugin most likely in the Controller. The way I am using the Select2 plugin is to have methods that handle all of this.

If I want to use the Select2 plugin field in any of my forms, with just a few method calls the Select2 plugin field will be up and running, saving / retrieving data for any field / model. The way I am doing this also integrates better with Yii2 and makes use of the Yii2 relations to fetch associated Select2 data, so this way integrates deeper with Yii2.

Allowing the user to select items on a form and have the software application save those items as a many to many relationship is not always an easy task. This method takes away some of the complexity of that, so that I can have user defined many to many relationships between models / database tables.

Populating standard columns in a database table using Yii 2

When creating web based software applications we sometimes want to have a standard way of populating a variety of database table columns which we intend to appear in multiple database tables within our software application. These columns may generally include the following …

  1. userID – for storing the user ID of the user who owns the record
  2. createdDate – for storing the date the record was created
  3. createdBy – for storing the ID of the user who created the record
  4. updatedDate – for storing the date the record was updated
  5. updatedBy – for storing the ID of the user who updated the record

The above are the standard columns I normally use within my database tables when creating web applications. I deliberately separate the userID from the createdBy and updatedBy. As I look at the createdBy and updatedBy as more of a audit trail and the userID as the actual owner of the record and the foreign key which connects that record to the users table.

In this article I am going to show you a method to populate these values automatically. These fields will be populated whenever you save a record within the web application.

As I presume you are going to want this method exposed to more than 1 Model within the web application I advise you first read the earlier article I wrote about creating master Models and Controllers …

Create a master Model and Controller in Yii2

Master Model and Controller classes are Model and Controller classes which are a parent class to all Model and Controller classes within your web application. All of the methods within the master Model and Controller classes are exposed to the Model and Controller classes within your web application that extend from those master Model and Controller classes.

Now that you have created a master Model make sure you have the following use statements within your master Model …

Now put the following method in your master Model …

The Yii2 beforeSave method will fire whenever a Model is saved within your web application. As the beforeSave method is used in our master Model, the beforeSave method will fire whenever a Model is saved providing that Model extends from our master Model.

The method above is made up of 5 IF statements each setting a variable on the Model. The variables on the Model are those 5 database table columns discussed at the beginning of the article. The above code can summarized as follows …

  1. Line 1 – beforeSave method, $insert variable is true or false depending on whether this is inserting a new record or updating an existing record. Yii2 sets the $insert automatically
  2. Line 3 – IF statement checks to see … userID column exists in table, this record is a new record being inserted, the user is logged in and hence has a userID, the userID variable has not already been set on the Model
  3. Line 4 – Set the userID variable on the Model to be the logged in users user ID
  4. Line 6 – IF statement checks to see … createdDate column exists in table, this record is a new record being inserted
  5. Line 7 – Set the createdDate variable on the Model to be the current datetime
  6. Line 9 – IF statement checks to see … createdBy column exists in table, this record is a new record being inserted, the user is logged in and hence has a userID
  7. Line 10 – Set the createdBy variable on the Model to be the logged in users user ID
  8. Line 12 – IF statement checks to see … updatedDate column exists in table
  9. Line 13 – Set the updatedDate variable on the Model to be the current datetime
  10. Line 15 – IF statement checks to see … updatedBy column exists in table, the user is logged in and hence has a userID
  11. Line 16 – Set the updatedBy variable on the Model to be the logged in users user ID
  12. Line 18 – beforeSave return true, the Model will not save unless this method returns true

If you need to use the beforeSave method in a Model that extends from the master Model and you want to retain the functionality of the beforeSave in the parent model you will need to call the parent beforeSave as follows …

Please note you do not have to use the beforeSave method in a Model that extends from the master Model for the beforeSave method in the Master Model to work. The above example is only shown in case you want to run further code in the extended Model that happens on the beforeSave whilst still retaining the functionality in the master Model. If the extended Model has no beforeSave method that is fine, the code will still run in the master Model and populate the database columns with the data.

It is also worth noting that you can also use the afterFind to format the data when finding Model records …

The above example shows the automatic formatting of the created and updated dates for user interface display purposes within our web application. The examples in this article can be extended to include any data or code you like in the beforeSave and afterFind methods. I personally use these methods in the web software applications to save and format general data that is used through many of the database tables within the web software application.

This method reduces code duplication, reduces chance for errors as the code is not in multiple places, keeps the code neat and tidy by only being in one place. This method frees you up to concentrate on other areas of the web software application.

Recursive deletion in Yii2 using Yii2 Models and Model relations

Sometimes when creating delete functionality within a web application we want to delete more than the record the user is trying to delete. Some records relate to other records and when a record is deleted we want to delete the records that are related to that record because those records no longer serve a purpose.

Some developers like to do recursive deletion at the SQL level using Cascading Deletion, however I and some other developers prefer to do it at the code level. In this case that would be PHP using the Yii2 framework.

To develop the recursive deletion in Yii2 it would be best to create a master Model, as the method I am about to explain to you is more than likely going to be used in more than 1 Model. As most likely you will want all of your Models to have this functionality exposed to them.

A master Model is a Model in which all other Models extend from, the extended Models have access to the methods within the parent Model, in this case the deleteRecursive method. To learn how to build this you can read my previous article …

Create a master Model and Controller in Yii2

After you have created your master Model you can place the following deleteRecursive method within it …

The recursiveDelete above can be explained as follows …

  1. Line 3 – foreach to loop around each item in the relations array
  2. Line 5 – check whether the relation for the Model is an array, this checks whether the relation is a ONE (not array) or a MANY (array). It uses the name provided in the relations array to call the relation
  3. Line 7 – foreach to loop through all of records returned by the relation. In this case that would handle a MANY relation.
  4. Line 8 – call the deleteRecursive function recursively. This will then use the deleteRecursive method of the related Model and delete the record and related records within that Model as well
  5. Line 12 – check to see whether this Model has a related Model, this would be a ONE relation
  6. Line 13 – call the deleteRecursive function recursively. This will then use the deleteRecursive method of the related Model and delete the record and related records within that Model as well
  7. Line 19 – delete the current record

In the extended Models you can call the deleteRecursive method as follows, make sure you setup your relations as you normally would in Yii2 using the Model relations, in the relations array put the names of the relations you have set up …

The “authors”, “pages”, “prices” are the relations / relation names used in this example.

This method is then called as follows …

The above will delete the Book record as well as “authors”, “pages”, “prices” related records and if those Models contain a deleteRecursive method those Models relations will also be deleted.

The deleteRecursive method above can be also be called as follows …

Due to the way the deleteRecursive method was set up you can override the relation / relation names at the time of deletion. This method has proved very useful for me and is a neat and tidy way of deleting Model records along with their related Model records.