public function save() {

		if(null === $this -> getAdapter()) {
			return trigger_error('Adapter is not set. Set the adapter with the setAdapter() method', E_USER_ERROR);
		}

		//Execute user defined before save function
		$this -> beforeSave();

		$class   = new \ReflectionClass(get_class($this));
		$values  = $this -> toArray();
		$columns = [];

		array_walk($values, function($a, $b) use (&$columns, &$values) { 

			if(true === in_array($b, $this -> exclude)) {
				
				unset($values[$b]);
				return;
			}

			if($a instanceof DateTime) {
				$values[$b] = $a -> loadFormat();
			}

			if(true === is_array($a)) {
				$values[$b] = json_encode($a);
			}

			$columns[] = sprintf('`%s` = VALUES(`%s`)', $this -> getAdapter() -> escape($b), $this -> getAdapter() -> escape($b));
		});

		//Convert column names to column names with backtics
		foreach($values as $column => $value) {
			
			$values['`' . $column . '`'] = $value;
			unset($values[$column]);
		}

		$query = sprintf('INSERT INTO %s (%s) VALUES(%s) ON DUPLICATE KEY UPDATE %s', $this -> getAdapter() -> escape($this -> getTable()), implode(array_keys($values), ', '), implode(array_fill(0, count($values), '?'), ','), implode($columns, ', '));

		$this -> getAdapter() -> query($query, array_values($values));

		$success = $this -> getAdapter() -> execute();
		
		//Set new id if last id is not null
		$id  		= $this -> getAdapter() -> getLastId();
		$ids 		= $this -> getIdentifier();
		$affected 	= $this -> getAdapter() -> getAffected();

		if(count($ids) > 0 && $affected > 0) {

			$method = sprintf('set%s', NameConvert :: toCamelcase($ids[0], true));

			if(true === method_exists($this, $method)) {
				call_user_func_array([$this, $method], [$id]);
			}
		}

		//Execute user defined after save function
		$this -> afterSave();

		return $success;
	}