Derived Classes in Php Phalcon - php

I am fairly new to php phalcon and the language itself. I am making a website that involves an abstract class and derived classes.
The Abstract Class:
<?php
abstract class UsersAbstract extends \Phalcon\Mvc\Model {
private $Full_Name; //
private $Mobile_Number; //
private $Email_ID; //
private $City; //
private $Country; //
private $DoB; //
private $Gender; //
private $Age; //
private $Availability_Flag; /*value of flag is 1 for active and 0 for inactive*/
/********setters and getters for all data members which I have not written here*******/
public function getSource()
{
return 'users_abstract';
}
}
The derived class
<?php
class UserPatients extends UsersAbstract
{
private $Patient_ID;
private $Guardian_Name;
private $Doctors = array();
public function getSource()
{
return 'user_patients';
}
/***************setter and getter for patient id*******************/
public function getPatientID()
{
return $this->Patient_ID;
}
public function setPatientID($value)
{
$this->Patient_ID = $value;
}
/****************setter and getter for guardian name******************/
public function getGuardianName()
{
return $this->Guardian_Name;
}
public function setGuardianName($value)
{
$this->Guardian_Name = $value;
}
/****************getter and setter for doctor array*********************/
public function getDoctors()
{
return $this->Doctors;
}
public function setDoctors($value)
{
$this->Doctors = $value;
}}
In my controller, I am reading data from a form in a view. An object of the class UserPatients is declared and its data members are set. Here is the action method that I am calling in the controller PatientSignInController:
public function SaveAction()
{
if (!empty($_POST)){
$patient_data = new UserPatients();
$patient_data->setFull_Name($_POST['Full_Name']);
$patient_data->setGuardianName($_POST['Guardian_Name']);
$patient_data->setDoB($_POST['DoB']);
$patient_data->setAge($_POST['Age']);
$patient_data->setGender($_POST['gender']);
$patient_data->setMobile_Number($_POST['Contact_No']);
$patient_data->setEmail_Address($_POST['Email_ID']);
$patient_data->setCity($_POST['City']);
$patient_data->setCountry($_POST['Country']);
$patient_data->setPatientID($_POST['Patients_ID']);
$patient_data->setFlag(1);
$doctorsArray = array("ACD","ABC"); //some hard coded values for the time being
$patient_data->setDoctors($doctorsArray);
$patient_medical_info = new PatientInfo();
$patient_medical_info->setBP($_POST['BP']);
$patient_medical_info->setTemperature($_POST['Temperature']);
$patient_medical_info->setInformation($_POST['Info']);
$patient_medical_info->setPatientID($_POST['Patients_ID']);
$patient_medical_info->setDateOfMeeting(date("d/m/y"));
$patient_data->save();
$patient_medical_info->save();
$this->response->redirect("../../../../WebMCare/PatientSignIn/Index");
}
}
The structure of my database is the same as these classes - I have a table Users_Abstract with all the attributes of the abstract class and I have a table User_Patients with all the attributes of the child class.
When I hit the save button on the form in the view and check the database tables, I discover that the new entries are added in the patient_info table. Which means that the $patient_medical_info->save() is working.
However, the table users_abstract does not contain any new data for the corresponding object, while the table user_patients does get the associated data. I checked messages for errors in save method, but it returned nothing.
I can't seem to find anything online.
Please help me.
I have tried storing data in a single table by associating one table, with all 12 attributes, to the classes UsersAbstract and User_Patients. Even that does not work.

Related

PHP cast object in simple ORM

I would like to make a simple ORM in PHP for standard CRUD interaction with my db, I also want make it work in php5 for legacy compatibility.
I've written some classes to do this and it works, but not completely as I would.
This is the idea. I have an abstrac class called ModelBase which has a property (tableName) and some metods like select, insert, update and delete, plus has an abstract method, getData, that will be implemented by the classes that will be implement ModelBase and should return object of correct type.
So, for example, I could have a class Users which implements ModelBase and one another class UserData which is the model with the property.
Here is the code:
abstract class ModelBase{
private $tableName;
public function __construct($tableName) {
$this->tableName = $tableName;
}
public function select{
// make select query to db and retreive data
// ...
$resData = [];
while($dataRow = mysqli_fetch_array($res, MYSQLI_ASSOC)) {
$resData[] = $this->getObjectData($dataRow); // implemented in child class
}
return $resData;
}
public function insert(){ /* ... */}
public function update(){ /* ... */}
public function delete(){ /* ... */}
abstract function getObjectData($data); // maps the results
}
class UserData {
public $id;
public $name;
public $surname;
public $email;
// other fields
public function __construct() {}
}
class User implements ModelBase {
private $tableName = 'users';
public function __construct() {
parent::__construct($this->tableName);
}
public function getObjectData($dataRow) {
$o = new UserData ();
// mapping dataRow to object fields
$o->id = $dataRow['ID'];
// ....
return $o;
}
}
So I use my classes in this way:
$users = new Users();
$u = users->select();
$firstUser = $u[0]; // I get my user if exists
In $firstUser I'll get my object with property and correct data but I would like to have that also my IDE (vsCode in this case) would recognize the object type in order to suggest the correct properties. So if I write $firstUser-> I would like to see field suggestions (id, name, surname, ...) from UserData and for other xyzData classes as well.
What I should do to improve my classes in order to see property suggestions when I use my objects, also in php5?
Solution for PHP 8, tested on PHPStorm.
<?php
class Base {
/**
* #return static[]
*/
public function select() : array {
return [new self];
}
public function selectFirst() : static {
return $this->select()[0];
}
}
class User extends Base {
public ?string $userName = null;
}
#detects the current class via () : static
(new User)->selectFirst()->userName;
#detects the current class via #return static[]
(new User)->select()[0]->userName;
In line solution for PHP 5, define the variable directly with this comment
/** #var $a User */
$a->userName;
There is no benefit of supporting old PHP 5. You lose so mutch clean code and modern approach when supporting old php versions.
But when you have to, then go with the inline solution.
Not tested and not so clean for PHP 5:
class User extends Base {
public ?string $userName = null;
/**
* #return User[]
*/
public function select() : array {
return parent::select();
}
}

Parent and child classes not referencing correctly within a function PHP

I am building an MVC component and I'm getting stuck with an issue with a parent and child model. I have a few methods in the parent Model and they're not working with the database_class object
the constructor works fine
but when I use that object in the methods its like the constructor doesn't exist?
Class Controlller
{
public function __construct()
{
$this->childModel = $this->model('childModel');
} // end construct
// methods go here
}
Here are the models:
class childModel extends parentModel {
private $dbo;
public function __construct()
{
$dbobj = new Database_class;
$this->dbo = $dbobj;
}
//methods
}
class parentModel {
private $dbom;
public function __construct()
{
$dbombj = new Database_class;
$this->dbom = $dbombj;
var_dump($this->dbom); //working perfectly as database object
}
public function methodName()
{
var_dump($this->dbom); //not showing up as database object
}
}
I don't think this code is doing what you think it's doing. In childModel, you are overwriting the __construct method of the parentModel, so the __construct in the parentModel never gets called. Therefore $this->dbom should be null. Furthermore if you wish to use $this->dbom from the childModel, you should probably change the scope from private $dbom to protected $dbom. See this page for more info on that: http://php.net/manual/en/language.oop5.visibility.php

Symfony: Entities and Class Implements

Suppose I want to have two entities in my database, a Box and an Object. I can have different boxes and within each box I can add multiple Objects.
(For simplicity, I've missed out the getters, setters, $id, etc in the code examples)
Box entity
namespace AppBundle\Entity;
class Box {
...
/**
* #ORM\OneToMany(targetEntity="Object", mappedby="box")
*/
private $objects;
}
Object entity
namespace AppBundle\Entity;
class Object {
...
/**
* #ORM\ManyToOne(targetEntity="Box", mappedby="objects")
*/
private $box;
// The following are assumptions
private $objectType;
private $objectData;
private $theObject;
}
My objects can be multiple types (I want to be able to add new types of objects without touching the database):
A Pen (not an Entity)
class Pen implements ObjectType {
public $color; // In reality this would have set/get
public function whatAmI() {
return "I am a ".$this->color." pen";
}
}
A Remote (not an Entity)
class Remote implements ObjectType {
public $numberOfButtons;
public function whatAmI() {
return "I am a remote with ".$this->numberOfButtons." buttons";
}
public function pressButton() {
...
}
}
ObjectType
interface ObjectType {
public function whatAmI();
}
My question is what is the best way to tie the two bits together? I would like to be able to do the following:
Go through all the objects in my box and call functions which they implement:
$myBox = $em->find('Box', $id);
foreach ($myBox->getObjects() as $object) {
echo $object->whatAmI();
}
Create a new object and add it to my box:
$myPen = new Pen();
$myPen->color = "red";
$myBox->addObject($myPen);
Call functions if I fetch the object directly from the DB:
$myRemote = find('Object', $id); // $id will be of a Remote class
$myRemote->pressButton();

PHP MVC - Model Relations

I am trying to create a PHP application using the MVC pattern. I am new to MVC and I do not use a framework since I want to understand in more depth the underlying MVC processes.I have a question regarding models, JSON representation and foreign keys. Lets assume that I have two models:
Class User {
public $id;
public $name;
public $gender_id;
}
Class Gender{
public $id;
public $description
}
The User->gender_id is a foreign key to Genders->id table.
My URI is /users/1 which is supposed to return the following JSON:
{"id":1,"name":"john","gender":"male"}
Is the controller's duty to know the model relations and retrieve the necessary data (user & gender model) which will then be passed to a view that will output the JSON ? Or should the association be defined somehow in the User's model? The gender description is a descriptive attribute but somehow it must be included in the Users view.
Regards
It is not the controller's duty to retrieve persisted data, you should have a Mapper for that. There are many answers that explain in detail the functions of Models and Controllers (this is a very good one).
Class User
{
private $id;
private $name;
private $gender;
public function __construct($id, $name, Gender $gender)
{
$this->id = $id;
$this->name = $name;
$this->gender = $gender;
}
public function getId()
{
return $this->id;
}
... and other getter/setters
public function setGender(Gender $gender)
{
$this->gender = $gender;
}
public function getGender()
{
return $this->gender;
}
}
And your gender class thus:
Class Gender
{
private $id;
private $description;
public function ($id, $description)
{
$this->id = $id;
$this->description = $description;
}
//with getters and setters
}
You can proceed to make a 'Service' (for lack of better word) to return your a JSON string of your User object. Note that this 'Service' is considered to be a part of your Model (see this)
Class UserToJSON
{
public function convert(User $user)
{
$user_arr = array();
$user_arr['id'] = $user->id;
$user_arr['name'] = $user->name;
$user_arr['gender'] = $user->gender->getDescription();
return json_encode($user_arr, true);
}
}
With all this in place (assuming you have a valid User object), you can get your JSON for a user easily like so:
$user = new User(1, "name", new Gender(1, "female"));
print (new UserToJSON())->convert($user);

Wrap/Reuse/Clone a PHP object (code optimization)

Imagine two classes which share almost the same exact methods and properties, both extending a parent class, but the differences are minimal.
class fields {
public function __construct() {
global $id;
$this->id = $id++;
}
}
class input extends fields {
public function __construct() {
parent::__construct();
}
public function draw() {
echo '<input>';
}
}
class textarea extends fields {
public function __construct() {
parent::__construct();
}
public function draw() {
echo '<textarea>';
}
}
I'm thinking it would be more efficient to rewrite the textarea class in this psuedo-code fashion:
class textarea extends fields {
public function __construct() {
$this = new input(); // <<------
}
public function draw() {
echo '<textarea>';
}
}
Basically, I'm unsure how this would best be done so that the class acts like the class from the first example.
In essence, I would like to do the following using OOP, but be able to use the object as it can be in the first example above (be able to call the possibly overloaded methods, have different properties, etc.):
function a() {echo '123';}
function b() {a();}
I have just copied the entire class and modify a few lines, but I feel it is wasteful.
Final Answer
Thanks to those people, here is the combined answer with example calls:
abstract class fields {
private static $masterid = 0;
public function __construct() {
$this->id = self::$masterid++;
}
}
class input extends fields {
public $data;
public function __construct($new = '') {
parent::__construct();
if ($new) $this->data = $new;
else $this->data = 'Hello';
}
public function draw() {
echo '<input>'.$this->export().'</input>';
}
public function export() {
return 'ID '.$this->id.' = '.$this->data;
}
}
class textarea extends input {
public function __construct($new = '') {
parent::__construct($new);
}
public function draw() {
echo '<textarea>'.$this->export().'</textarea>';
}
}
$a = new textarea();
$a->draw();
$a = new textarea('World');
$a->draw();
$a = new input('!');
$a->draw();
//Outputs:
// <textarea>ID 0 = Hello</textarea>
// <textarea>ID 1 = World</textarea>
// <input>ID 2 = !</input>
Make the fields class an abstract class, and like Darren suggested, make the 'draw' method a function of the fields class.
Now heres the trick, you want the input class to extend fields, but override the draw method. This will allow you to customize the functionality of that method, and you can still call the parent variation from within it.
Finally, since the textarea class is going to have many similarities to the input class, make textarea extend input. Thereby inheriting the properties and methods of both fields and input.
Make the "fields" class have a draw method:
public function draw($msg) {
echo $msg;
}
Then in the textarea or input class put:
parent::draw("<input>");
This cuts down on the number of methods you have, and can call one method for both types of field.
Also in your "fields" class, change the id code to be like this:
public $id
public function __construct($id) {
$this->id = $id;
}
Then in the subclass:
parent::__construct(1); //Or whatever ID you want
The way you have it, ID is the same value every time you set it, which will result in every subclass of fields having the same id. This way each subclass will have a seperate ID.
Also because I'm nice, here's it all put together:
public class field {
$id;
public __construct($id) {
$this->id = $id;
}
public function draw($msg) {
echo $msg;
}
}
public class input extends field {
public __construct() {
parent::__construct(1);
parent::draw("<input>");
}
}
public class textarea extends field {
public __construct() {
parent::__construct(2);
parent::draw("<textarea>");
}
}
That's how I'd put it together from what you've said. I may have mistaken what you were asking for though. Can you tell I'm primarily a Java programmer from that?
It's not exactly clear what you want to do. For the example you've given, I think the structure is OK, but you should make a few changes, particularly with the constructor. I think the constructor should be abstract, with an abstract method draw().
abstract class fields {
// Use a static member to keep track of id's instead of making it global
private static $id = 0;
// Use an instance variable to keep track of a particular instance's id
private $myId;
public function __construct() {
// Increment the static ID & assign it to the instance id.
$this->myId = self::$id++;
}
// Provide a public getter, so that the ID can't be changed
// externally to this class
public function getId() {
return $this->myId;
}
public abstract draw(); // Make sure all sub classes implement a draw() method.
}
class input extends fields {
// Don't need to call the parent constructor if you're not adding anything
// else. It will be called automatically.
public function draw() {
echo '<input>';
}
}
class textarea extends fields {
public function draw() {
echo '<textarea>';
}
}

Categories