array_map plus other possibilities

When building web applications certain patterns appear in our code. A pattern that use to appear in my code quite regularly is shown in the example below …

Essentially we have an array of data and we want to create a new array out of only part of the original data. The above code can be abstracted using the PHP array_map function as shown in the example below …

PHP includes a number of these functions within its library. PHP also gives you the ability to create your own. The above array_map function can be created in PHP as follows …

Using code similar to the above is also the key to implementing iteration functions on collections allowing you to write code as such …

Or filtering …

The possibilities this opens are numerous. If you would like to know more about writing code similar to the above then I can recommend the following book …

https://adamwathan.me/refactoring-to-collections/

Refactoring to Collections – The Definitive Guide to Curing the Common Loop by Adam Wathan

Select2 library solution in Yii2 part 4 – retrieving the data

To continue on from the previous article I wrote about saving the Select2 data …

http://www.jamesbarnsley.com/site/2016/11/07/select2-library-solution-in-yii2-part-3-saving-the-data/

I will now talk about how to the retrieve the stored Select2 data so that the data can be displayed on the front-end Select2 field. Following on from the Task / Countries example, place the following “loadSelect2Items” method inside the Master model or Task model if you did not create a Master model …

The code above can be explained as follows …

  1. Line 3 – return the array of Select2 data using the “array_map” function
  2. Line 4 – store the related entity models name into a variable, in this case that would be the Country models name. This uses the Country relationship that was created in “Part 2” of this article series
  3. Line 5 – store the IDs of the related relationship entity model in the return data, in this case that would be the IDs of the Country model records
  4. Line 6 – find all the records for the model / model property in the “select2_data” table, in this case that would be the Task model and “countries” property

The next step is use the “loadSelect2Items” in the Task model to the load the Select2 data into the “countries” property, place the following inside the “afterFind” method of the Task model …

So that concludes the Select2 library solution for Yii2. I have covered the creation of the necessary database table and the read / write methods for reading / writing the data.

After the initial methods have been setup this solution will provide you with a way of easily putting a Select2 field on your forms that allows for many to many relationships between models with just a couple of line of code.

Select2 library solution in Yii2 part 3 – saving the data

To continue from the previous article …

http://www.jamesbarnsley.com/site/2016/10/31/select2-library-solution-in-yii2-part-2-database/

Once the database table has been created the code can now be written to display the Select2 field on the form and save the Select2 data to the database table.

In this article I will demonstrate the Select2 functionality as though we are wanting to add “Tags” to a Task model. When I say “Tags” I mean the standard web term for Tags. Essentially these are words that you can tag to an entity for example a WordPress article that categorizes the WordPress article using the tags allowing a user to search by those words.

When I say Task model, this is a fictional model in a Yii2 application that will allow the user to create and update tasks. For the purposes of this article it is assumed you will create your own Task model along with the controller and views. Create a standard CRUD for tasks possibly giving each task a name and a description.

You will need to create a Tag database table to store the Tag data along with its associated model. Create a database table with “id” field for the primary key and a “name” field to store the Tag name. Create a standard Yii2 model for the Tag table, this model does not need any methods inside it, it is a blank Yii2 model that extends ActiveRecord.

After you have created your task CRUD functionality and the Tag database table with associated model the Select2 functionality can be integrated.

First the field is added to the form using the Kartik Select2 plugin. The plugin can be found here …

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

Add the field to the form using code similar to this. Include the plugin in the form …

Add the field to the form …

Create a “tags” property in the Task model, this will be used to store the tags field data on both saving and retrieving …

Now the field is added to the form and you have a property in which to store the array of data which the Select2 library needs in order to function. Next you need to use the “saveSelect2Items” items method as shown below to save the array data in the “tags” property to the database.

The “saveSelect2Items” method can be placed inside the Task model but it would be better in some kind of global area such as a Master model as is it likely that you will want to use the functionality in more than one model / form. I wrote an article on how to create Master models which can be read here …

http://www.jamesbarnsley.com/site/2016/03/14/create-a-master-model-and-controller-in-yii2/

The “saveSelect2Items” method is as follows …

The code above can be explained as follows …

  1. Line 3 – get the class name of the model object in this case that would be the Task model and convert it to lowercase characters
  2. Line 4 – get the class name of the store model object in this case that would be the Tag model and convert it to lowercase characters
  3. Line 5 – get the Select2 array data of the model object in this case that would be the “tags” property in the Task model
  4. Line 7 – if the model object Select2 property is not empty, in this case that would be the “tag” property
  5. Line 9 – get the current stored records in relation to the model and model properties we are using. In this case the Task model, Tag model and “tag” property
  6. Line 11 – loop through the currently stored records
  7. Line 13 – if the related model object ID is not in the model object property array data. In this case that is if the Tag ID is not in the “tag” property array data
  8. Line 15 – set the deleted flag to 1, which indicates deleted
  9. Line 16 – save the record
  10. Line 22 – loop through the array data in the model object property, in this case that is the Task model “tags” property
  11. Line 24 – check to see whether a record already exists in relation to the model and model properties we are using. In this case the Task model, Tag model and “tag” property
  12. Line 26 – if no existing record can be found
  13. Line 28 to 33 – create a new Select2 record and set the properties
  14. Line 35 and 36 – save the new Select2 record but if it does not save then return false
  15. Line 42 – the else part of the original if statement, if there is no array data in the “tags” property
  16. Line 44 – delete all the existing records for the model we are dealing with. In this case that is the Task model

As mentioned in the database article the “saveSelect2Items” method soft deletes the unwanted Select2 records with a little adaptation this could be altered to hard delete the records.

Now that the “saveSelect2Items” has been created you can call it in your Task model by placing the following code in the “beforeSave” method of the Task model …

The first parameter of the “saveSelect2Items” is the property used to store the Select2 array data, the second parameter is the original model that uses the Select2 field on the form in this case that is the Task model. The third parameter is the relation model in this case that is the Tag model.

The code up to this point puts a Select2 field on a form and saves the Select2 data when the form is saved. If you go back to the form the Select2 field will not be populated with the saved data yet as that is covered in the next article which talks about retrieving the Select2 data.

Select2 library solution in Yii2 part 2 – database

To continue from the previous article …

http://www.jamesbarnsley.com/site/2016/10/24/select2-library-solution-in-yii2-part-1-introduction/

I will now talk about the database table needed to get my implementation of the Select2 library working. As mentioned earlier the original design for the database included a table for each set of Select2 relations. So if I wanted a Person to be able to select multiple Countries I would have a Select2 PersonCountries table, 1 table per relation.

The latest design for the database has just 1 table to store all of the Select2 relations used throughout the web software application. I find this easier as I can then use the Select2 like a module, whenever I want Select2 in my web software application I just drop in the code files along with the database table.

The database table I am using is as follows …

I will now run through what the columns in the database table are used for …

  1. id – unique integer for the record
  2. entityModel – the short name of the model class stored in lowercase characters, for example the “Person” model
  3. entityModelField – the name of the model property used on the form to select the related Select2 relations, for example “countries”
  4. entityModelID – the ID of the model, for example the ID of the “Person” model
  5. relationEntityModel – the short name of the related model class in lowercase characters, for example the “Country” model
  6. relationEntityModelID – the ID of the related model, for example the ID of the “Country” model
  7. deleted – a flag to determine if this record is deleted
  8. createdBy – the ID of the user this record was created by
  9. createdDate – the date this record was created
  10. updatedBy – the ID of the user who last updated this record
  11. updatedDate – the date this record was last updated

Please note that “id” is just a standard primary key and is not unique to this article also deleted, createdBy, createdDate, updatedBy and updatedDate are not unique to this article. These are just standard columns that I populate all of my tables with and are not really necessary for the purposes of this article.

The deleted column may be necessary if you are running the code exactly as explained in this article but the record could have just as easily have been hard deleted and hence the deleted column is just personal preference.

To know more about the standard columns I use and to auto populate these columns read the following article …

http://www.jamesbarnsley.com/site/2016/04/04/populating-standard-columns-in-a-database-table-using-yii-2/

The above database table is the table I use to power the Select2 library relations in my web software applications. An example use case for this can be described as follows …

You have a update Person form (entityModel) with a countries field (entityModelField) that allows the user to select various Countries that are related to the person (the ID of the Person is the entityModelID). You can select various Countries and save them to the Person. For each country saved a select2_library record will be created, the ID of the Country is the relationEntityModelID and the Country model itself is the relationEntityModel.

At this point a Select2Library model will need to be created for the “select2_library” table. In the example used in this article a relationship will need to be created between the Select2Library model and the Country model. This will need to be created using the “relationEntityModelID” like this …

All of the above will become clearer when actually running the code and seeing the results. The code to get this to run will be described in the follow up articles.

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.

Generating a unique random string for Model properties in Yii2

When building web software applications I sometimes need a way to generate unique random strings. Unique random strings can be used as character keys or tokens to identify database records without having to give away the database records ID number. I personally use unique random strings to produce clickable links in my “Request lost password” emails. The unique random string can be matched to a user record and the password can be re-created and sent to the user.

In this article I will show you a method of creating unique random strings. Yii2 already has a way of generating random strings but these will not always necessarily be unique, so in cases where they need to be, this method will come in use. The method I am about to show is named “generateUniqueRandomString”. I would recommend placing this method in a master Model as it is likely that you are going to want to use this method in more than 1 Model and want it exposed to many different Models.

I covered how to create master Models in a previous article which you can read here …

Create a master Model and Controller in Yii2

After you have created the master Model make sure you put the following “use” statement within it …

Now place the following “generateUniqueRandomString” method inside the master Model …

The above code can be explained as follows …

  1. Line 3 – Use the standard Yii2 “generateRandomString” method to generate a random string of characters
  2. Line 5 – IF statement to check whether the random string already exists for the Model, checked against the attribute (or DB column) passed in through the methods parameters
  3. Line 6 – If the random string does not exist already then return the random string
  4. Line 8 – If the random string does exist already, then recursively run the method again and try and generate a different random string that does not already exist

You can use the above method like follows …

The above code shows a book being found and a unique random string being generated for the books “characterKeyString” property. The book is then saved.

The length by default is set to 32 which means it will generate a 32 character unique random string. If you want to change the length just pass in the second parameter as the length you want to generate.

This method is very useful for when it is important that a random string is unique. I have personally used this method in my user creation, lost password request and file storage parts of my web software applications.

Creating a Utility class in Yii2

A Utility class is a place to put all common methods that will often need to be re-used in a web software application. During a previous article it was demonstrated how to create a master Model and Controller …

Create a master Model and Controller in Yii2

The master Model and Controller are good places to store a lot of re-used methods that relate to Models and Controllers. Sometimes though methods may not relate to Models and Controllers and need to re-used elsewhere in the web software application. This is where the Utility is useful. It is important to note that the Utility class is not designed to be instantiated as an object and should contain “static” methods that can act independently.

To create a Utility class create a new file called “Utility.php” and place it inside your “components” folder. Inside the “Utility.php” file place the following code …

The above code shows a blank Utility class ready to be populated with re-usable methods. Below shows a Utility class with an example method …

Notice how the method is defined as “static”, this is because the Utility class will not be instantiated into an object when used in the web software application. The method within the Utlity class can be used in the web software application as follows …

Include the Utility class into the file the Utility class will be used in …

Now call the desired Utility class method …

I personally create a Utility class in all my web software applications and find it a useful place to store re-usable methods that do not relate to Models and Controllers. Re-usable methods that do relate to Models and Controllers I store in the master Model and Controller, re-usable methods that do not relate to Models and Controllers I store in the Utility class.

Defining array data in Models using Yii2

Array data can be used in many places in a web application but one aspect of using array data in a Yii2 web application is to populate dropdown lists. Yii2 dropdown lists are populated with array data, the array data defines the items that will appear in the dropdown list.

Yii2 has special helpers when it comes to populating a dropdown list with database data namely ArrayHelper::map and the standard Yii2 Models. Populating a dropdown list with database data will not be covered in this article. This article is about populating a dropdown list using hard coded data.

In the example below you are shown a way of storing the data in a magic property for a number of colour choices that are wanting to be used in a dropdown list within a add / edit book form. The method below would reside in the Model in this case a Book Model …

Now inside the form the dropdown list is rendered to use the data in the above method as follows …

If the standard “prompt” setting is needed for the dropdown list or there are some other specific items needed in the data they can be kept separate from the hard-coded data array in the Model like follows …

After this data has been saved the data can be displayed within your application by writing a method to format the selected “colourChoice” within your web application …

The above method can be used as follows …

If the data could be classified as being more global than a “books colour choice” for example a “yes or no” dropdown list, then it is possible to place the above methods inside a master Model which will mean that the dropdown list data will be accessible from any Model that extends the master Model …

Create a master Model and Controller in Yii2

I have used the above methods including placing the above methods in my master Model to store all the hardcoded data used for dropdown lists as well other purposes to great effect. The above methods are much better than hardcoding the data in the views as having the data in the Models is a more natural place for the data to reside as well as being accessible to multiple parts of the web application.

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.