Is this the preferable OOP way to achive this CRUD functions or can I reduce one layer & combine Code & DataAccess layer to make it more simple?
The 3 layer method (Interface "U.I.", Business logic "Code" & Data Access), is the suggested way to do things.
You'll find that there are several business apps. that use the "2 layer" method that you suggested. If your think that application is going to "grow", you should use the 3 layer instead.
But, have in mind, that its complexity will also increase.
You may also want to get (download, develop, buy) a separate tool program that reads a database or data access, and generates your entity classes from it, instead of programming all by yourself.
If possible, do the same, for the "Code" or "Business logic" entities.
One more thing, avoid putting all you entities, in a single file.
Use a file per entity, instead. Make, unleast, a single "GUI" folder for your interface or "boundary" classes,
a folder for your "Code" classes, and a folder for your "Data Access" classes.
Your website or application may be small, and this suggestions may seen very complex nad unnecesary.
But, by experience, apps. tend to grow, even "pet" or "personal" websites, unexpectly may grow, and become complex.
Even, if its a personal, small project, you may try to use the suggestions, in order to be prepare for large websites or apps.
Additional Suggestion
One trick I learn from a coworker, to make code more maintainable, its to use a program that generates the entities code, automatically, and, later, not make instances of those class entities, as usually done in the 3 layer method.
Instead, a second class entity was code, usually manually, adding some members or features, that may be updated regularly.
So the first (parent) class have the members that can be obtained from the database (or XML file), and the second (child) class, has the members that may not be obtained from the database, and also require to do a lot of changes, that require to be "coded by hand".
Example:
(1) You have a database table (or XML file or local file) like this:
CREATE TABLE User
(
integer UserKey primary key,
varchar(20) UserAlias,
varchar(250) UserPasword,
integer UserIsActive, -- My D.B. doesn't support boolean
)
(2) You generate a Data-Access-Layer entity like this, wheter manually or tool-generated:
abstract class FieldsUserDataAccessEntityClass
{
/* integer */ protected $fieldUserKey = 0;
/* string */ protected $fieldUserAlias = "";
/* string */ protected $fieldUserPassword = "";
/* integer */ protected $fieldUserIsActive = 0;
/* integer */ public function CalculateNewKey();
/* void */ public function Insert();
/* void */ public function InsertWithKey(/* integer */ $newKey);
/* void */ public function Update();
/* void */ public function Delete();
} // class
This previous class is commonly used directly (without the "abstract" feature).
But, the suggestiuon is, that in other file, this, (I skip the methods code):
/* concrete */ class UserDataAccessEntityClass extends FieldsUserDataAccessEntityClass
{
public /* integer */ function getUserKey();
public function setUserKey(/* integer */ $newValue);
public /* string */ function getUserAlias();
public function setUserAlias(/* string */ $newValue);
public /* string */ function getUserPassword();
public function setUserPassword(/* string */ $newValue);
public /* string */ function getUserPassword();
public function setUserPassword(/* string */ $newValue);
public /* bool */ function getUserIsActive();
public function setUserIsActive(/* bool */ $newValue);
} // class
...
/* void */ function GlobalDoSomething()
{
/* UserDataAccessEntityClass */ $CurrentUser = new UserDataAccessEntityClass();
/* integer */ newKey = $CurrentUser->CalculateNewKey();
$CurrentUser->setUserKey(newKey);
$CurrentUser->setUserName("JohnDoe");
$CurrentUser->setUserPassword("a9b8c7d6e5f4");
$CurrentUser->setUserIsActive(true);
$CurrentUser->Insert();
$CurrentUser = null;
} //
...
I use the casting of the "IsActive" field from "integer" to "boolean", as an example,
could be other stuff like truncating a string that is too long.
Some developers will complain, and suggest to do this in the business logic entity.
(3) You generate a Business-Logic-Layer entity like this, wheter manually or tool-generated:
abstract class FieldsUserLogicAccessEntityClass
{
/* integer */ protected $fieldUserKey = 0;
/* string */ protected $fieldUserAlias = "";
/* string */ protected $fieldUserPassword = "";
/* integer */ protected $fieldUserIsActive = 0;
/* void */ public function DoSomeThing();
} // class
In other file, this, (I skip the methods code):
class UserLogicAccessEntityClass extends FieldsUserLogicAccessEntityClass
{
public /* integer */ function getUserKey();
public function setUserKey(/* integer */ $newValue);
public /* string */ function getUserAlias();
public function setUserAlias(/* string */ $newValue);
public /* string */ function getUserPassword();
public function setUserPassword(/* string */ $newValue);
public /* string */ function getUserPassword();
public function setUserPassword(/* string */ $newValue);
public /* bool */ function getUserIsActive();
public function setUserIsActive(/* bool */ $newValue);
/* void */ public function DoAnotherThing();
} // class
...
/* void */ function GlobalDoSomething()
{
/* UserLogicAccessEntityClass */ $CurrentUser = new UserLogicAccessEntityClass();
$CurrentUser->setUserName("JohnDoe");
$CurrentUser->setUserPassword("a9b8c7d6e5f4");
if ($CurrentUser->TryLogin())
{
echo "Welcome !!!";
}
else
{
echo "Security Alert !!!";
}
$CurrentUser = null;
} //
...
These method helps a lot when, you have to add or remove or update fields in the database, but, its more complex, so a entity generator is required.
The idea its that a tool generates the "abstract with fields" entity classes,
and you modify manually the "concrete child" entity classes, when required.
And in real world programming, modifying hte entities manually, happens a lot.
Is it ok to instanciate User class more than once in ManageUser page (one instance for Add, one for Edit and so on) or should instanciate it only once for a single page?
Its ok, to instantiate an entity class, several times, but, its more common, to have them as temporally objects int methods. In case of objects like the "currently logged user", you may use a "singleton" object.
UserfromUserDataAccess? Allows you to keep your specialized code separate (good!) but still seemingly reduce one layer from your application.UserDataAccesswithout changingUsertoo.