I like the idea of using FUSE models for validation in RedbeanPHP.
My applications sometimes require accepting data through multiple sources (form, file, etc.), so putting the validation on the actual class update makes sense.
Looking at the examples on the Redbean site, the validation seems to be based on throwing an exception.
Of course, you can only throw one exception, so I am assuming I'd need to create an additional property of type "array" in my FUSE class to hold validations messages associated with individual fields.
Does anyone have any better ideas? Here's what I've been trying thus far...
<form action="" method="post">
<p>your name: <input name="name" type="text"></p>
<p>your email: <input name="email" type="text"></p>
<p>your message:</p>
<textarea name="message" id="" cols="30" rows="10"></textarea>
<input name="send" value="send message" type="submit">
</form>
<?php
/**
* #property $name string
* #property $email string
* #property $message string
*/
class Model_Comment extends RedBean_SimpleModel{
public $invalid = array();
public function update(){
if(empty($this->name)) $this->invalid['name'] = "field is empty";
if(empty($this->email)) $this->invalid['email'] = "field is empty";
if(empty($this->message)) $this->invalid['message'] = "field is empty";
if(count($this->invalid) > 0) throw new Exception('Validation Failed!');
}
public function getInvalid(){
return $this->invalid;
}
}
if(isset($_POST['send'])){
$comment = R::dispense('comment');
/* #var $comment Model_Comment */
$comment->import($_POST,'name,email,message');
try{
R::store($comment);
}
catch(Exception $e){
echo $e->getMessage();
$invalid = $comment->getInvalid();
print_r($invalid);
exit;
}
echo '<p>thank you for leaving a message.</p>';
}
echo "<h2>What people said!</h2>";
$comments = R::find('comment');
/* #var $comments Model_Comment[] */
foreach($comments as $comment){
echo "<p>{$comment->name}: {$comment->message}</p>";
}
?>
You can extend RedBean_SimpleModel class to add your own methods and fields to it, so it will work with all your model. Then, you can use transactions to manage your validations. It could look like this (code not tested):
class RedBean_MyCustomModel extends RedBean_SimpleModel {
private $errors = array();
public function error($field, $text) {
$this->errors[$field] = $text;
}
public function getErrors() {
return $this->errors;
}
public function update() {
$this->errors = array(); // reset the errors array
R::begin(); // begin transaction before the update
}
public function after_update() {
if (count($this->errors) > 0) {
R::rollback();
throw new Exception('Validation failed');
}
}
}
Then, your model could look like this:
class Model_Comment extends RedBean_MyCustomModel {
public function update(){
parent::update();
if(empty($this->name)) $this->error('name', 'field is empty');
if(empty($this->email)) $this->error('name', 'field is empty');
if(empty($this->message)) $this->error('name', 'field is empty');
}
public function getInvalid(){
return $this->invalid;
}
}
Related
I'm working with a player class, the code prints a form with name, lastname and location fields that have to be filled in to add a new player.
But I have a problem when printing the players since I only print the names of the players, when I try to print the data separately (name, lastname and location) I do not print anything.
session_start();
class Player {
private $players;
private $name;
private $lastname;
private $location;
public function __construct($name,$lastname,$location)
{
$this->name = $name;
$this->lastname = $lastname;
$this->location = $location;
$this->players = array();
}
public function getName()
{
return $this->name;
}
public function getLastname()
{
return $this->lastname;
}
public function getLocation()
{
return $this->location;
}
public function addPlayer($onePlayer)
{
$this->players[] = $onePlayer;
return $this;
}
public function printPlayers()
{
foreach($this->players as $player){
// just show the name¿?.
echo $player.'<br />';
// The problem is here.
/*echo $player['name'].'<br />';
echo $player['lastname'].'<br />';
echo $player['location'].'<br />';*/
}
}
public function __toString()
{
return $this->name;
return $this->lastname;
return $this->location;
}
}
function printForm()
{
echo '<FORM METHOD="POST" style="text-align: center; margin-top: 73px;">
<h2>Add Players</h2>
<label>Add the name : </label><INPUT class="form" TYPE = "text" NAME = "name"> <br>
<label>Add the lastname : </label><INPUT class="form" TYPE = "text" NAME = "lastname"> <br>
<label>Add the location : </label><INPUT class="form" TYPE = "text" NAME = "location"> <br><br>
<INPUT class="form" TYPE = "submit" VALUE = "add" name="action">
<INPUT class="form" TYPE = "submit" VALUE = "list" name="action">
</ FORM>';
}
// Load the player data of the session and if it does not exist create a new player.
function loadData()
{
return isset($_SESSION['player']) ? $_SESSION['player'] : new Player();
}
// Save the player's data in the session.
function saveData($player)
{
$_SESSION['player'] = $player;
}
printForm();
$player = loadData();
if(isset($_POST['action']))
{
switch($_POST['action'])
{
case 'add':
$player->addPlayer(new Player($_POST['name'],$_POST['lastname'],$_POST['location']));
saveData($player);
break;
case 'list':
echo '<hr />';
$player->printPlayers();
break;
}
}
It looks like in the problematic part you're trying to access private properties using array syntax. That won't work for a couple of reasons
The properties aren't accessible there because they're defined as private
You can't get them with array syntax. If they weren't private you'd need to use $player->name.
But fortunately you have also written some getters, so you should be able to use those instead, like this:
echo $player->getName();
Guys i have error in my php mvc code when am updating my profile it tell me error while updating l check my well but it seem am suck and don't know what to do. please help me!
it keep on warning me with this warning
Warning: PDOStatement::execute(): SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in C:\xampp\htdocs\php.dev\classes\Model.php on line 37
This my classes/Model.php file
abstract class Model {
protected $dbh;
protected $stmt;
public function __construct() {
$this->dbh = new PDO("mysql:host=".DB_HOST.";dbname=".DB_NAME, DB_USER, DB_PASS);
}
public function query($query) {
$this->stmt = $this->dbh->prepare($query);
}
// binds the prepare statement
public function bind($param, $value, $type = null) {
if (is_null($type)) {
switch (true) {
case is_int($value):
$type = PDO::PARAM_INT;
break;
case is_bool($value):
$type = PDO::PARAM_BOOL;
break;
case is_null($value):
$type = PDO::PARAM_NULL;
break;
default:
$type = PDO::PARAM_STR;
}
}
$this->stmt->bindValue($param, $value, $type);
}
public function execute() {
$this->stmt->execute();
}
public function resultSet() {
$this->execute();
return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
}
public function lastInsertId() {
return $this->dbh->lastInsertId();
}
public function single(){
$this->execute();
return $this->stmt->fetch(PDO::FETCH_ASSOC);
}
public function emailExist() {
$this->execute();
return $this->stmt->fetch(PDO::FETCH_ASSOC);
}
}
and here's my controllers/user.php
class Users extends Controller{
protected function profile(){
if (!isset($_SESSION['is_logged_in'])) {//if user do not login they can not profile page
header('Location: '.ROOT_URL.'shares');
}
$viewmodel = new UserModel();
$this->returnView($viewmodel->profile(), true);
}
}
and here's my models/user.php code
public function profile(){
// Sanitize POST
//$post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
if(isset($_POST['updateProfile'])){
$name = $_POST['name'];
$email = $_POST['email'];
if (empty($_POST['name']) || empty($_POST['email'])) {
Messages::setMsg('Please Fill All Form Fields', 'error');
return;
}
// check if email is already taken
$this->query('SELECT * FROM users WHERE email = :email');
$this->bind(':email', $_POST['email']);
$row = $this->emailExist();
if ($row) {
Messages::setMsg('Email already Exist', 'error');
return;
} else {
# Update the MySQL
$this->query("UPDATE users SET name =:name, email =:email WHERE id =:id");
$this->bind(':name', $_POST['name']);
$this->bind(':email', $_POST['email']);
$this->execute();
// Verify
if($this->lastInsertId()){
Messages::setMsg('Successfull Updated', 'success');
return;
} else {
Messages::setMsg('Error while updating data', 'error');
return;
}
}
}
return;
}
and here's my views/users/profile.php code
<form method="post" action="<?php $_SERVER['PHP_SELF']; ?>">
<div class="form-group">
<label>Name</label>
<input type="text" name="name" class="form-control" value="<?php echo $_SESSION['user_data']['name'];?>" />
</div>
<div class="form-group">
<label>Email</label>
<input type="text" name="email" class="form-control" value="<?php echo $_SESSION['user_data']['email'];?>" />
<!-- input type="hidden" name="id" class="form-control" value="<!?php echo $_SESSION['user_data']['id']?>" / -->
</div>
<input class="btn btn-primary" name="updateProfile" type="submit" value="Submit" />
</form>
If the user doesn't already exist, it runs:
$this->query("UPDATE users SET name =:name, email =:email WHERE id =:id");
Which is attempting to update an existing user, instead of adding a new one. The query fails with an error because you haven't bound anything to :id (and you shouldn't, because you're attempting to add a new user).
Instead try this query:
INSERT INTO users SET name =:name, email =:email
and it should work. It still won't allow you to edit users, but it will allow you to add new ones.
EDITED: Added checking stops into code.
keeping OOP design, what am I doing wrong?
The triangle sides are not passing into the classes properly.
I already tested the object with parameters inside the PHP file and it's working excellent. So it seems that the only culprit here is how I'm passing the params inside the classes.
Here is my shape.php:
<?php
abstract class Shape{
abstract protected function getArea();
abstract protected function getPerimeter();
}
class Triangle extends Shape{
private $_sides = array();
private $_perimeter = null;
public $status = 0;
function __construct($s0=0, $s1=0, $s2=0){
$this->_sides[] = $s0;
$this->_sides[] = $s1;
$this->_sides[] = $s2;
echo 'constructed<hr>';
//calculate perimeter:
$this->_perimeter = array_sum($this->_sides);
echo 'calculated perimeter<hr>';
$this->checkForm();
}
public function checkForm(){
if (!empty($_POST['submit'])){
$checkIt = $this->status = 1;
/* echo 'status is <hr>'.$checkIt;*/
}
return $this->status;
}
public function proceed(){
if ($this->status == 1){
echo 'proceed func started<hr>';
$this->_sides[0] = $_POST['s0'];
$this->_sides[1] = $_POST['s1'];
$this->_sides[2] = $_POST['s2'];
echo 'Side 1: '.$this->_sides[0] = $_POST['s0'].'<hr>';
echo 'Side 2: '.$this->_sides[1] = $_POST['s1'].'<hr>';
echo 'Side 3: '.$this->_sides[2] = $_POST['s2'].'<hr>';
}else{
echo 'This didn\'t work as planned... :(';
}
}
public function getArea(){
return (sqrt(
($this->_perimeter/2) *
(($this->_perimeter/2)- $this->_sides[0]) *
(($this->_perimeter/2)- $this->_sides[1]) *
(($this->_perimeter/2)- $this->_sides[2])
));
}
public function getPerimeter(){
return $this->_perimeter;
}
}
/*$check = new Triangle(2, 2, 2);*/
$check = new Triangle();
echo $check->proceed();
echo 'status is: '.$check->status.'<hr>';
echo 'The '.get_parent_class($check).' is a '.get_class($check).'. It\'s Perimeter is: '.$check->getPerimeter().'M.<br>';
echo 'The '.get_parent_class($check).' also has an area of: '.$check->getArea().'M.<br>';
And this is my index.php file:
<div class="row">
<div class="boxy">
<form method="post" action="Shape.php">
<label for="s0">Side 1</label>
<input name="s0" type="number" placeholder="Side 0"><br>
<label for="s1">Side 2</label>
<input name="s1" type="number" placeholder="Side 1"><br>
<label for="s2">Side 3</label>
<input name="s2" type="number" placeholder="Side 2"><br>
<input type="submit" name="submit" value="Run It.">
</form>
</div>
</div>
There are few issues with your code, such as:
You're trying to set up triangle properties in the constructor but you're not passing any values. See this statement,
$check = new Triangle();
You didn't make use of checkForm() and proceed() method.
Though there are several solutions to this problem, one would be like this:
Keep your constructor method empty, like this:
function __construct(){}
And change your proceed(), getArea() and getPerimeter() methods in the following way,
private function proceed(){
if ($this->status == 1){
$this->_sides[0] = isset($_POST['s0']) ? $_POST['s0'] : 0;
$this->_sides[1] = isset($_POST['s1']) ? $_POST['s1'] : 0;
$this->_sides[2] = isset($_POST['s2']) ? $_POST['s2'] : 0;
}else{
echo 'This didn\'t work as planned... :(';
}
}
public function getArea(){
if($this->checkForm()){
$this->proceed();
return (sqrt(
($this->_perimeter/2) *
(($this->_perimeter/2)- $this->_sides[0]) *
(($this->_perimeter/2)- $this->_sides[1]) *
(($this->_perimeter/2)- $this->_sides[2])
));
}else{
echo "Something went wrong. ";
}
}
public function getPerimeter(){
if($this->checkForm()){
$this->proceed();
return $this->_perimeter = array_sum($this->_sides);
}else{
echo "Something went wrong. ";
}
}
Well, I actually found the error, I forgot to return the proceed() results.
Here it is amended and fully working:
abstract class Shape{
abstract protected function getArea();
abstract protected function getPerimeter();
}
class Triangle extends Shape{
private $_sides = array();
private $_perimeter = null;
public $status = 0;
function __construct($s0=0, $s1=0, $s2=0){
$this->_sides[] = $s0;
$this->_sides[] = $s1;
$this->_sides[] = $s2;
echo 'constructed<hr>';
//calculate perimeter:
$this->_perimeter = array_sum($this->_sides);
echo 'calculated perimeter<hr>';
$this->checkForm();
}
public function checkForm(){
if (!empty($_POST['submit'])){
$checkIt = $this->status = 1;
/* echo 'status is <hr>'.$checkIt;*/
}
return $this->status;
}
public function proceed(){
if ($this->status == 1){
echo 'proceed func started<hr>';
$this->_sides[0] = $_POST['s0'];
$this->_sides[1] = $_POST['s1'];
$this->_sides[2] = $_POST['s2'];
echo 'Side 1: '.$this->_sides[0] = $_POST['s0'].'<hr>';
echo 'Side 2: '.$this->_sides[1] = $_POST['s1'].'<hr>';
echo 'Side 3: '.$this->_sides[2] = $_POST['s2'].'<hr>';
}else{
echo 'This didn\'t work as planned... :(';
}
return $this->_sides;
}
public function getArea(){
return (sqrt(
($this->_perimeter/2) *
(($this->_perimeter/2)- $this->_sides[0]) *
(($this->_perimeter/2)- $this->_sides[1]) *
(($this->_perimeter/2)- $this->_sides[2])
));
}
public function getPerimeter(){
return $this->_perimeter;
}
}
$check = new Triangle($_POST['s0'], $_POST['s1'], $_POST['s2']);
/*$check = new Triangle();*/
echo 'status is: '.$check->status.'<hr>';
echo 'The '.get_parent_class($check).' is a '.get_class($check).'. It\'s Perimeter is: '.$check->getPerimeter().'M.<br>';
echo 'The '.get_parent_class($check).' also has an area of: '.$check->getArea().'M.<br>';
Controller:
class PeopleController extends \Phalcon\Mvc\Controller{
public function indexAction(){
}
public function CreatePersonAction(){
$person = new people();
$person->firstName=$this->request->getPost("firstName");
$person->surname=$this->request->getPost("surname");
$person->telephone=$this->request->getPost("telephone");
$person->email=$this->request->getPost("email");
$person->city=$this->request->getPost("city");
$person->country=$this->request->getPost("country");
$person->save();
if ($person) {
echo"Successfully Registered User!";
} else {
echo "Sorry, the following problems were generated: ";
foreach ($person->getMessages() as $message) {
echo $message->getMessage(), "<br/>";
}
}
}
}
Model:
<?php
class People extends \Phalcon\Mvc\Model{
}
I have tried implementing the getSource() method into the model as the phalcon docs suggest that but still not getting the desired output of saving the POST items to the database
Try this:
<?php
use Phalcon\Mvc\Controller as PhController;
class PeopleController extends PhController
{
public function IndexAction()
{
//When no view(aka template) is used you should disable the view rendering
//Otherwise the output buffer can get overwritten and your echoes won't display
$this->view->disable();
echo "<h1>Index Action!</h1>";
}
public function CreatePersonAction()
{
$this->view->disable();
if($this->request->isPost()) {
$dataSent = $this->request->getPost();
$person = new People();
$person->firstName = $dataSent["firstName"]
$person->surname = $dataSent["surname"];
$person->telephone = $dataSent["telephone"];
$person->email = $dataSent["email"];
$person->city = $dataSent["city"];
$person->country = $dataSent["country"];
$savedSuccessfully = $person->save();
if($savedSuccessfully) {
echo "Successfully Registered User!";
} else {
$messages = $person->getMessages();
echo "Sorry, the following problems were generated: ";
foreach ($messages as $message) {
echo "$message <br/>";
}
}
} else {
echo "The request method should be POST!";
}
}
}
Also, add this code to your main index.php (just before Phalcon\Mvc\Application->handle()):
$debug = new \Phalcon\Debug();
$debug->listen();
With this you'll get better error messages, so you can check if your DB settings are OK. Also remember that Phalcon only works with the database schema passively, that means, all tables and fields should already exist to the Model get stored, Phalcon just use the tables and never create them.
I have created a form in html which takes all the information using the method post in php to print them out for the user but its seems like that I have a problem with my form. It does not print out the entered details by the user, I have tried to fill up and then press submit to create an object of the class profile assigning all the information from the user to the object and print them out on the browser but nothing appear on the browser.
I have also tried to echo the methods like getFirstName but its the same nothing comes up, can anyone help me to find out whats the problem with the code and how can I fix it.
Please note that I have included three different files one is the html form and the other one is the passingdata.php which will get all the information entered by the user and the third file is the class profile which is used in the passingdata to create an object and give it all the needed information in order to create an object of that class.
Finally, I have invoked the method printDeatils which should print out all the information entered by the user
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><?php echo 'Student Deatils'; ?></title>
</head>
<body>
<p>Please enter your Details:</p>
<div>
<form name="student" method="post" action="passingdata.php">
<div>
<label>First name:</label> <input type ="text" name="first_name">
<label>Last name</label> <input type ="text" name="last_name">
<br></br>
<label>International student</label> <input type="checkbox" name="international">
<br></br>
<fieldset>
<legend>Course</legend>
<label>CS <input type="radio" name="course" value="CS"></label>
<label>SE <input type="radio" name="course" value="SE"></label>
<label>MIT <input type="radio" name="course" value="MIT"></label>
</fieldset>
<br></br>
<input type="submit" name="Submit" value="Submit">
<input type="reset" name="Resit" value="Reset">
</div>
</form>
</div>
<?php
?>
</body>
</html>
The passing data file:
<?php
require("profile.php");
$ss = new Profile($_POST['first_name'], $_POST["last_name"],
$_POST["course"], $_POST["international"]);
echo $ss->printDtails();
?>
The class profile:
<?php
class Profile {
private $_firstName, $_lastName, $_international, $_course;
function __contruct ($firstName, $lastName, $course, $international) {
$this->_firstName = $firstName;
$this->_lastName = $lastName;
$this->_course = $course;
$this->_international = $international;
}
public function setFirstName($firstName)
{
$this->_firstName = $firstName;
}
public function setLastName($lastName)
{
$this->_lastName = $lastName;
}
public function setInternational($inter)
{
$this->_international = $inter;
}
public function setCourse($course)
{
$this->_course = $course;
}
public function getFirstName()
{
return $this->_firstName;
}
public function getLastName()
{
return $this->_lastName;
}
public function getInternational()
{
return $this->_international;
}
public function getCourse()
{
return $this->_course;
}
public function printDtails()
{
echo "$_firstName";
}
}
?>
In the printDtails() function you need to echo $this->_firstName
Also in your class, the word construct is spelled wrong, you have __contruct it needs to be __construct
This worked for me, however I did modify your code slightly.
I must admit that I'm learning classes myself, so this may or may not be what you're looking for, however it did work.
Also, inside your printDtails() function, it needed a echo $this->_firstName; etc.
I changed your constructs to $this->_firstName = $_POST['first_name']; etc.
N.B.: The word construct was mispelled as contruct with the missing s
Here is what I came up with:
<?php
class Profile {
private $_firstName, $_lastName, $_international, $_course;
function __construct ($_firstName, $_lastName, $_international, $_course)
{
$this->_firstName = $_POST['first_name']; // modified
$this->_lastName = $_POST['last_name']; // modified
$this->_course = $_POST['course']; // modified
$this->_international = $_POST['international']; // modified
}
public function setFirstName($firstName)
{
$this->_firstName = $firstName;
}
public function setLastName($lastName)
{
$this->_lastName = $lastName;
}
public function setInternational($inter)
{
$this->_international = $inter;
}
public function setCourse($course)
{
$this->_course = $course;
}
public function getFirstName()
{
return $this->_firstName;
}
public function getLastName()
{
return $this->_lastName;
}
public function getInternational()
{
return $this->_international;
}
public function getCourse()
{
return $this->_course;
}
public function printDtails()
{
echo $this->_firstName . "\n"; // modified
echo $this->_lastName . "\n"; // modified
echo $this->_course . "\n"; // modified
echo $this->_international . "\n"; // modified
}
}
?>