Basic Application Development: Part Four

Supporting helpers, honoring user permissions, creating a package

An important thing to note about the color picker and other helpers: When you are a logged in user with an edit bar available, you will have many javascript libraries and css styleesheets loaded that users without edit bar access will have. This can be confusing during development, as you are often logged in as admin and have all these libraries available, they are easy to take for granted. Your non-edit-bar-having users, however, will not have such a smooth experience. In the case of the color picker, we will need to copy jquery.colorpicker.js into our root directory and add these three lines to our on_start method in our my_favorite_color single page controller: 

$html = Loader::helper('html');
$this->addHeaderItem($html->javascript('jquery.colorpicker.js')); 
$this->addHeaderItem($html->css('ccm.coorpicker.css));

Honoring permissions

This loads the HTML helper and loads these scripts and stylesheets in the header of our page, as well as places the color picker javascript in a location we can more easily get at it for inclusion. 

In our single page, we can wrap our File submit section of our code in a permissions check that checks a passed in variable to determine whether or not to show the file upload interface on the single page. 

if($canAddFilesToSet) { ?>
   File:<br/><?php echo $form->file('my_image'); ?>
   <br/><br/>
<?php } ?>

Let's head over to our on_start function and set this variable: 

Loader::model('file_set');
$fs = FileSet::getByName('Favorite Color Pics'); 
$fsp = new Permissions($fs);
print_r($fsp);

The print statement is just to test this out and display our results from this, we will change it later. Now we can remove Loader::model('file_set'); from our update_color function, as it is included in on_start (It's an important convention to keep your code short and clean to use DRY principles, or Don't Repeat Yourself). You'll see a big permissions object when you submit this. In the permissions object, there is a method called "canAddFilesToSet". So let's get rid of that print_r($fsp) and replace it with:

$this->set('canAddFilesToSet', $fsp->canAddFiles()); 

When we log in as a user who can't add files, we won't see that part of the single page, but if we log in with admin or some other user who has add file permissions, that part will show up. 

Now we can go into our controller to the update_color function and do the permissions check there to make sure any incoming post data we receive here is coming form a user who is allowed to upload files. We will do this by moving our definition of $fs more towards the beginning of update_color so that we can use it to wrap the import functionality in a permission check (remember, we removed Loader::model('file_set') because it's in on_start now): 

public function update_color() {
	if ($this->myUI instanceOf UserInfo) {
		Loader::library('file/importer');
		$fs = FileSet::getByName('Favorite Color Pics');
		$fsp = newPermissions($fs);
		if ($fsp->canAddFiles()) {
			$fi = newFileImporter();
			$pathToFile = $_FILES['my_image']['tmp_name'];
			$nameOfFile = $_FILES['my_image']['name];
			$myFileObject = $fi->import($pathToFile, $nameOfFile);
			if (is_object($myFileObject)) {
				$fs->addFileToSet($myFileObject); 
			}
			$this->myUI->setAttribute('favorite_color_picture', $myFileObject);
		}
		$this->myUI->setAttribute('favorite_color', $this->post('color'));
	}
	$this->redirect('/my_favorite_color');
}

Now when you upload as a user with upload access, it will be included in the file manager. 

Form elements do attempt to sanitize their data. There is no sanitizing  used at the view or controller level, but there is some sanitizing done in the form helper (You can view what is done in the former helper file, under the function processRequestValue). You will want to sanitize data yourself when it's coming out of the database, though ideally it shouldn't have gone in unsanitized in the first place. 

Regarding permissions, all permissions are combined per user. So their various group permissions will be combined with their individual user permissions to create their total permissions signature. As of 5.6.0.2 advanced permissions, you can now issue permissions denials, and denials override allowances. 

Packages

This is covered a little more in depth in the Advanced Application Development trainings. A package's directory looks kind of like a mini concrete5 file system. Using the Example FAQ package in the marketplace as our example, you can see that it has a blocks directory with a template in it for the page list block, a controller, a single page, and then the package controller itself. 

Package controllers are a class. To create a package class, you camel case your package name and append it with "Package" and make it extend Package, like so:

class ExampleFaqPackage extends Package 

There are some required variables to include here: 

protected $pkgHandle = 'example_faq';
protected $appVersionRequired = '5.4.0';
protected $pkgVersion = '1.0';

Respectively, this is the package handle that is the short name of the package, the minimum version of concrete5 that is required, and the package version itself.  

Thereafter, there is a function for getting the package description and package name: 

public function getPackageDesription() {
	return t('Adds a simple FAQ system to a website. Used in the Example FAQ Single Page How-To');
}

public function getPackageName() {
	return t('Example FAQ');
}

Packages controllers can also have an install function, though it isn't required. Here is the example from the Example FAQ controller: 

public function install() {
       $pkg = parent::install();
       Loader::model('single_page');
       Loader::model('attribute/categories/collection');

        // install attributes
        $cab1 = CollectionAttributeKey::add('BOOLEAN',array('akHandle' => 'faq_section', 'akName' => t('FAQ Section'), 'akIsSearchable' => true), $pkg);
         $cab2 = CollectionAttributeKey::add('SELECT',array('akHandle' => 'faq_tags', 'akName' => t('FAQ Tags'), 'akSelectAllowMultipleValues' => true, 'akSelectAllowOtherValues' => true, 'akIsSearchable' => true), $pkg);

        $def = SinglePage::add('/dashboard/example_faq', $pkg);
        $def->update(array('cName'=>'FAQ Entries', 'cDescription'=>'Frequently asked questions.'));
}

So this is installing a few different collection attributes, and installing a single page programmatically. When we install single pages, controllers, etc, from a package, we have to include the package object in the install method. This let's concrete5 know to look in the package's directory for these files, not in the concrete5 single pages location. Now let's install the package. When it installs, you'll see that it adds single pages to the dashboard. This is how you make a dashboard page, you simply install it underneath the dashboard in the site map and you will have the dashboard theme applied to it. There is also a pretty exhaustive how-to to creating a single page powered editing interface in c5. Example FAQ's functionality is probably better accomplished via composer, but it was architected prior to composer's creation. 

Check out the applications category in the concrete5 marketplace for some applications to analyze and learn from! 


Recent Discussions on this Topic

Date picker not working in my web application

Hi I am working in the web application development using concrete5.6.1.2 the application is work when the concrete logged in the admin. for ex: i am using core concrete files in my application are [code][/code] [code][/code] but after sign out…

seperate login...

I am new to concrete5. How to set separate login for my application. concrete5 already gives the login page. But i want to use it as site editing admin. I need a another login to my application. If the application is open the home page should open af…

How to set my custom login page as startup page?

I'm creating an application using concrete5. I'm beginner of concrete5. So, how to set the login page to my application. I want to use concrete5's core login page as site editing login. If an end user open my application, at first it should show m…

Application Flow

hi, i just read the page about the application flow (http://www.concrete5.org/documentation/introduction/the-dispatcher-understanding-the-concrete-applic/). I am actually developping (or trying to do it !) a web app integrated with C5. My applicatio…