Create your first custom add-on: Feedbacks – Part 3/3

This is the third and final part of the tutorial Create your first custom add-on, where we are creating an add-on to store the feedback messages from our users.

In this last part of the tutorial we will create the client side scripts to make the calls to the web service endpoints that we created in the previous parts.

As generic purpose way of handling a custom add-on we will create two classes for our example: one that will provide us the URL of our web service (and eventually any other generic stuff related to your add-on) and one to represent a Feedback object in Unity.

To deserialize the JSON string returned from the endpoints we can use either the Combu internal extension method hashtableFromJson() of the string class or (if you are on Unity 2017 or greater) JsonUtility.FromJson.

We will use the extension method in this example.

FeedbacksAddon.cs

Here we provide just a static property that is the URL of our PHP web service.

namespace Combu.Addons.Feedbacks
{
    public class FeedbacksAddon
    {
        const string WEBSERVICE_ROOT = "addons/feedbacks/client.php";

        public static string URL
        {
            get
            {
                if (CombuManager.isInitialized)
                {
                    return CombuManager.instance.GetUrl(WEBSERVICE_ROOT);
                }
                return string.Empty;
            }
        }
    }
}

Feedback.cs

This file contains the declaration of the Feedback class, it has almost the same public properties (and methods) as its server side counterpart.

using System;
using System.Collections;
using System.Collections.Generic;

namespace Combu.Addons.Feedbacks
{
    [Serializable]
    public class Feedback
    {
        public long Id;
        public long IdAccount;
        public string Title;
        public string Message;
        public DateTime? DateCreated;
        public DateTime? DateUpdated;
        public int Rating;
        public User User;

        #region Constructors

        public Feedback()
        {
        }
        public Feedback(string jsonString)
        {
            FromJson(jsonString);
        }
        public Feedback(Hashtable data)
        {
            FromHashtable(data);
        }

        #endregion

        #region JSON serialization/deserialization

        void FromJson(string jsonString)
        {
            FromHashtable(jsonString.hashtableFromJson());
        }

        void FromHashtable(Hashtable data)
        {
            if (data == null)
                return;
            if (data.ContainsKey("Id") && data["Id"] != null)
            {
                if (!long.TryParse(data["Id"].ToString(), out Id))
                    Id = 0;
            }
            if (data.ContainsKey("IdAccount") && data["IdAccount"] != null)
            {
                if (!long.TryParse(data["IdAccount"].ToString(), out IdAccount))
                    IdAccount = 0;
            }
            if (data.ContainsKey("Title") && data["Title"] != null)
            {
                Title = data["Title"].ToString();
            }
            if (data.ContainsKey("Description") && data["Description"] != null)
            {
                Message = data["Description"].ToString();
            }
            if (data.ContainsKey("Message") && data["Message"] != null)
            {
                Message = data["Message"].ToString();
            }
            if (data.ContainsKey("DateCreated") && !string.IsNullOrEmpty(data["DateCreated"] + ""))
            {
                DateTime date;
                if (DateTime.TryParse(data["DateCreated"].ToString(), out date))
                {
                    DateCreated = date;
                }
                else
                {
                    DateCreated = null;
                }
            }
            if (data.ContainsKey("DateUpdated") && !string.IsNullOrEmpty(data["DateUpdated"] + ""))
            {
                DateTime date;
                if (DateTime.TryParse(data["DateUpdated"].ToString(), out date))
                {
                    DateUpdated = date;
                }
                else
                {
                    DateUpdated = null;
                }
            }
            if (data.ContainsKey("Rating") && data["Rating"] != null)
            {
                if (!int.TryParse(data["Rating"].ToString(), out Rating))
                    Rating = 0;
            }
            if (data.ContainsKey("User") && data["User"] != null)
            {
                if (data["User"] is Hashtable)
                    User = new User(data["User"] as Hashtable);
                else
                    User = new User(data["User"].ToString());
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Retrieve a list of feedbacks.
        /// </summary>
        /// <returns>The list of feedbacks.</returns>
        /// <param name="callback">Callback.</param>
        public static void List(Action<Feedback[]> callback)
        {
            CombuForm form = new CombuForm();
            form.AddField("action", "list");
            CombuManager.instance.CallWebservice(FeedbacksAddon.URL, form, (string text, string error) =>
            {
                List<Feedback> results = new List<Feedback>();
                if (string.IsNullOrEmpty(error) && !string.IsNullOrEmpty(text))
                {
                    Hashtable response = text.hashtableFromJson();
                    if (response != null && response.ContainsKey("results"))
                    {
                        ArrayList list = (ArrayList)response["results"];
                        if (list != null)
                        {
                            foreach (Hashtable data in list)
                            {
                                // Create a new object from the result
                                Feedback record = new Feedback(data);
                                // Add to the list
                                results.Add(record);
                            }
                        }
                    }
                }
                if (callback != null)
                    callback(results.ToArray());
            });
        }

        /// <summary>
        /// Retrieve a feedback.
        /// </summary>
        /// <returns>The feedback or null.</returns>
        /// <param name="id">Identifier.</param>
        /// <param name="callback">Callback.</param>
        public static void Load(long id, Action<Feedback> callback)
        {
            CombuForm form = new CombuForm();
            form.AddField("action", "load");
            form.AddField("Id", id.ToString());
            CombuManager.instance.CallWebservice(FeedbacksAddon.URL, form, (string text, string error) =>
            {
                Feedback result = null;
                if (string.IsNullOrEmpty(error) && !string.IsNullOrEmpty(text))
                {
                    Hashtable response = text.hashtableFromJson();
                    if (response != null && response.ContainsKey("success"))
                    {
                        bool success;
                        bool.TryParse(response["success"] + "", out success);
                        if (success)
                        {
                            // Create a new object from the result
                            result = new Feedback(response["message"] + "");
                        }
                        else if (!string.IsNullOrEmpty(response["message"] + ""))
                        {
                            error = response["message"].ToString();
                        }
                    }
                }
                if (callback != null)
                    callback(result);
            });
        }

        /// <summary>
        /// Save this feedback.
        /// </summary>
        /// <param name="callback">Callback.</param>
        public void Save(Action<bool, string> callback)
        {
            CombuForm form = new CombuForm();
            form.AddField("action", "save");
            form.AddField("Id", Id.ToString());
            form.AddField("Title", Title);
            form.AddField("Message", Message);
            form.AddField("Rating", Rating.ToString());
            CombuManager.instance.CallWebservice(FeedbacksAddon.URL, form, (string text, string error) =>
            {
                bool success = false;
                if (string.IsNullOrEmpty(error) && !string.IsNullOrEmpty(text))
                {
                    Hashtable response = text.hashtableFromJson();
                    if (response != null && response.ContainsKey("success"))
                    {
                        bool.TryParse(response["success"] + "", out success);
                        if (success)
                        {
                            FromJson(response["message"] + "");
                        }
                        else if (!string.IsNullOrEmpty(response["message"] + ""))
                        {
                            error = response["message"].ToString();
                        }
                    }
                }
                if (callback != null)
                    callback(success, error);
            });
        }

        /// <summary>
        /// Delete this feedback.
        /// </summary>
        /// <param name="callback">Callback.</param>
        public void Delete(Action<bool, string> callback)
        {
            Delete(Id, callback);
        }

        /// <summary>
        /// Delete a feedback.
        /// </summary>
        /// <param name="id">Identifier</param>
        /// <param name="callback">Callback.</param>
        public static void Delete(long id, Action<bool, string> callback)
        {
            CombuForm form = new CombuForm();
            form.AddField("action", "delete");
            form.AddField("Id", id.ToString());
            CombuManager.instance.CallWebservice(FeedbacksAddon.URL, form, (string text, string error) =>
            {
                bool success = false;
                if (string.IsNullOrEmpty(error) && !string.IsNullOrEmpty(text))
                {
                    Hashtable response = text.hashtableFromJson();
                    if (response != null && response.ContainsKey("success"))
                    {
                        bool.TryParse(response["success"] + "", out success);
                        if (!success && !string.IsNullOrEmpty(response["message"] + ""))
                        {
                            error = response["message"].ToString();
                        }
                    }
                }
                if (callback != null)
                    callback(success, error);
            });
        }

        #endregion
    }
}

Now to send a new feedback from client we will have some code like the following:

Feedback newFeedback = new Feedback();
newFeedback.Title = "Awesome!";
newFeedback.Message = "Hey, I was here!";
newFeedback.Rating = 5;
newFeedback.Save((bool success, string error) =>
{
    Debug.Log(success + " - " + error);
});

While to retrieve the list of feedbacks sent:

Feedback.List((Feedback[] feedbacks) =>
{
    Debug.Log(feedbacks.Length + " feedbacks received");
    foreach (Feedback feedback in feedbacks)
    {
        Debug.Log("#" + feedback.Id + 
            " at " + (feedback.DateCreated.HasValue ? feedback.DateCreated.Value.ToLongDateString() : "") + 
            " from " + (feedback.User != null ? feedback.User.userName : "Unknown") + 
            " with title '" + feedback.Title + "': " + feedback.Message);
    }
});

We can also load a feedback if we know its Id:

Feedback.Load(1, (Feedback feedback) =>
{
    if (feedback != null)
    {
        Debug.Log("#" + feedback.Id +
            " at " + (feedback.DateCreated.HasValue ? feedback.DateCreated.Value.ToLongDateString() : "") +
            " from " + (feedback.User != null ? feedback.User.userName : "Unknown") +
            " with title '" + feedback.Title + "': " + feedback.Message);
    }
});

If we have a reference to a feedback object then we can also delete it:

myFeedback.Delete((bool success, string error) =>
{
    Debug.Log(success + " - " + error);
});

Or we can delete a feedback if we know its Id:

Feedback.Delete(1, (bool success, string error) =>
{
    Debug.Log(success + " - " + error);
});

Conclusions

This example covers the most basic features of creating your own entities with the properties and methods that you need in a generic situation and persist them on database for later access.

As exercise you could try to extend the core features explained in this tutorial and add for example the pagination to the method Feedback.List (HINT: take a look at existing client and server core scripts, like Combu.News).

2 comments on “Create your first custom add-on: Feedbacks – Part 3/3

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.