## Welcome #### Why Ultimix? Object-oriented and highly reusable code Event-driven programming Feature-rich Web components: HTML input controls, grids, trees, wizards, dialogs and meny others Powerfull AJAX API Rich documentation and strong userbase Exceptional performance Ultimix is licensed under the MIT/BSD license which makes it perfect for use in commercial applications Ultimix comes with a set of validators as well as numerous helper methods and widgets to simplify the task for form input and validation Built-in support of internationalization (I18N) and localization (L10N) Built-in enterprise modules user managemenet, authentification and authorization, content management, comments, reviews, blogs and others Wide range of supported databases - MySQL, Oracle, MSSQL, PostgreSQL. You can extend this class with your own classes. Separation of presentation and logic Configurable and pluggable modular architecture Caching modules and selective output caching Cross-site script (XSS) prevention Skinning and theming mechanism that allows you to quickly switch the outlook of a Ultimix-power website Simple and effective tools help identify and solve performance issues quickly Ultimix provides support for writing and running unit tests as well as functionality tests, campatible with PHPUnit #### Join the project! We want to invite you in this project. Any help of yours will be very useful. You can make this project better, and all community will be very grateful for this. If you want to join the project contact us using this email alexey (_at) dodonov(dot_)pro Thanks anyways ) #### Installation All versions of the Ultimix distributives can be found here Download distributive and install it in any directory on your server. Then install database support as described in this very simple manual. You can also download the latest sources from Git:
    	https://github.com/gdever/ultimix.git
SVN repository is also available:
    	https://ultimix.svn.sourceforge.net/svnroot/ultimix
#### First 'Hello world' application Page creation is very simple. You can use common html files or php scripts. These types of files are processed in a different way. But don't think about it now. Lets create our first html script (this code can be found in the 'hello_world_demo.html' file): Code:
    <html>
    	<head>
    		<title>Hello world!</title>
    	</head>

    	<body>
    		<?php

    			print( 'Hello world! Today is {date:value=now}' );

    		?>
    	</body>
    </html>
To run this script, copy it in the root directory of the Ultimix Framework and type http://localhost/ultimix/hello_world_demo.html Note that macro was processed. Second hello world demo can be found in the '/doc/demo/hello_world_demo.php' file. It is simple and obvious like all 'hello world' applications. Code:
    <?php

    	chdir( '../../' );

    	print( 'Hello world!' );

    ?>
All macroes will not be processed in the php scripts. To do this you need to run macro processing function manualy. The only reason these two script types are supported is to provide faster page generation. Obviously php script will work faster than html scripts, because you may deside on your own wich modules of the Ultimix Project will be used while page generation. The other difference of the html scripts is that you will be able to use framework without any programming skills! Just data-driven declaration! It is hard to belive but it is true! Try yourself. #### Modular architecture This demo can be found in the '/doc/demo/demo2.php' file. All ultimix code is organized into packages. You can load any of them without limitations and use them in your code. Code:
    <?php

    	chdir( '../../' );

    	/* include base functions wich allow you tu user the power of Ultimix ) */
    	require_once( 'include/php/startup.php' );

    	/* basic preparations */
    	start_php_script();

    	/* loading packages */
    	$Core = get_package( 'core' , 'last' , __FILE__ );

    ?>
As you can see above the function get_package provides access to the package. Each package has at least one class, and this function returns objects of this class. It works like a singleton creating object if it was not created yet, or returns created object. If the package class was not found, then false will be returned. The function get_package has three parameters. First one is the package's name. Second one is the package's version. You can instal different versions of the same packages and use them at the same time in your applications. If the word 'last' is set instead of version, then the lates version of the package will be returned. Each package's version contains three digits (the major version, the minor version, and the release version). You may explicitly get package with the exact version like shown below: Code:
    <?php

    	/* loading package 'core' with version 1.0.0 */
    	$String1 = get_package( 'string' , '1.0.0' , __FILE__ );
    	$String2 = get_package( 'string' , '1.0.0' , __FILE__ );
    	/* here $String1 and $String2 are references on the same objects */

    ?>
The meaning of the third parameter of the get_package function will be described in the next tutorials. If you want to get new object instead of instance of the already created object, you may use get_package_object function as shown below: Code:
    <?php

    	/* loading package 'core' with version 1.0.0 */
    	$String1 = get_package_object( 'string' , '1.0.0' , __FILE__ );
    	$String2 = get_package_object( 'string' , '1.0.0' , __FILE__ );
    	/* here $String1 and $String2 are not the same objects */

    ?>
#### Caching subsystem. Part 1 This demo can be found in the '/doc/demo/demo3.php' file. Ultimix has vast abilities for caching data. The package 'cache' is a basement for all of them. Cache can be switched on/off using config /packages/cache/conf/cf_cache. Where the setting 'cache_switch' swithces caching (values 'on'/'off'), and the setting 'timeout' sets cache cleaning timeout in seconds, it means that cache data will be removed from the storage when this timeout expires. Cached data is stored in the /packages/cache/data directory. Lets code! Code:
    <?php

    	/* loading package */
    	$Cache = get_package( 'cache' , '1.0.0' , __FILE__ );

    	/* This function call adds data to the cache */
    	$Cache->add_data( 'first_string' , 'String to be cached!' );

    	/* was the data cached? */
    	if( $Cache->data_exists( 'first_string' ) === true )
    	{
    		print( 'data was found in cache<br>' );
    	}

    	if( $Cache->data_exists( 'second_string' ) === false )
    	{
    		print( 'data was not found in cache<br>' );
    	}

    	print( $Cache->get_data( 'first_string' ).'<br>' );

    	/* update data */
    	$Cache->set_data( 'first_string' , 'Updated string' );

    	/* remove data from cache */
    	$Cache->delete_data( 'first_string' );
    ?>
Note that each stored record may be marked with a set of tags and then be deleted by one of these tags. All of this stuff is shown below: Code:
    <?php

    	/* loading package */
    	$Cache = get_package( 'cache' , '1.0.0' , __FILE__ );

    	/* This function call adds data to the cache */
    	$Cache->add_data(
    		'first_string' , 'String to be cached!' ,
    		array( 'tag1' , 'tag2' , 'tag3' )
    	);

    	/* remove data from cache */
    	$Cache->delete_data_by_tag( 'tag2' );
    ?>
#### Caching subsystem. Part 2 This demo can be found in the '/doc/demo/demo4.php' file. Caching subsystem is extended with the 'cached_fs' package wich provides access to the file system, such as file_get_contents, file_put_contents and file_exists. This package is based on the 'cache' package, that's why all settings from the /packages/cache/conf/cf_cache config affect it. Note that all calls of these functions are cached within the script execution session even if the caching is switched off. The abilities of this package are shown below: Code:
    <?php

    	/* loading package */
    	$CachedFS = get_package( 'cached_fs' , '1.0.0' , __FILE__ );

    	/* reading entire file */
    	$CachedFS->file_get_contentns( 'index.html' );

    	/* writing entire file */
    	$CachedFS->file_put_contentns( 'index.html' , 'Hello!' );

    	/* remove data from cache */
    	if( $Cache->file_exists( 'index.php' ) )
    	{
    		print( 'The file index.php exists!' );
    	}
    ?>
#### Caching subsystem. Part 3 This demo can be found in the '/doc/demo/demo5.php' file. The last element of the caching subsystem is the 'cached_multy_fs' package wich allows you to get files from differnet folders. You'll get access to the files from different folders as they were placed in the only one folder. The list of this folders is stored in the ./packages/cached_multy_fs/conf/cf_data_storage config (as you may notice all configs are placed in the /conf directory of the package). The default content is: Code:
    packages/_core_data/conf
    packages/_core_data/res/lang
    packages/gui/packages/context_set/res/templates
It means that if you will try to read file with name, for example, index.html. Then it will be searched in the packages/_core_data/conf directory, then the packages/_core_data/res/lang directory will be searched, and at last the packages/gui/packages/context_set/res/templates directory will be searched. You can add your own directories to this config to extend the default set. This class is widely used in the Ultimix, so you are recommended to use it to. It will allow other developers to override you package's templates, CSS or JS files, configs, etc. So if you will use the cached_multy_fs package, they may do it 'from the outside' without changing your package. It will make your code more reusable. Let's see the example below. Create directory './packages/dir1' and add this path to the cf_data_storage as shown in the next listing Code:
    packages/dir1
    packages/_core_data/conf
    packages/_core_data/res/lang
    packages/gui/packages/context_set/res/templates
Add file 'hello.html' with the string 'Hello base!' to the directory ./packages/dir1 Then the next code will output 'Hello base!' string Code:
    <?php

    	require_once( 'include/php/startup.php' );

    	start_php_script();

    	/* loading package */
    	$CachedMultyFS = get_package( 'cached_multy_fs' , '1.0.0' , __FILE__ );

    	/* reading entire file */
    	print( $CachedMultyFS->file_get_contentns( 'hello.html' ) );
    ?>
Now lets create directory './packages/dir2' and add this path to the cf_data_storage as shown in the next listing Code:
    packages/dir2
    packages/dir1
    packages/_core_data/conf
    packages/_core_data/res/lang
    packages/gui/packages/context_set/res/templates
Add file 'hello.html' (it has the same name) with the string 'Hello override!' to the directory ./packages/dir2 Then the next code will read our newly created file and output 'Hello override!' string. Note that scripts are the same. But data (configs and displaying files) are different. Code:
    <?php

    	require_once( 'include/php/startup.php' );

    	start_php_script();

    	/* loading package */
    	$CachedMultyFS = get_package( 'cached_multy_fs' , '1.0.0' , __FILE__ );

    	/* reading entire file */
    	print( $CachedMultyFS->file_get_contentns( 'hello.html' ) );
    ?>
As was said above, this class is widely used in the Ultimix, so you can override data of the base Ultimix packages in your projects. For example you may override the tempate of the registration form and add some fields of your own in it. Or you may override sign in form or anything else you want. #### Introduction to packages Package is the smallest unit in the Ultimix Framework. Each package is a set of php and javascript code, language files, templates, css files, images, configs and any other data. All packages have almost the same directory structure wich can be seen below:
    package_directory
    /
    |
    +---conf
    |
    +---data
    |   |
    |   +---page
    |   |
    |   +---permit
    |
    +---packages
    |   |
    |   +---core
    |       |
    |       +---data
    |
    +---res
    |   |
    |   +---css
    |   |
    |   +---images
    |   |
    |   +---lang
    |   |
    |   +---template
    |
    +---include
    |   |
    |   +---js
    |   |
    |   +---php
    |
    +---tmp
You certanly can use your own structure, but numerous features were adopted for the directory structure wich is listed above. #### Package creation steps 1. Go to the directory packages; 2. Create there the directory wich name is <package_directory> (for example - it is not necessary that names of the package and it's directory should match); 3. Open the file /packages/core/data/package_list and append a new string <package_name>;.<package_version>;#<package_directory> Code:
    package_name.1.0.0#package_directory
where 1.0.0 is the package's version. That's it! We have created our thirst package wwich may be accessed by calling get_package or get_package_object functions. Note that both of them will return false, because we have not created php script of the package yet. But you already may store resorces and configs in it. Now go to the directory /packages/<package_directory> and create file <package_name>.php wich contains class <package_name>_<package_version*>. Code:
    <?php
    class	package_name_1_0_0
    {
    	function	func()
    	{
    	}
    }
    ?>
Now we have a good full featured package. Let's use it! Code:
    <?php
    	require_once( 'include/php/startup.php' );

    	start_php_script();

    	$NewPackage = get_package( 'package_name' , 'last' , __FILE__ );

    	$NewPackage->func();
    ?>
#### Internationalization (I18N) and localization (L10N) As we said above each package may contain language files with translations of all used strings. As usual all these files are stored in the 'packages/package_directory/res/lang' directory. Each language file has its own extension wich depends on the language of the stored data. For examle language files with english data has extension 'en', language files with russian data has extension 'ru' etc. The language file name is equal to the package name. For example 'core.ru', 'lang.en', 'cached_multy_fs.jp' and so on. There are special language files wich are user through entire ultimix project. They are '/ultimix_directory/res/lang/lang.[language code, en/ru/fr/etc.]'. These files are always loaded. Each file consists of pairs 'key=localized value'. Wich can be shown in the next example: Now we have a good full featured package. Let's use it! Code:
    key1=First localized string
    key2=Second localized string
    key3=Third localized string
Now let's find out hou this data can be used in your code. It can be done using 'lang' package. Code:
    <?php
    	require_once( 'include/php/startup.php' );

    	start_php_script();

    	/* this code can be found in the 'demo6.php' file */
    	$Lang = get_package( 'lang' , 'last' , __FILE__ );

    	print( 'Hello from '.$Lang->get_string( 'ultimix' ) );
    ?>
#### Logging and tracing Ultimix provides API for tracing and logging. It can be found in the 'trace' package. To switch this API on you should set trace_x_y_z->StoreTrace variable to true. This package has a very simple API wich is described below: Code:
    <?php
    	require_once( 'include/php/startup.php' );

    	start_php_script();

    	/* this code can be found in the 'demo7.php' file */
    	$Trace = get_package( 'trace' , 'last' , __FILE__ );

    	/* these function calls output trace strings with different severity */
    	$Trace->add_trace_string( 'Some string' , 'ERROR' );
    	$Trace->add_trace_string( 'Some string' , 'NOTIFICATION' );
    	$Trace->add_trace_string( 'Some string' , 'COMMON' );
    	$Trace->add_trace_string( 'Some string' , 'QUERY' );

    	/* all trace strings can be groupped */
    	/* starting group with name 'Group 1' */
    	$Trace->start_group( 'Group 1' );

    	$Trace->add_trace_string( 'Groupped string 1' , 'COMMON' );
    	$Trace->add_trace_string( 'Groupped string 2' , 'COMMON' );

    	/* groups may be nested */
    	/* starting nested group with name 'Group 2' */
    	$Trace->start_group( 'Group 2' );

    	$Trace->add_trace_string( 'Groupped string 3' , 'COMMON' );

    	/* closing nested group with name 'Group 2' */
    	$Trace->end_group();

    	/* closing group with name 'Group 1' */
    	$Trace->end_group();

    	print( $Trace->compile_trace() );
    ?>
#### Creating templates Obviously all templates are packages itself. Note that html code of the template must be stored in the '/res/templates/template.tpl' file. #### Report generation Each report is described by records wich are stored in the umx_report table. You can use Report Manager in the Admin Console. Each record contains report's name, package name and version and function name wich are used to find report generation code. #### Built-in support of internationalization (I18N) and localization (L10N) Ultimix Framework supports internationalization (I18N) and localization (L10N) in a native way. Just look at the example: Code:
    <?php
    	require_once( 'include/php/startup.php' );

    	start_php_script();

    	/* this code can be found in the 'demo8.php' file */
    	$AutoMarkup = get_package( 'page::auto_markup' , 'last' , __FILE__ );

    	$Str = '{lang:main_page}';
    	$Str = $AutoMarkup->compile_string( $Str );

    	print( 'The macro {lang:main_page} will be replaced with "'.$Str.'" string' );
    ?>
You can use the macro {lang:string_alias} anywhere in the *.tpl files. Where string_alias is a string to be displayed according to he client's locale. #### Template engine Ultimix Framework has it's own template engine wich is powerfull and easy to understand. It can be accessed through 'page::auto_markup' package, like shown below: Code:
    <?php
    	require_once( 'include/php/startup.php' );

    	start_php_script();

    	/* this code can be found in the 'demo9.php' file */
    	$AutoMarkup = get_package( 'page::auto_markup' , 'last' , __FILE__ );

    	$Str = '{date:value=now}';
    	$Str = $AutoMarkup->compile_string( $Str );

    	print( 'The macro {date:value=now} will be replaced with "'.$Str.'" string' );
    ?>
All supported macro a stored in the ./packages/page/packages/auto_markup/conf/cf_macro_scripts config. See it for more information. #### Database support This framework supports wide range of database engines. For example MySQL, PostgreSQL, Oracle, MSSQL etc. You can work with the databases using adapter from package 'database'. The way you can do it is shown below: Code:
    <?php
    	require_once( 'include/php/startup.php' );

    	start_php_script();

    	/* this code can be found in the 'database_demo.php' file */
    	$Database = get_package( 'database' , 'last' , __FILE__ );

    	/* selecting all users */
    	$Result = $Database->query( 'SELECT * FROM umx_user' );

    	var_dump( $Database->fetch_results( $Result ) );

    	/* selecting all users in the other way */
    	var_dump( $Database->select( '*' , 'umx_user' ) );

    	/* selecting exact user in the other way */
    	var_dump( $Database->select( '*' , 'umx_user' , 'id = 1' ) );

    	/* inserting record */
    	$Database->insert(
    		'umx_user' , array( 'login' , 'password' ) ,
    		array( 'test_user' , 'test_pass' )
    	);
    	/* commit changes */
    	$Database->commit();

    	/* deleting record */
    	$Database->delete( 'umx_user' , 'id = 1234567' );
    	/* commit changes */
    	$Database->commit();

    	/* updating record */
    	$Database->insert(
    		'umx_user' , array( 'password' ) , array( 'new_pass' ) ,
    		'login LIKE "test_user"'
    	);
    	/* commit changes */
    	$Database->commit();
    ?>
#### Additional resources Forum (registration is not necessary) Ultimix-based projects can be found here #### Other projects Ra Testing Manager - it is a simple but effective way to manage your unit-tests. nitro++ framework - lightweight and extreamly fast c++ crossplatform framework. #### Contacts You can send feature requests, bug reports and questions on email dodonov_a_a@inbox.ru Author's blog
2011 © ultimix