Our Application, as simple as it may be functionality wise, is designed to be available for any number of freelancers, agencies or companies to utilise. In order to manage this, we need an effective way of creating Companies in our App, and separating their data using namespacing in our Datastore. In this article, we will create the ability to add, edit and remove companies from our App and also look at how we can assign Users to a Company on signup, and after the Company has been created.

To begin, we need a Company Entity type, as well a CompanyStore.

<?PHP	// models/companystore.class.php

class CompanyStore extends CacheStore {
	
	private $Company;
	
	public function buildSchema(){
		$Schema = new GDSSchema('Company');
		$Schema->addString('CompanyName', true);
		$Schema->addBoolean('Active', true);
		return $Schema;
	}
	
	public function __construct($Gateway, $Cache){
		parent::__construct($this->buildSchema(), $Gateway, $Cache);
		$this->setEntityClass('Company');
	}
	
?>
<?PHP	// models/company.class.php

class Company extends GDSEntity {
	
}	

?>

To start with, we do not need much information about our Company entities. The information we choose to gather about Companies will evolve as the App evolves, however at this stage, we simply need a Company name and the ability to check that the Company is Active.

We can build on our CompanyStore by generating and processing an add/update form.

<?PHP	// models/companystore.class.php -- additions only --
	
	public function processUpdateForm(){
		if(!isset($_POST['CompanyKey'])){
			$this->Company = new Company();
		} else{
			$this->Company = $this->fetchById($_POST['CompanyKey']);
			if(!$this->Company){
				throw new CompanyException('Trying to process company update form, but the CompanyKey provided returned no valid company');
			}
		}
		
		$this->Company->CompanyName = $_POST['CompanyName'];
		$this->Company->Active = (bool) $_POST['Active'];
		
		$this->upsert($this->Company);

		$_POST['CompanyKey'] = $this->Company->getKeyId();

		$this->getUpdateForm(false);
		
		$this->UpdateForm->add_error('error', 'The company '.$this->Company->CompanyName.' has been updated.');
		return $this->UpdateForm;
			
	}
	
	public function getUpdateForm($New = false){
		$Form = new AppForm('UpdateCompany');
		
		$UCompanyName = '';
		$UActive = true;
		
		if(!$New){
			if(isset($_POST['CompanyKey'])){
				$this->Company = $this->fetchById($_POST['CompanyKey']);
				$UCompanyName = $this->Company->CompanyName;
				$UActive = $this->Company->Active;
			} else{
				throw new CompanyException('Trying to generate update form, but $_POST[CompanyKey] not set');
			}
		}
		
		$Form->add('label','labelCompanyName','CompanyName','Company Name: ');
		$CompanyName = $Form->add('text','CompanyName', $UCompanyName);
		$CompanyName->set_rule(array(
			'required' => array('error','A Company name is Required'),
		));
		
		$Form->add('label','labelActive','Active','Active: ');
		$ActiveAttributes = '';
		if($UActive or $New){
			$ActiveAttributes = array('checked' => 'checked');
		}
		$Active = $Form->add('checkbox','Active',true,$ActiveAttributes);
		
		if(isset($this->Company)){
			$Form->add('hidden','CompanyKey',$this->Company->getKeyId());
		}
		
		$Form->add('submit','btnSubmit','Save Page');
		
		$this->UpdateForm = $Form;
		return $Form;
	}
?>

The getUpdateForm(), and processUpdateForm() methods we have used here are very similar to the ones we have been using previously, having been updated to store the information relevant to Companies in our App. We can now add a Companies Controller, and an AddCompanyView to allow us to render our form to the user.

<?PHP	// views/addcompanyview.class.php

class AddCompanyView extends View{
	
	private $Form;
	private $Content;
	
	public function __construct(){
		$this->setContent();
	}
	
	public function setForm($Form){
		$this->Form = $Form;
	}
	
	public function render(){
		echo $this->Content;
		if($this->Form->validate()){
			$this->Form = $this->Model->processUpdateForm();
		}
		$this->Form->render('*horizontal');		
	}
	
	public function setContent(){
		$Content = '<h1>Add a New Company</h1>';
		$Content .= '<p>Use this form to add a new company.';
		$this->Content = $Content;
	}
	
	
}
	
?>
<?PHP	// controllers/companies.class.php

class Companies extends Controller{
	
	public function __construct(){
		$this->Model(App::newCompanyStore());
	}
	
	private function getUpdateForm($New = false){
		$UpdateForm = $this->Model->getUpdateForm($New);
		return $UpdateForm;
	}
	
	public function add(){
		$this->View(App::newAddCompanyView());
		$this->View->Model($this->Model);
		$this->View->setForm($this->getUpdateForm(true));
		$this->View->render();
	}
?>
	

So far, everything in this article is very similar to the way we have been gathering data from users and storing it in our Datastore. When we think about the Company signup process however, a User will be creating a Company and an administrator User at the same time. How can we manage this with our current setup? We currently have 2 completely separate forms rendered in different views, by different controllers. What I want is a simple one page signup form that allows Users to get to work as quickly and painlessly as possible.

To achieve this, we will make a few changes to the way we generate our User UpdateForm, and our Company UpdateForm. Essentially, I want to separate the items that are common to our signup form and our update form, from those that are required only by the update form. I have done this below for our CompanyStore class to explain further.

<?PHP	// models/companystore.class.php -- updates only --
	
	public function getCommonAddFields($Form, $New = true){
		$UCompanyName = '';
		
		if(!$New){
			if(isset($_POST['CompanyKey'])){
				$this->Company = $this->fetchById($_POST['CompanyKey']);
				$UCompanyName = $this->Company->CompanyName;
				$UActive = $this->Company->Active;
			} else{
				throw new CompanyException('Trying to generate common fields, but $_POST[CompanyKey] not set');
			}
		}
		
		$Form->add('label','labelCompanyName','CompanyName','Company Name: ');
		$CompanyName = $Form->add('text','CompanyName', $UCompanyName);
		$CompanyName->set_rule(array(
			'required' => array('error','A Company name is Required'),
		));
		
				
		if(isset($this->Company)){
			$Form->add('hidden','CompanyKey',$this->Company->getKeyId());
		}
		
		return $Form;
	}
	
	public function getUpdateForm($New = false){
		$Form = new AppForm('UpdateCompany');
		
		$Form = $this->getCommonAddFields($Form, $New);
		
		$UActive = true;
		
		if(!$New){
			if(isset($_POST['CompanyKey'])){
				$this->Company = $this->fetchById($_POST['CompanyKey']);
				$UActive = $this->Company->Active;
			} else{
				throw new CompanyException('Trying to generate update form, but $_POST[CompanyKey] not set');
			}
		}
		
		$Form->add('label','labelActive','Active','Active: ');
		$ActiveAttributes = '';
		if($UActive or $New){
			$ActiveAttributes = array('checked' => 'checked');
		}
		$Active = $Form->add('checkbox','Active',true,$ActiveAttributes);

				
		$Form->add('submit','btnSubmit','Save Page');
		
		$this->UpdateForm = $Form;
		return $Form;
	}
?>

In the code snippet above, I have split our getUpdateForm() method into two methods getUpdateForm() and getCommonAddFields(). The getCommonAddFields() method will add fields to the form for all of the items common to both the signup form and to the Company Add/Update form. In this case, we have simply put the CompanyName field in our addCommonFields() method. You will notice we do not create a new form, nor do we add a submit button at the end of the form. We will call this method, and provide our existing form, for the fields to be added to the form, and then return the updated form to the caller of the method.

In our getUpdateForm() method, you will see we now create a new form, then provide the form to our addCommonAddFields() method. We then add the fields that we want in a full Company profile. In this case, we have just added an active checkbox. We will automatically set the Company to active when we process the signup form. We also add a submit button to the end of the form.

We can now do the same with our UserStore’s getUpdateForm() method.

<?PHP	// models/userstore.class.php -- updates only --
	
	public function getCommonAddFields($Form, $New = true){
		$Form->add('label', 'labelUsername', 'Username', 'Username: ');
		if($New){
			$Username = $Form->add('text', 'Username');
			$Username->set_rule(array(
				'required' => array('error','Username is required!'),
			));
		} else{
			if(isset($_POST['UserKey'])){
				$this->User = $this->fetchById($_POST['UserKey']);
				if(!$this->User){
					throw new UserException('Trying to update a user, but the UserKey provided returned no valid user');					
				} else{
					$Username = $Form->add('text','Username', $this->User->Username, array('disabled' => 'disabled'));
				}

			} else{
				throw new UserException('Trying to update a user, but no UserKey has been supplied. $_POST[UserKey] not set.');
			}
		}
		
		if($New){
			$Form->add('label', 'labelPassword','Password','Password: ');
			$Password = $Form->add('password','Password');
			$Password->set_rule(array(
				'required' => array('error','Password is required!'),
				'length' => array(8,0,'error','Password must be at least 8 characters long.'),
			));
			
			$Form->add('label','labelConfirmPassword','ConfirmPassword','Confirm Password: ');
			$ConfirmPassword = $Form->add('password','ConfirmPassword');
			$ConfirmPassword->set_rule(array(
				'compare' => array('Password','error','Passwords do not match!'),
			));
		}
		
		$UName = '';
		$USurname = '';
		$UEmail = '';
		
		if(isset($this->User)){
			$UName = $this->User->Name;
			$USurname = $this->User->Surname;
			$UEmail = $this->User->Email;
		}
		
		$Form->add('label','labelName','Name','Name: ');
		$Name = $Form->add('text','Name', $UName);
		$Name->set_rule(array(
			'required' => array('error','Your name is required.'),
		));
		
		$Form->add('label','labelSurname','Surname','Surname: ');
		$Surname = $Form->add('text','Surname', $USurname);
		$Surname->set_rule(array(
			'required' => array('error','Your surname is required.'),
		));
		
		$Form->add('label','labelEmail','Email','Email: ');
		$Email = $Form->add('text','Email', $UEmail);
		$Email->set_rule(array(
			'required' => array('error','Your email is required.'),
			'email' => array('error','Your email address is not valid'),
		));
		
		if(isset($this->User)){
			$Form->add('hidden','UserKey', $this->User->getKeyId());
		}
		
		return $Form;

	}
	
	public function getUpdateForm($New = false){
		$Form = new AppForm('EditUser');
		
		$Form = $this->getCommonAddFields($Form, $New);
				
		$Form->add('submit','btnSubmit','Save User');
		
		$this->UpdateForm = $Form;
		return $Form;
	}

In the User getCommonAddFields() method, we have included all of the fields we currently have set up for Users. We will need all of this information for each User. Later, as our App evolves, we may wish to store more information about our Users, and generate profile pages for them. We can add any additional fields to the getUpdateForm() method, without affecting our signup form.

Now that we have access to the fields we need for our signup form, we can create a SignupModel, which will handle our signup form data interactions.

<?PHP	// models/signupmodel.class.php

class SignupModel {
	
	private $CompanyStore;
	private $UserStore;
	
	public function __construct($CompanyStore, $UserStore){
		$this->CompanyStore = $CompanyStore;
		$this->UserStore = $UserStore;
	}
	
	public function getSignupForm(){
		$Form = new AppForm('SignupForm');
		
		//Company Signup Items
		$Form = $this->CompanyStore->getCommonAddFields($Form, true);
		
		//User Signup Items
		$Form = $this->UserStore->getCommonAddFields($Form, true);
		
		$Form->add('submit','btnSubmit','Save Details');
		
		return $Form;
	}
	
	public function processSignupForm(){
		$this->CompanyStore->processUpdateForm();
		$this->UserStore->processUpdateForm();
		return $this->getSignupForm();
	}
	
}	
	
?>

Our SignupModel accepts 2 objects, a CompanyStore and a UserStore, which are used to communicate with our Datastore. We have also set up a getSignupForm() method which creates a new form to hold our signup form, and then uses our new getCommonAddFields methods to gather all of the fields we need for our signup form. We then add a submit button, and return the form.

To process our signup form, we can use the CompanyStore and UserStore’s processUpdateForm() methods to save our Company and User information. We can now add a Signup Controller and SignupView View to render and handle our new form.

<?PHP	// controllers/signup.class.php
	
class Signup extends Controller{
	
	public static $Internal = false;
	
	public function __construct(){
		$this->Model(App::newSignupModel());
	}
	
	public function index($Params){
		$this->View(App::newSignupView());
		$this->View->Model($this->Model);
		$this->View->setForm($this->Model->getSignupForm());
		$this->View->render();
	}
	
	
}
	
?>
<?PHP	// views/signupview.class.php

class SignupView extends View{
	
	private $Form;
	private $Content;
	
	public function __construct(){
		$this->setContent();
	}
	
	public function setForm($Form){
		$this->Form = $Form;
	}
	
	public function render(){
		echo $this->Content;
		if($this->Form->validate()){
			$_POST['Active'] = true;
			$this->Form = $this->Model->processSignupForm();
		}
		$this->Form->render('*horizontal');		
	}
	
	public function setContent(){
		$Content = '<h1>Welcome</h1>';
		$Content .= '<p>Please tell us a little about yourself.';
		$this->Content = $Content;
	}
	
	
}
	
?>

We have set our Signup Controller’s $Internal property to false, this allows the signup form to be accessed without the user having to log in. If we ensure all dependencies have been added to our container.class.php file, and run composer dump, we should be able to run our new signup form.

This form now works, and creates a Company for us using the CompanyName field, and also creates a User from the provided information. We need to now use the new Company to set the CurrentCompany field in our User. This will link the User to the Company.

<?PHP	// models/userstore.class.php -- updates only --
	
	public function processUpdateForm(){
		if(!isset($_POST['UserKey'])){
			$this->User = new User();
			$this->User->Username = $_POST['Username'];
			$this->User->Password = $this->generatePassword($_POST['Password']);
		} else{
			$this->User = $this->fetchById($_POST['UserKey']);
			if(!$this->User){
				throw new UserException('Trying to process user update form, but the UserKey provided returned no valid user');
			}
		}
		
		$this->User->Name = $_POST['Name'];
		$this->User->Surname = $_POST['Surname'];
		$this->User->Email = $_POST['Email'];
		
		if(isset($_POST['CompanyKey'])){
			$this->setCurrentCompany($_POST['CompanyKey']);
		}
		$this->User->Active = true;
		
		$this->upsert($this->User);
		
		$_POST['UserKey'] = $this->User->getKeyId();
		
		$this->getUpdateForm(false);
		
		$this->UpdateForm->add_error('error', 'The user '.$this->User->Username.' has been updated.');
		return $this->UpdateForm;
			
	}
	
?>

The only change we have made here, is that we have removed a line that set $this->User->CurrentCompany = ‘Example Company’ and changed it to test if a $_POST[‘CompanyKey’] had been set, and if so, set the CurrentCompany to the posted value. This value is already set in our processUpdateForm in our CompanyStore class, so if our Company is added successfully, our User will be correctly assigned to the Company.

Now that we are able to add handle signups, and can assign our User to a Company, we can use this information in the next few articles to improve on our security. In the next article, we will start developing a user permissions system to manage access to each page in our application.