Arkiv för ‘PHP’ kategori

Data Objects for Osclass plugins using dliCore

13 april, 2015

As mentioned in our previous post regarding database tables for Osclass plugins written using dliCore the library offers another way to access the data stored in your tables. It was a thought that originated in an old library I did many years ago that I simplified for this case. The old approach consisted of something I called data gateways. These gateways would fill objects (that knew nothing about the back end storing the data) with data. The objects could be loaded and saved from each back end through the respective gate way. This made it quick and easy to change your code from working with the database to testing using mock-up data in xml files.

For dliCore I took parts of this an made a system that would abstract the database layer for the developer and allow them to work with objects instead. I made it so that it would not require a huge overhead and it would also keep track of the fact that objects and databases were in sync. By that I mean that if you add a column to your table and you don’t allow it to have a default value then it must be present in the object or an exception is thrown.

Here I give a very simple presentation about how to connect an object to a table. Let’s use a simple messages table in a plugin called userMessages in our example.

Create table

First we create our table class.

Our messages contains a id, a foreign key to the receiving user, a foreign key to the sending user, a title, the contents and a date time of when the message was sent. Indexes to speed up access by date etc could of course be added.

Register table

Now we register the table with our plugin to it will be installed when the plugin is installed.

Creating our data object

Now we create an object that extends DbModel. We tell it which table it’s connected to and we give it the member variables needed to carry the data. Note that we could add more variables here than what is available in the table and add additional logic as well.

If a set function is present, that will be used when creating the object when reading from the database. So any extra logic needed on data read from the database can be put there. For instance you might store a data in some specific format in the database but want it to be stored differently within the object. If this need does not exist and there is no wish for any public get or set functions they can be left out.

Functionality to save a single or multiple items and fetch items based on their primary key exists by default. Even multi-column primary keys are supported. To add extended functionality like we did in our old DAO object we can do things like this to our object.

Working with your objects

By these simple steps you can now do things like

Closing thoughts

If one opts-in to use this style you get an easy encapsulation of objects without much work. For the standard tables like User these objects will also be made available by the library. That way, user objects can be passed around instead of user id´s or associative arrays.

Note that just as with most parts of dliCore, the use of these objects are purely optional. You can stick to just creating the tables in this new way, or doing it the old manual way and sticking with DAO your old objects. For older plugins being moved to use dliCore this can help reduce the needed modifications.

 

Flattr this!

Database Tables for Osclass plugins using dliCore

13 april, 2015

One thing that a lot of plugins wish to do is to save persistent data. This can be done in a number of ways. There are volatile ways like storing them in memory etc and non volatile ones like storing data to files, databases and similar. Since Osclass itself uses the MySQL database (probably works fine with Miranda DB to) a lot of plugins use this to store their data.

As with most things, working with databases has had a “semi official” way established.

Most plugins tend to do things in the following way.

Define table structure

The table structure is placed in a file. This is commonly named struct.sql but could be named anything. Here’s a small mock-up of a table for storing some random extra data for a users profile.

Osclass internally uses prefixes on column names to convey what type of data the column contains.

The comment /*TABLE_PREFIX*/ will be automatically replaced with the prefix defined in the config.php file in the root folder of your Osclass installation.

Some plugins have one table defined in the file, some have several, others have several files with one table in each file etc. For instance our i_data_type column might have a table with mapping between datatype id’s and actual names. However, this could also be mapped in the PHP code.

This file is then read and executed during plugin installations. I have seen several ways, but a common one is to call something like this in the plugins install function

 

DAO objects

Most plugins then create their own DAO object by extending the DAO class of Osclass. I have also seen examples of plugins doing queries directly in their own functions (often contained in a very messy index.php file… hehe). I would suggest that you at least use the base DAO object in Osclass to communicate with your database since it handles a lot of work for you.

Extending it and making your own class is good if you want to encapsulate functions within it.

If we for example wanted to get the data of a particular type for a given user you could have a function in your DAO object that looked something like this

You would then build up more and more functionality and add more and more functions for what you needed to be able to do with your data.

Something to think about

There are some issues with this approach. Not really problems with Osclass itself, but things people should think about.

Most sites I have visited has has their struct.sql files visible. That means that anyone could type in the url to the struct file and view the layout. This could then be used to identify potential ways to compromise the site. Since most plugins use this common approach and naming scheme it’s quite easy to locate schema files to view. You could “fix” this by editing your .htaccess file to not allow .sql files to be viewed. Something lite this should work.

Also, passing data around as associative arrays makes it easy to introduce errors that go unnoticed until code is in production. If you use an IDE that gives you nice warnings about typos in function names etc, make sure you type your array keys correctly since it will not report errors in those 🙂

How you could do it using dliCore

Since dliCore is all about encapsulating things and streamlining there is functionality in place to handle databases to. Instead of manually adding code to a plugins install and uninstall function to read and execute code to install the needed schemas dliCore let you define tables as classes.

Defining a table in dliCore

Our previous example table in a plugin named extendedProfile would be created something like this.

Note that most look the same. But we use /*TABLE_NAME*/ instead of /*TABLE_PREFIX*/. This is a new option in dliCore that will equate to /*TABLE_PREFIX*/ plus the $_tableName of the table in question. This is mostly for convenience.

Since the struct is now part of the class it’s not visible to a user trying to access it like it could have been in a .sql file.

The AbstractTable base class contains functions to install and uninstall the table. We could add an optional function called updateSchema which will be called if a plugin is updated. It will in that case be passed the previously installed version and the newly installed one.

In that function any alterations to lift a schema to new versions could be carried out.

Registering tables

In order to have your table installed and uninstalled with a plugin (as well as notified when a plugin is updated) you register it with the plugin that is the owner of it. This can be done in your plugins _init function.

The _registerTable function is a member function of he Plugin class and takes either an instance of the table or the class name of the table and an internal name. Using the class name makes sure that no instance is created until it’s needed.

Any table registered with a plugin has their installSchema function called when the plugin is installed and their uninstallSchema function called when a plugin is uninstalled.

So adding a table to a dliCore based plugin is a matter of creating your table class like above and registering it with the plugin. The rest is done for you.

Accessing data

Note that we didn’t create any functions to access the data in our table class like we did in our DAO object. You could do this if you want to. As with most things in dliCore it’s optional to use features or stick to the old school way of doing things. But another way to access and work with data objects is to use the dliCore dbModel class. I will talk more about that next time.

Flattr this!

Streamlining, accelerating and encapsulating Osclass plugin development

12 april, 2015

In our previous post we looked at the basics of building a plugin for Osclass. There are however quite a few issues that I have observed in almost every plugin I have looked at that I felt I wanted to do differently.

Issues I saw with plugins

  • index.php often becomes bloated with functions that handle every aspect of the plugin. At rare occasions are classes that separate logic and presentation introduced (I did this myself when usign the official way of constructing plugins), but more often than not index.php will just consist of a myriad of function mixing logic and presentation, acting as functions for hooks and so on and so fourth.
  • All functions in index.php are publicly available. That means that for plugins that ended up having all their function in index.php, any one of these functions would be publicly available to call from any other plugin.
  • More often than not hooks will be riddled with html code, javascript together with switch and if statements.
  • Plugins are not naturaly object oriented.

Now, you can solve a lot of these issues on your own and some things are not even problems to some people. Object Oriented development might not be your cup of tea and in that case you will not have the same issues I have with this. But to me Object Oriented development is a great way to encapsulate functionality. For instance for a Plugin.

I have for example introduced classes that actually handle my logic and presentation that were basically just called from the hooks in my plugin. But as time went on and I noticed I did more than the few plugins I originally thought I would be doing I felt I wanted some base for my plugins and not reinvent the wheel every time.

Streamlining, accelerating and encapsulating Osclass plugin development

I decided to build myself a base library that I could use to quickly create new plugins. I created dliCore which consists of two components. It’s all just a few days old so things could change, but here’s some of the basics of what I want to achieve.

dliCore

dliCore is a plugin in itself. It provides admin interfaces to configure common things that all plugins based on dliCore can take advantage off.

  • Configuring things like caching manager
  • Presents common place for support requests regarding plugins built using dliCore
  • Contains dliLib and makes sure that is available to plugins

dliLib

  • Contains a myriad of classes to support development of plugins

Together they present developers with a base that accelerates development of plugins and keep them organized even when they grow to large proportions. Do note that any part of it is optional. There are functionality to link objects to specific database tables, but a developer is free to create an Osclass DAO object and work with that if they want to.

This was primarily meant for my own plugins and could function as a catalyst for others to create their own solutions. But if there is a desire for others to use this I’m open to a public supported release to help all of my fellow plugin developers.

Building our Osclass Hello World plugin using dliCore

With dliCore I wanted to take a more object oriented approach and encapsulate plugins in a more clear manner. Instead of having your index.php file contain a bunch of public functions, all which are loaded, mixed logic and presentation within these functions etc. dliCore allow you to encapsulate all of your plugin functionality within a Plugin object. This makes the index.php file look a bit different.

First we define a namespace for our plugin. These further help us keep our plugin specific code isolated.

A good convention is to have the name of your plugins folder, the namespace and the name of the plugin be the same.

After that we have our normal info block.

I would have liked to be able to include this in the plugin class itself, but due to how Osclass reads that data it’s not possible. I wanted to make sure no alterations were needed to Osclass in order for dliCore to work.

Next we declare that we will be using the PluginManager and our plugin dliTestPlugin.

After that we check that dliCore is enabled. If it is we make sure that the index.php file of dliCore is loaded by a require_once (since we can’t force Osclass to load that before any other plugin) create an instance of our plugin and register it with the PluginManager. If dliCore is not enable we register a install hook that will just tell the user that dliCore is needed for this plugin to work.

Now you might look at this and go

-“But hey, if dliCore is enabled we don’t register any install hook. So we won’t be able to install our plugin… and there’s no uninstall hook either… and…”

Easy there. As I said, everything is encapsulated. We do have install functions and uninstall functions and all the other stuff to. They are just not globally available.

dliTestPlugin

Let’s take a look at our plugin class

Here you can see that our plugin contains two public function. installHook and uninstallHook. These are the functions that will run when the plugin is installed or uninstalled. It actually also automatically handles a lot of other things in the background during installation and installation as well, but we’ll look at that later.

Hooks using dliCore

dliCore makes it super easy for you to add a hook to your plugin. Simply create a public function, name it correctly and you have a working hook.

Registering a hook for the item_detail hook

Registering a hook for the before_html hook

As you can see, you use the normal hook name you want to hook against and write that name in camel case instead of using underscores and then you end the name with Hook.

The exact same behavior  is available for filters, just en the function name in Filter.

How do we handle that routing thingy to show our file helloWorld file?

Using dliCore you are free to setup routes like normal in for instance the _init function of your plugin or even the index.php file. But that would make me a bit sad.

Instead you should use Controllers. Create a subfolder under your plugin and name it Controllers. Insede we create a file HelloWorldController.php.

This controller will handle our logic. That way we can easily keep it separated from the presentation.

By adding an Action function to your controller, dliCore will automatically create the needed routes for it. For instance the route dliTest/HelloWorld/helloWorld will run our helloWorldAction function in our HelloWorldController. All that is done for you.

But we passed a message parameter last time. How do we get the route to understand that it should accept a parameter named message? Well, you simply add it as a paramater to the action function.

This will automatically add to the route that a parameter called message is accepted by the route and will automatically provide your function with the result of that. But how do we make sure the parameter fulfills a specific regexp like we could when we manually crafted our routes? Well, I could have used some array to map function parameters to their regexps etc, but I wanted to keep it all in one place. One place to update if you wanted to add or remove a parameter. At first I was thinking about letting the user provide the regexp in a comment block. But I didn’t really like that. After scratching my head a bit I came to think about the fact that since actions are automatically called I could hijack their default value and use that to convey their regular expressions.

So in order to make sure it’s only valid to pass the characters a-Z to the function, we update it like this.

This means that adding and removing parameters from actions is extremely fast and easy and you only have to alter code in one place. Instead of having to change your function, update your route etc.

Displaying our message

You could very well just echo your message in the action.

That would print our message in a otherwise empty page. This works alright if the response is some JSON etc. But for presentation of normal pages that’s not how I like to do it.

Instead we create a view file. This is our graphical representation file from a request to our given function. So for dliTest/HelloWorld/helloWorld, which ends up running the helloWorldAction function of the HelloWorldController object we create a file named helloWorld.php.

Now we place this file in a sub folder of our plugin views\HelloWorld\helloWorld.php.

The views folder is the top level folder for our views files. HelloWorld is the name of the controller so that all files owned by a given controller can reside in the same place. The helloWorld part of our files name is the name of the action function minus the Action part. That way it’s easy to quickly find a given view file for any action in any controller.

To make it possible to access our message parameter in the view file we export it to the  view.

Then in our view file we write

This will echo our message parameter.

In your view file you could now easily add html markup to style your presentation, without having it mixed with all your logic.

Theme specific views

It’s also possible for you to create theme specific versions of your views. This allows a developer to add support for specific themes or for users to add alterations to specific themes themselves.

To add a theme specific version of a view file, add a folder under the views folder and name it according to the themes name and place your views under that. For instance

views/cooltheme/HelloWorld/helloWorld.php

Any file placed in the sub folder of an active theme that matches a given route will be used before the default view is used.

The default views can be copied and used as a starting point.

Extra features

dliCore contains a myriad of extra functionality connected to database table management, memory usage, caching, handling objects, managing and sending emails etc. More on this in future posts.

Availability

dliCore will be uploaded to the Osclass market so it can be easily installed for any plugin requiring it.

 

Flattr this!

Förslag till en samling tutorials

30 maj, 2011

Jag har funderat lite på vad man skulle kunna göra en tutorial/kurs om. Det finns ju otroligt mycket bra information på nätet redan och även om detta mest hade varit en kul liten grej så hade det varit roligt om någon lärde sig något på samma gång. Jag tror att jag kommer rikta in mig på en webapplikation av enklare slag skriven i PHP. Med enklare menar jag då, inte som omfattande. Vi skall fortfarande använda oss av abstrakta databaslager, AJAX och annat trevligt. Mycket då det saknas en del bra information för den svenska publiken om PHP men också för att det händer mycket med språket. Det möjliggör också för många att testa på det då alla delar vi kommer använda oss av kommer vara gratis (eller ha en free trial) utan att bli beroende av tredjepartslösningar som exempelvis Mono om man nu sitter i exempelvis Linux. Jag är dock inte partisk utan kan mycket väl se att vi i ett senare skede gör om exakt samam applikation i .Net för att se likheter och skillnader.

Jag tänkte försöka utgå ifrån att inte förvänta mig en massa kunskap av de som tar del av materialet. Men naturligtvis så kommer det att hjälpa om man utvecklat tidigare då jag endast kort kommer gå igenom grunder och sedan gå in på lite mera avancerade områden. Jag tänker mig följande upplägg

  1. Sätta upp lokala utvecklingsverktyg och saker att tänka på (OS, IDE, användbara plugins etc)
  2. Sätta upp server (utvecklingsstack, databas, versions hantering etc)
  3. Lite kort om PHP, karakteristiska saker med språket. Styrkor och svagheter etc.
  4. Ett antal enklare mindre program som visar lite på olika sätt att koda under PHP (och många andra språk också)
  5. Enklare introduktion till OOP och hur PHP hanterar detta.
  6. Introduktion till Zend Framework
  7. Introduktion av MVC mönstret

Sedan börjar vi knacka på vår lilla applikation och börjar då titta på hur Zend Framework hanterar views etc. Sedan går vi in på användarhantering, åtkomstkontroll, osv.

Detta är bara en idé om punkter att ta upp och jag tror att det hela, dynamisk, växer fram med tiden. Finns det några idéer eller önskemål så kom gärna med förslag.

Flattr this!

Abstrahera databaslogiken ytterligare en nivå

13 maj, 2011

Hanteringen och kopplingen till datakällorna går ofta igenom en mognadsprocess ju mer en utvecklare lär sig. Det är inte ovanligt att man ser kod i stil med

Många som jobbat lite med databasdrivna applikationer börjar förr eller senare att abstrahera bort databaslogiken. I ett första steg kan detta te sig som så att man skapar objekt som har fint namngivna funktioner, exempelvis ett User objekt med funktioner så som getName() osv. I dessa funktioner sker sedan databasanrop annat. Men det publika interfacet av objektet blir mycket trevligare.

Nästa steg är ofta att hämta ut all relevant data i konstruktorn av User och således inte hämta den varje gång du anropar getUsername(). Sedan bygger man vidare med cachning av datan osv, osv.

Jag satt själv och funderade på detta för ett tag sedan och tänkte att man egentligen bör abstrahera det så pass att User objektet i detta fallet inte har någonting med databasen att göra. Data bör kunna sparas på olika ställen utan att vår User egentligen skall behöva förändras. Så all logik kopplad till lagring av data bör således inte ligga i klassen som definierar vår User.

Istället bestämde jag mig för att göra som så att min modell, User i detta fallet, endast innehöll data, samt funktioner för att manipulera denna data. Att sedan hämta och lagra datan hanteras istället av en annan klass. Jag valde att kalla dessa för Gateways. På detta sätt kan man skapa Gateways som jobbar emot olika datakällor utan att behöva pilla på våra modell klasser. Detta lämpar sig tex om man sitter och utvecklar ny funktionalitet och vill ha testdata lokalt i en XML fil istället för att jobba mot databasen. När det sedan är dags att jobba emot databasen så använder man sig bara av en annan Gateway och så är det löst.

För att uppnå detta skapar vi en basklass för våra modeller. I denna basklass har vi funktioner för att fylla på data, samt att hämta ut data. Vi inför en standard som säger att data i våra datakällor sparas i formatet ‘foo_id’ och att vår modell i så fall kommer innehålla funktioner som heter ‘setFooId()’ och ‘getFooId()’.

En klass för en User hade då sett ut i stil med.

 

Denna modell kan nu innehålla data, men hur skall vi då sköta lagring av våra modeller? Här kommer våra Gateways in. Även här börjar vi med en basklass med det som är gemensamt för alla våra Gateways. En specialanpassad gateway för att spara till DB kan sedan se ut enligt följande.