Jump to content

Matt

Management
  • Posts

    69,390
  • Joined

  • Last visited

  • Days Won

    551

 Content Type 

Downloads

Release Notes

IPS4 Guides

IPS4 Developer Documentation

Invision Community Blog

Development Blog

Deprecation Tracker

Providers Directory

Forums

Events

Store

Gallery

Everything posted by Matt

  1. In a previous blog entry on IP.Board 3.0's new framework, I mentioned that at the core of the new framework is something called 'ipsRegistry'. This blog post will go into more detail and will be of interest to modification authors. Overview IP.Board, like most complex applications, has a need for 'core' data, like settings, session and input data ($_GET, $_POST, etc). There is also a need for a database connection and access to global objects like cached data. It would be incredibly wasteful to make each file and class set up a database connection, load any cached data, authorize the browser session and build up any settings. This could happen many time in any IP.Board view. Clearly there is a need for a way to initialize this data once and then pass it throughout the application. This is exactly what the ipsRegistry is for. Previous versions of IP.Board relied on the 'ipsclass' object as a registry; but this quickly became tarnished without clear boundries as more and more data was attached to it. It was more of a global variable than anything else. The new registry is composed of clearly defined objects. Also in previous versions initialization of the settings, caches, input data, sessions, etc was handled over a scattering of classes and files. The new registry is a single point for this initialization. This initialization occurs when init() is called. This makes it much easier to use IPS registry data in your own scripts and modifications. Previously you would have needed to copy out half of the default index.php. Now your scripts can be as simple as: require_once( 'classes/base/ipsRegistry.php' ); /* Call init which loads up input, caches, settings, creates the DB handle, authorizes and loads the member $registry = ipsRegistry::instance()->init(); print $registry->request()->getField('foo'); $registry->DB()->do_update( 'table', array( 'foo' => 'bar' ); ); print ( $registry->member()->getProperty('member_id') ) ? 'Hello ' . $registry->member()->getProperty('members_display_name') : 'You are a guest'; require_once( 'conf_data.php' ); Gathering Input from URLs and Forms One key part of IP.Board's initialization was the sanitization of $_GET and $_POST into a clean array. This was vital to the overall security of the board. IP.Board 3.0 as a 'request' registry object for this and all functions relating to this initialization (parse_key, parse_value, etc). This is available via either $this->request->getField('foo') or $this->request['foo']. This effectively replaces $this->ipsclass->input['foo']; Cached Data There are many improvements to the caching backend which we'll go into more detail in a later blog entry. The cache registry object simply returns the cache when requested via $this->registry->cache()->getCache('forums'); The cache is loaded and unpacked during initialization so you do not need to manually call it. The Database So much of the database code has been refactored that it's almost a separate blog on its own. Here, I'll concentrate on the registry object. The main function is getDB() which is interfaced via $this->DB (or ipsRegistry: :D B() when outside of class scope). This is a simple function to return the DB object which is set up during initialization via setDB(). This happens transparently when the file is included and init() called (which is done so by ipsController.php). You may set up more connections by specifying a key, for example: return $this->registry->DB( 'newConnection' )->build_and_exec_query( array( 'select' => '*', 'from' => 'table' ) ); $this->DB->setDB( 'mysql', 'newConnection', 'user@localhost.com', 'password', 'localhost' ); Settings The setting cache is loaded and unpacked during initialization. This registry object merely returns the setting when requested via $this->settings->getSetting('foo') or $this->settings['foo']. Member Information Previously member information was scattered through 'ipsclass'. IP.Board's member registry centralizes this information. This object sets up the incoming IP address, browser and operating system and attaches it to the member class. It also authorizes the current browser session (via cookies or an inline URL) and loads up the session member and builds up the permission arrays. All this is done during initialization meaning there is less to do on the front end. I hope this post has given you some insight into the IPS registry and the improvements it brings not only to IP.Board itself, but also to modification authors who will find their workload greatly reduced by automatic set up of all the required information. If you find that you do not need all of this information set up, then you can write a child class of ipsRegistry and alter the 'protected' functions to prevent them from initializing.
  2. HTML logic has been a feature of Invision Power Board for quite some time now. Although we didn't make much use of the '<foreach>' tag so that skins could be backwards compatible, we did make good use of the <if> <else /> logic. Now that we have a clean slate with v3.0, we can really make some positive changes. Invision Power Board 3.0 makes full use of the existing HTML logic and adds some more functionality. This allows for some dramatic customization without touching any of the PHP code. Where possible, each 'view' (board index, topic listing, viewing a topic) has a single template. Previous versions 'stitched' together several templates (as many as 30!) to create a single page view. This meant that some items were fixed and unable to be moved. For example, on the board index, it was not possible to move the board stats above the list of forums. Likewise it was not possible to move the active users below the board statistics. Now you can. You can move any item to any place for that view without having to edit the PHP files themselves. This will really open up designer's creativity and allow some really unique looking templates. Another leap forward for Invision Power Board 3 is the ability to use display logic in the templates themselves. Naturally, we were always able to use <if> and <else /> but you can now use the following standard tags: The Date Tag: Examples: {%date="1210012321"|format="manual{d m Y}"%} {%date="-1 day"|format="long"%} {%date="now"|format="long"|relative="false"%} For the first time, you can now explicitly specify a date format on a per-use basis. The tag accepts either a unix 'timestamp' or a human string like 'now', '-1 day', 'tomorrow', etc. The format parameter can either be a standard IPB date format (long, short, joined, etc) or a manual PHP Date format. The Parse Tag: Examples: <parse expression="substr( $data['name'], 0, 10 )" /> <parse expression="sprintf( "14", "There are %s apples in the bag" )" /> This parse tag allows you to make on-the-spot parsing using PHP code. This tag is replaced with the value returned from PHP. The URL Tag: Examples: {%url="foo=1&bar=2"|base="public"%} {%url="foo=1&bar=2"|label="Click Me"|base="public"|id="myLink"|class="linkCSS"|onclick="this.function()"%} The first example will actually create the entire <a href='' ... >...</a> HTML chunk whereas the second example will only return a formatted URL. The main reason for this tag is to prevent hardcoded entire URLs or even fixing part of the URL to a setting. In IPB 2.3 it wasn't unusual to see this: <a href='{$this->ipsclass->base_url}&act=login'>Log In</a> The new method would be like so: <a href='{%url="act=login"|base="public"%}'>Log In</a> The 'base' value being 'public' tells the template engine to use the public URL and not the ACP url. The real power of this feature lies in the return value being automatically fed via formatURL() which can return a friendly URL if friendly URLs are enabled. The Variable Tag: Example: <variable key="tdColor" oncondition="$foo == "green"" value="green" /> <variable key="tdColor" oncondition="$foo == "black"" value="black" /> <span style='color:<variable="tdColor" />'>Hello World!</span> <variable key="tdColor" default="blue" /> In this example, depending on $foo having a value of green: <span style='color:green'>Hello World!</span> This tag allows you to decide in the template itself how part of the template should display without having to edit PHP code. This is a handy tag for use in foreach blocks to alternate between colours when showing posts, topics, etc. Custom Tags The tags URL and date tags shown above use the {%tag="foo"|param="bar"%} format. These are actually custom plug-ins. You can write your own custom plug ins and they are available immediately within the templates. You could even modify the default plug-ins to change their behaviour. We're looking forward to how these new tools are used in your own templates!
  3. One of the biggest discussions we had during Invision Power Board 3.0's planning was whether or not to drop support for PHP 4 and require a minimum of PHP 5. The advantages of using only PHP 5 were numerous and we really felt like we could increase security and efficiency by taking advantage of the new PHP 5 features. This decision became much easier when we learned that PHP 4 was no longer being developed. To really see the benefit of using PHP 5, one must first consider how Invision Power Board's new framework is made possible by PHP 5. Although Invision Power Board 1 and 2 were loosely based on the 'front controller' design pattern, it had no real framework to hang the code on. The closest it had to one was the 'ipsclass' super-class. 'ipsclass' was a convenient method of transporting various classes and functions around Invision Power Board. Convenient, but not ideal. One had to pass this 'super-class' from class to class forcing PHP 4 to use a reference (and being severely punished when forgetting!). This super-class contained almost all the 'core' functionality of Invision Power Board. Member, input and database objects were attached along with numerous other classes and functions. None of which was ordered in any logical format. We have recoded Invision Power Board 3.0's framework from the ground up. We have done away with the 'ipsclass' super-class and employed the 'Controller -> Command -> View' pattern. This allows us to quickly add new code and to allow fast refactoring of our existing code. This pattern is built upon the 'IPS Registry'. This is a singleton class which maintains interfaces to several other registry objects (database, request, settings and member). Each of these objects maintains a clear place within the registry. This allows us to pass core data through the different levels of our pattern. Other functions from 'ipsclass' are moved into singtons: "IPSLib"; disparate functions that do not belong elsewhere, "IPSText"; functions for parsing and cleaning text, "IPSCookie"; functions to handle cookie management and "IPSMember"; functions that deal with loading, saving and parsing members. This offers a clear structure with clear boundries for each singleton class. Being singletons, you do not need to pass or reference the class in other files. Here's an example: IPB 2.3 Code $value = $this->ipsclass->settings['board_name']$id = $this->ipsclass->member['id'];$this->ipsclass->input['f'] = 2;print $this->ipsclass->get_cookie('foo');$text = $this->ipsclass->txt_alphanumerical_clean( $text );print $this->ipsclass->class_forums->build_info(); print $this->ipsclass->input['name']; IPB 3.0 Code $value = $this->settings->getSetting('board_name');$id = $this->member->getProperty('member_id');$this->request->setField( 'f', 2 );print IPSCookie::get('foo');$text = IPSText::alphanumerical_clean( $text );print $this->registry->getClass('class_forums')->build_info(); print $this->request->getField('name'); It's worth noting that we have also applied the ArrayAccess interface to the registry, so you may access them like so: $this->settings['board_name']; print $this->request['name']; Although the code examples use $this->request, $this->member, etc, these are set up in a constructor. You would pass the IPS Registry singleton into the class. Here's a typical constructor: { $this->registry = $registry; $this->member = $registry->member(); $this->request = $registry->request(); $this->settings = $registry->settings(); $this->DB = $registry->DB();} function __construct( ipsRegistry $registry ) You could also access the ipsRegistry class directly, although this is strongly discouraged: print ipsRegistry::instance()->request()->getField('name'); PHP 5 offers a much better OOP (object orientated programming) environment where references are assigned automatically. You can also chain along functions, which we make great use of. This allows us to do some neat trickery, like so: IPB 2.3 Code print $this->ipsclass->compiled_templates['skin_boards']->board_index( $data ); $this->ipsclass->load_template('skin_boards'); IPB 3.0 Code print $this->registry->getClass('output')->getTemplate('boards')->board_index($data); You'll note that you no longer have to implicitly load the template anymore. This is handled within the 'getTemplate' function if it's not already loaded. This object is then returned for use to chain onto 'board_index()'. This simple adjustment of code makes for less manual code and less room for error. We are also making great use of PHP 5 abstract classes and interfaces to define extensible classes. This will make it much easier and clearer for others writing their own additions to Invision Power Board. Having a clear interface to work with will reduce errors in development and formalize how you may access Invision Power Boards class structures. The 'controller -> command' structure is built so that you may add new modules and sections dynamically without the need to change a single line of code elsewhere in the script. Modification authors can just drop in new folders and Invision Power Board will run them when called correctly via a URL. The controller makes use of variables in a URL and safely loads a command file if a matching command file is located. For example: "appcomponent=core&module=global&section=login" is mapped to "applications/core/modules_public/global/login.php". We make use of the Reflection class functions to ensure that any potential command file is a sub-class of the controller to prevent the risk of tampering. We've barely scratched the surface, but it's clear that Invision Power Board 3's framework is very powerful and code-efficient. This is only made possible by the advancements in PHP 5 that we've taken full advantage of.
  4. A lot of the time a significant portion of development time is spent working on items that the end user will never get to see. A case in point is the attachments system. The attachments system was introduced back in the early days of IP.Board. During the development of IP.Board 2.2 the attachment system came under focus for two reasons. The first reason was that we were already testing the 'new' attachment system in IP.Dynamic (as shown in this movie) and we wanted to introduce that into IP.Board. The original system forced one to wait for an entire page reload before continuing with a post. The new version used a fancy concoction of javascript and iframes to upload data 'inline' - that is, without a page reload. Naturally, AJAX (XMLHttpRequest) would have been an obvious choice but it is impossible to upload data using current XMLHttpRequest methods. The second reason was that the code was due an overhaul because it was originally developed long before we had our components system in place. This made the original system inflexible and not very extensible. Infact, Remco had to maintain his own attachments system for the IP.Blog component which duplicated PHP code, HTML templates and SQL information. With this in mind, we abstracted the code into component friendly modules. This allowed one to simply create a new module to manage the component's settings and upload paths. The main attachment class handled the rest. This saved us a lot of code re-use and allowed us to store attachments from several components in one table. We think the new interface alone is a marked improvement over the old system. It's much quicker and allows one to upload several attachments quickly. We have plans to further abstract the attachments system in a later version of IP.Board to allow attachments to be saved and retrieved in different formats. This rather minor feature really highlights how new web technologies and ways of thinking can push even a secondary feature further along and how we're always looking to improve the efficiency of IP.Board and its components.
  5. Laurel resting is an activity that is banned at IPS and for good reason. While Brandon was busy working on the bug reports for IPB 2.2.0 back in the release candidate stages I managed to tick off another bunch of items from the IP.Dynamic to-do list. Here's a round-up of the latest features to be added. Staff Calendar We use an online calendar here at IPS to organize ourselves and to schedule meetings and other events and I thought that most other organizations would likely do the same, so it made perfect sense to add one into IP.Dynamic so that you can keep everything within one application. 4.5mb Quicktime Movie Task Manager Maintaining a website is a large and complex responsibility especially when shared with several other people. Some kind of task manager was a must to help keep staff on track and on schedule. 4.6mb Quicktime Movie Personal Topics This is like private messages, but better! The private message implementation found at IPB emulaltes the email system. You can PM one member and CC in others. The problem with that, like email, is that there is no real way to have a discussion with more than one person without a lot of copy and pasting. Enter Personal Topics. They behave in a similar manner to IPB topics with the topic starter becoming the moderator for the topic giving them the power to remove and block members from the topic. 6.4mb Quicktime Movie Content Versioning Every good CMS must be able to store versions of content and even more importantly roll back to them even when they've been deleted from the content repository. Unfortunately a lot of so-called CMS software doesn't have this functionality. Fortunately, IP.Dynamic isn't like most other CMS software! IP.Dynamic versions pages, system templates, content templates and content blocks. It's a modular system so one can write ones own modules to add versioning to any area of IP.Dynamic. 9.6mb Quicktime Movie.
  6. Matt

    IPSTheme

    Updating status to: Fixed
  7. Matt

    Chris59

    The code was always there, but it was a manual update. I've now run this through the converge class to take into account custom set ups and external databases.
×
×
  • Create New...