Johan Broddfelt

Edit on the fly

No we are going to do some real magic. Let's build an edit form that work regardless of which table we are working on. Start by creating a edit.php in /views/generic/.

fetchFields();
    $colCount = count($fields);
    if (filter_input(INPUT_POST, 'save', FILTER_SANITIZE_URL) != '') {
        foreach ($fields as $f) {
            $name = $f->varName;
            if ($t->columnName == 'id') {
                // do nothing;
            } else {
                $obj->$name = filter_input(INPUT_POST, $f->columnName);
            }
        }
        $obj->update();
        ?>
        
Changes are saved

id == 0) { ?> New Edit realClassName(); ?>

Back
varName; ?>
columnName, $matches)) { $columnArr = explode('-', $t->columnName); echo Db::realClassName(str_replace('_id', '', $columnArr[0])); } else { echo Db::realClassName($t->columnName); } ?> columnName == 'id') { ?> $name; ?> columnName, $matches)) { $columnArr = explode('-', $t->columnName); if (count($columnArr) < 2) { $columnArr[1] = $t->columnName; } $table = preg_replace("/_id$/", '', $columnArr[1]); $objClassName = preg_replace('/s/', '', '' . $obj->className($table)); //print $table.' : '.$objClassName; $sc = new $objClassName(); $scFields = $sc->fetchFields(); $scs = $sc->fetchArray(' ORDER BY `' . $scFields[1]->columnName . '`, `id`'); ?> realType == 'text') { ?> columnType == 'chk') { ?> type="checkbox" value="1" $name) { ?> checked="checked" realType == 'datetime' or $t->realType == 'timestamp') and $obj->$name == '') { $obj->$name = date('Y-m-d H:i:s'); } ?> type="text" value="$name; ?>" name="columnName; ?>" realType == 'date') { ?> class="datepicker" >

One of the most important parts of this code is the segment where we take care of the different types of database values and displays them in different kinds of input form fields. For instance columnType "chk" that is the type of all columns starting with "is_". This means that if you name a column is_active, then that will automatically generate a checkbox in the input form. The same for columns of type date. Her we will also add a datepicker later, that will apear automatically for all date fields. And if the column name ends with "_id" then the script will try to find a class with the name of this id and get a list of items from this class table. In order to generate items for the select list. This is a really neat feature.

In this code there is one function we have not yet implemented. The $obj->update(). This function will create a new post (INSERT) if the id is zero, otherwise it will (UPDATE) the post with the same id in the database. Let's create this function in Db.php.

    function update() {
        $fields = $this->fetchFields();
        foreach ($fields as $field) {
            $columnName[] = $field->columnName;
            $fieldName    = $this->strToCamel($field->columnName);
            $data[]       = $this->handleDataIn($field->columnName, $field->columnType, $this->$fieldName);
        }
        $indexId = 0;
        $i = 0;
        if ($this->id == 0) {
            $sql = 'INSERT INTO `' . $this->table . '` (';
            foreach ($columnName as $sItem) {
                if ($sItem != 'id') {
                    $sql .= '`' . $sItem . '`, ';
                } else {
                    $indexId = $i;
                }
                $i++;
            }
            $sql = trim($sql, ', ');
            $sql .= ') VALUES (';
            $i = 0;
            foreach ($data as $sItem) {
                if ($indexId != $i) {
                    $sql .= "'" . $sItem . "', ";
                }
                $i++;
            }
            $sql = trim($sql, ', ');
            $sql .= ')';
            Db::query($sql);
            $this->id = Db::insert_id();
        } else {
            $sql = 'UPDATE `' . $this->table . '` SET ';
            $found = true;
            $indexId = 0;
            $i = 0;
            while ($found) {
                if ($columnName[$i] != 'id') {
                    $sql .= "`" . $columnName[$i] . "`='" . $data[$i] . "', ";
                } else {
                    $indexId = $i;
                }
                if (is_null($columnName[($i+1)])) {
                    $found = false;
                }
                ++$i;
            }
            $sql = trim($sql, ", ");
            $sql .= " WHERE id  = " . (int)$data[$indexId] . "";
            Db::query($sql);
        }
        $this->fetchObjectById((int)$this->id);
        return $this->id;
    }

As you can see it is a restriction for every table using the Db.php class that it has a column called "id" that is uniqly indexed and set up to autoincrement. In this code we also have a new function we have not implemented yet "handleDataIn". This function will prepare data to be stored in the database. It is your last resort to manipulate data before it is saved to the database.

    // Before saving data to the database, we want to check it for sql-injection and stuff
    private function handleDataIn($field, $type, $data) {
        $aString  = array('text', 'date', 'time', 'datetime', 'tinytext', 'mediumtext', 'longtext');
        $aInt     = array('int', 'double', 'tinyint', 'smallint', 'mediumint', 'bigint');
        $aDecimal = array('decimal');
        $tmp = explode('(', $type);
        $type = $tmp[0];
        if (in_array($type, $aString)) {
            $data = String::slashText($data); 
        }
        if (in_array($type, $aInt)) {
            $data = (int)$data;
        }
        if (in_array($type, $aDecimal)) {
            $data = str_replace(',', '.', $data);
        }
        if (preg_match("/^is_/", $field, $aMatches)) {
            $data = (int)$data;
        }
        return $data;
    }

And here wa have a function call to String::slashText(). That will take a string and slash the text and prevent any atempts of SQL-injection. So we also need to add the String.php in out classes library.

]*?>.*?/is', '', $text);
        $text = preg_replace('//is', '', $text);
        
        // Secure all safe tags, only allowing tags and slashes. No other information inside tags.
        $text = preg_replace('/(<(/?)(b|p|i|u|s|span|li|lu|table|tr|th|td|cite|wbr|strong|em|italic|code|pre)(/?)>)/i', '#$2$3$4¤', $text);
        $text = preg_replace('/<(a).*?(href="[^"]*?").*?(target="[^"]*?")>/i', '#$1 $2 $3¤', $text);
        $text = preg_replace('/<(a).*?(href="[^"]*?")>/i', '#$1 $2¤', $text);
        $text = preg_replace('/(<(/a)>)/i', '#$2¤', $text);
        $text = preg_replace('//', '#br#', $text);

        // Remove all tags that are left
        $text = preg_replace('/<[^>]*?>/', '', $text);
        
        // Restore all safe tags
        $text = preg_replace('/#br#/', '
', $text); $text = preg_replace('/(#(/a)¤)/i', '<$2>', $text); $text = preg_replace('/(#(a.*?)¤)/i', '<$2>', $text); $text = preg_replace('/(#(/?(b|p|i|u|s|span|li|lu|table|tr|th|td|cite|wbr|strong|em|italic)/?)¤)/i', '<$2>', $text); return $text; } }

The only thing left for this first draft of a generic edit form is to add som styling to our css.

.button {
  height: 30px;
  font-size: 1em;
  line-height: 1.2em;
  display: inline;
  margin-top: 0px;
  margin-bottom: 5px;
  padding: 5px;
  padding-left: 10px;
  padding-right: 10px;
  background: #fff;
  border: 1px solid #333;
  color: #333 !important;
  -webkit-border-radius: 4px;
  -moz-border-radius: 4px;
  -o-border-radius: 4px;
  -ms-border-radius: 4px;
  -khtml-border-radius: 4px;
  border-radius: 4px;
  cursor: pointer;
  text-transform: uppercase;
}
.button:hover {
  background: #999;
  color: #fff !important;
}
input, select, textarea {
  font-size: 1em;
  line-height: 1.2em;
}

table.form th, table.form td {
  padding: 5px;
}
table.form th {
  text-align: left;
  font-weight: normal;
  font-size: 0.8em;
  vertical-align: top;
}
em {
  color: #333;
}

.information {
  background: #cfc !important;
}
.warning {
  background: #ff9 !important;
}
.error {
  background: #fcc !important;
}

- framework, php, generic, software

<< Generating code
Follow using RSS
Generating the edit form >>

Comment

Name
Mail (Not public)
Send mail updates on new comments
0 comment