Basic Application Development: Part Two

Part two: Tasks, setting user attributes, controller structure

Now that we have our single page view and controller in place, we can start doing some fancy controller work. In our newsroom list, we are going to create an add link, so that when we click the link, we show something else on our single page. First, we will add some logic to our single page. 

<?php if  ($this->controller->getTask() == 'add') { ?>

Form Inputs go here

<?php } else { ?>

Newsroom List. 
<br/><br/>
<a href="<?php echo $this->url('/newsroom', 'add')?>">Add</a>

<?php } ?>

This is checking to see if we are within the controller add method. If we are, we get the "Form Inputs go here" in the view. Otherwise, we get the content beginning with "Newsroom List." So in essence, when clicking the add link, we get the form, otherwise we get the default contents. 

Now we will create a form: 

<form method="post" action="<?php echo $this->action('save')?>">
	<input type="text" name="name" value="" />
	<input type="submit" value="Submit" />
</form>

This form uses an "action" for the form action. This is similar to the url method, only it assumes that you are posting back to the same page. When we submit this, we will get a page not found because we have not defined a save function yet in the single page controller. Here's what it will look like: 

public function save() {
   $name = $this->post('name'); 
   print $name;
   exit;
}

Now when we type in a name and click submit you will see the name and exit, so you'll just see the name on a white screen. Also, keep in mind we use the concrete5 post method instead of accessing the PHP $_POST array. This is generally a better way to go within your controllers, just to make sure the name is consistent. 

 

Case study: Setting user favorite color attribute

Now for a different example. Let's add a single page and controller called "My Favorite Color." (For the process, check out part one of this series). We will be using a custom attribute for users to store the favorite color. In order to do that, go to users/attributes and let's create a text attribute. We will give it a handle "favorite_color". The handle is important to remember as we will refer to it later in the code. "Name" is what it will look like in the site. Now click add. We could change this via the user ui in the backend, but we're going to do this through our single page instead. 

Now let's create a form on our single page to receive the new preferred color: 

<form method="post" action="<?php echo $this->action('update_color')?>">
	<input type="text" name="color" value="" />
	<input type="submit" value="Save" />
</form>

Now when we submit this form, we will again get a 404 page not found because we haven't created a update_color function in our controller. So let's create that now.

public function view() {
	$u = new User();
	if ($u->isRegistered()) {
		$ui = UserInfo::getByID($u->getUserID());
		$color = $ui->getUserFavoriteColor();
		$this->set('favoriteColor', $color); 
	}
} 

The user info object is much more robust than the simple user object, and it gets us the user's attribute as well, so that's why we are getting that object from the current user object. Additionally, using getUserFavoriteColor isn't actually a concrete5 method. There is a magic method in the user info object that, if it doesn't recognize the method that starts with "getUser", it will look at the text after that and it will lower case that, and any sort of camel casing it finds, it will put an underscore next to it. So this would turn into "favorite_color".  If it finds an attribute that string pertains to, it will return that attribute value. 

Now we will change the value of our form in the view to the value of the $favoriteColor variable like so: 

<form method="post" action="<?php echo $this->action('update_color')?>">
	<input type="text" name="color" value="<?php echo $favoriteColor; ?>" />
	<input type="submit" value="Save" />
</form>

Now the favorite color associated with the user will show up. But when you hit save, the value doesn't come through. That's because it's only passing in this variable to the view function.  You could just call the view function at the end of our update_color function, but what if there were methods in the view function that you didn't want to run during update color, but you still wanted this variable to be passed in when the page is either first accessed (view function) or accessed via a method (update_color function) ? Then you would want to make use of the on_start method. 

 

Creating an on_start function

public_function on_start() {
	$u = new User();
	if ($u->isRegistered()) {
		$ui = UserInfo::getByID($u->getUserID());
		$color = $ui->getUserFavoriteColor();
		$this->set('favoriteColor', $color); 
	}
} 

This is somewhat similar to the __construct method in Object Oriented PHP.  However, don't use the construct method in your controllers, use on_start. on_start will run prior to both view and update_color. Now we could go through and parse the $_POST[] array in our controller and try setting that data for when the form is viewed, but this can become cumbersome, particularly when we have many form items we are parsing. We should use the form helper, and use the on_start method to load it up so we can access it in our various controller methods like so: 

public_function on_start() {
	$u = new User();
	if ($u->isRegistered()) {
		$ui = UserInfo::getByID($u->getUserID());
		$color = $ui->getUserFavoriteColor();
		$this->set('favoriteColor', $color); 
	}
	$form = Loader::helper('form');
	$this->set('form', $form);
} 

Now the $form variable will be set in our view. Back in our view, where our form is, we can change it to include the form helper: 

<form method="post" action="<?php echo $this->action('update_color')?>">
	<?php echo $form->text('color', $favoriteColor)?>
	<input type="submit" value="Save" />
</form>

The first parameter of the text method is the input's name, and the second parameter is an optional default value for the input. You can also use one for submit: 

<form method="post" action="<?php echo $this->action('update_color');?>">
	<?php echo $form->text('color', $favoriteColor);?>
	<?php echo $form->submit('submit', 'Save');?>
</form>

There currently isn't a way to organize the view into separate files by task. Generally you create single pages, though you are required to have separate views and separate controllers. You could set up a base controller and extend that controller if you wanted that sort of functionality. 

 

Saving the user attribute value

Now let's make the update_color method save the attribute value. Instead of just copying all the code to get the current user info object that we did in the on_start function, since on_start is running before update_color, we can just set a protected variable in the controller so we can access that value like so (Here is also a bird's eye view of our controller as it will look at this point with this included):

<?php 

class MyFavoriteColorController extends Controller {

	protected $myUI; 

	public_function on_start() {
		$u = new User();
		if ($u->isRegistered()) {
			$ui = UserInfo::getByID($u->getUserID());
			$this->myUI = $ui;
			$color = $ui->getUserFavoriteColor();
			$this->set('favoriteColor', $color); 
		}
		$form = Loader::helper('form');
		$this-set('form', $form);
	} 

	public function view() {

	}

	public function update_color() {
		if ($this->myUI instance of UserInfo) {
			print_r($this->myUI);	
			exit;
		}
	}
}

You can see at the top of the controller we are now declaring a protected variable of $myUI, and we are setting that variable's value in the on_start function with $this->myUI = $ui. When you hit submit in the view, you will now see the printed output of the current user info object. Now let's change that so it actually saves the attribute against the current user. 

public function update_color() {
	if ($this->myUI instanceof UserInfo) {
		$this->myUI->setAttribute('favorite_color', $this->post('color'));
	}
	$this->redirect('/my_favorite_color');
}

So we are invoking the setAttribute member function for the UserInfo objet contained in the protected variable $myUI, which takes two parameters: The attribute handle, and the value to be inserted. After we're finished, we are redirecting back to the my_favorite_color single page. Now, we can see that we are updating the user's favorite color attribute. We can check that by searching for the user and viewing their properties. 

 

Giving the user feedback

Now let's give the user some feedback regarding whether or not the update worked. In our redirect method, we can also supply a second parameter of a function to be run. So let's change that to include a method called "color_updated": 

$this->redirect('/my_favorite_color', 'color_updated'); 

And let's create the method for color_updated():

public function color_updated() {
	$this->set('message', 'Color saved successfully.');
}

Now in our view, we can check to see if $messages exists and echo it out if so: 

<?php if (isset($message)) { ?>
	<b><?php echo $message ;?></b>
	<br/></br/>
<?php } ?>

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…