I'm using PHP 5.4. I'm in the process of trying to make my application more SOLID. I'm currently going through my objects and making sure they follow SRP. I'm stuck on how to handle populating my object with properties, especially properties that "extend" the object's properties. Let me better explain.
I have a class called Flock (yes, a group of chickens--I'm in agriculture). It consists of several properties that are in the flocks table in the database: id, member_id, integrator_id, date_placed, date_picked_up, etc:
<?php
class Flock
{
private $id;
private $member_id;
private $farm_id;
private $integrator_id;
private $comments;
private $production_sq_ft;
private $number_of_houses;
private $avg_effective_age_of_houses;
private $date_placed;
private $date_picked_up;
private $head_started;
private $head_picked_up;
private $pounds_picked_up;
private $pounds_sold;
private $base_rate;
private $performance_rate;
private $fuel_rate;
private $other_rate;
private $feed_pounds_consumed;
public function __construct() {}
//Then a bunch of getters and setters.
}
My goal is to use the same object for both creating and retrieving a flock. However, in my database, I have created several "master" views--views that join together all lookup tables and perform any basic calculations on the data that can be performed at the row level. In this example, in my master view for flocks, I have joined the integrators table with my flocks giving me an integrator_name column in my view. The same goes for the members and farms tables. I have also found the difference in days between date_placed and date_picked_up giving me a column called total_time_in_facility. In my current version of this application, all this data is simply stored in an array and accessed using magic methods (__get). So if I wanted to get the integrator name, I would simply use $flock->integrator_name. However, if I were to use my Flock class to populate a database, I would not pass the integrator name--I would simply pass the values I've listed above.
My question is--what is the best way to get this extended data about a flock? Should I use another class to handle this (like FlockDetails)? Should I not be using this master view at all? Instead of performing any calculations in my view, should I simply be performing those within the class itself? I was under the impression that I should only be using a single class to describe a flock. If I were to create a new flock, I would use this class. If I wanted to retrieve on, I would simply populate it using a factory. But if I populate it using a factory, what about the additional details contained in my master view? Can anyone help me clear this up? Thanks!
Well, I would probably have a class Flock which represents a single row in the table "flocks" and class FlockEx which extends the class Flock by adding the fields you get as a result of the calculation in db. So, when you want to update or add a new flock to the db you use Flock class and when you retrieve flock fields along with the calculated ones you use FlockEx. Makes sense?
Related
The question hard to formulate in just one sentence when I don't have the exact terms ready for use, but I'm basically working on a Symfony 5 project that involves a MySQL database. I use Twig to allow for communication between my PHP controllers and my HTML interface. Until now, I've been doing just fine using simple references to entity fields in Twig, such as:
myEntity.someField
To get the value I needed. However, I currently need to reference a "nested" field like so :
myEntity1.myEntity2Field.someField
The "nesting" making a world of a difference between the two. I am now getting an error when trying to do this (Impossible to access an attribute ("someField") on a string variable ("<value from entity2 field>")),
probably because my database is not organized correctly yet, from what I understand. Hopefully you could understand my difficulty. So, how can I tweak my database to allow this sort of double-referencing to take place?
Note: myEntity2Field refers to the name of a field from Entity2 that should serve as a reference to the entire Entity2 table, from which someField can then be extracted.
the error you are getting is because you are trying to access a value from a string or integer, not an Object.
myEntity.someField is the same as $myEntity->getSomeField() if you have a getter Method or $myEntity->someField if you are accessing the property directly.
If someField value is not an Object you can only access the value but if its an Object you will be able to access the other object properties and methods in this way.
To do so the best way is to use association(relation) between your entities spically if you have the association already in the database and if you build your relations right in your database so you jaut have to refernce this relation or association between your entities and doctrine will do the rest for you.
as an example:
<?php
/** #Entity */
class User
{
// ...
/**
* #ManyToOne(targetEntity="Address")
* #JoinColumn(name="address_id", referencedColumnName="id")
*/
private $address;
}
/** #Entity */
class Address
{
private $street;
public function getStreet(){
....
}
}
this example is a ManyToOne relation between the user and the addresse entity with the getters methos in the user entitiy you will be able to use the nesting when you access the user:
$user->getAddress()->getStreet()
as an example and this will work in twig also:
{{user.address.street}}
https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/association-mapping.html#many-to-one-unidirectional
the other way you can get the object inside your calss and map it with methods so you can access it as you want.
i hope i will be able to help you with this info.
Is there a way to override the default behavior of SS Data Objects such that when I assign a static $table_name property to my DataObject the dev/build does not create a table name with the DO name like it normally does?
For example I have this very small Data Object
<?php
class SalesRep extends DataObject {
private static $table_name = 'tbl_users';
}
I am trying to prevent creation of table salesrep on dev/build and also I would like the ORM to know that when I do a $Model->write(); I'm writing to the table tbl_users instead of table salesrep
This is currently not possible with SilverStripe 3.x. SilverStripe uses the "convention over configuration" principle and the database tables always have the same name as the related DataObject.
However, in SS4, with namespacing, you'll be able to define a tablename in your config. As #bummzack already noted, this is currently in alpha.
However, you might try and overwrite DataObject's getBaseTable(), which method like:
/**
* Get the name of the base table for this object
*/
public function baseTable() {
return 'tbl_users';
}
but i doubt it'll work without problems, cause in other places the baseTable property is - again - generated out of the class names.
This is part of using the ORM that is within SilverStripe and can take some getting used to. I would perhaps look at this in two different ways...
1) If your goal is to present a certain name to the user, but have a different table name then the solution is to use singular_name and plural_name and then you are free to name the DataObject however you wish...
class tbl_users extends DataObject {
private static $singular_name = 'Sales Rep';
private static $plural_name = 'Sales Reps';
...
}
..remember the whole point of the ORM is that the PHP class defines the table and it would make sense to keep the table name the same as you'd like to use in the code.
2) If it absolutely has to be a specific table then you can specify it as an external table/content and one of the following solutions might suit you best... "Save to external Table", "External Content Module" or "External Data Module"
A user fills in the form and submits it. Based on the input, an object Organization is hydrated. I want to separate communication with database from the actual object.
I thought of creating an OrganizationMapper that holds the methods for database communication (save, delete...). The organization class would get the OrganizationMapper through the constructor.
With these class definitions, however, I can't instantiate the classes because of their mutual dependence.
How else could I separate the database communication from Organization and put it into OrganizationMapper?
class Organization
{
protected $id;
protected $name;
... other properties ...
public function __construct(OrganizationMapper $mapper)
{
$this->mapper = $mapper;
}
public function getId() {...}
public function setId($id) {...}
... other methods ...
public function saveToDb()
{
$this->mapper->save($this);
}
The OrganizationMapper is
class OrganizationMapper
{
public function __construct(Organization $organization)
{
$this->organization = $organization
}
... other methods
public function save($organization)
{... the code to use the methods of Organization class to save the data to the database...}
}
And that's why circular dependencies are usually considered a bad thing.
Kidding aside, it seems to me that you do not actually need the constructor dependency in the OrganizationMapper class. From the looks of it, you're passing the Organization instance that you want to persist as a parameter into the mapper's save() method anyway and shouldn't need the instance attribute $this->organization in that class at all.
In general, I'd try to keep the OrganizationMapper stateless. Try to avoid storing an Organization instance as an instance attribute (especially if you actually use that same mapper instance for persisting multiple Organizations). Just do as you already did with the save() method and pass the Organization object as a method parameter.
Also, I would not associate the Organization class with the mapper. One could argue that this violates the Single Responsibility Principle as it's not the class' responsibility to persist itself. You could move this logic to the calling code and have the Organization class not know about the mapper at all (which is nice, because you completely eliminate the circular dependency between the two classes):
class Organization
{
protected $id;
protected $name;
// <other properties here>
// <getters and setters here>
}
class OrganizationMapper
{
public function save(Organization $organization)
{
// save $organization to DB, somehow
}
}
$organization = new Organization();
$organization->setName('Foobar International Inc.');
$mapper = new OrganizationMapper();
$mapper->save($organization);
To find a better way of seperating these two concerns, think about the purposes of your two objects:
an Organization is there to give you access to all informations of an organization
your OrganizationMapper is there to save a Organization object to database.
When you think about it like this, then there's a couple of questions, that rise up:
Why does your Organization need a saveToDb() method? It's not it's job to save it?
An instance of OrganizationMapper should be able to save any Organization in the database, so why do you pass it in twice? (once in the constructor, and once in the save($organization) method). In that case - what happens, if you pass a different organization to the constructor than to the save method?
In your current example, how would you load an Organization from Database?
As alternative, I would suggest to remove saveToDb() from Organization entirely, as it's not the job of the org to save itself to database. Additionally, I would remove the current Constructor from OrganizationMapper. In it's current design, there's little reason to pass the Organization to the constructor.
Also, I would rename the OrganizationMapper to OrganizationRepository or OrganizationService. The primary purpose of that class is not to map SQL to Objects but to retrieve/save Organizations from/to DB. (Also, in OOP, classes should only follow the single responsibility pattern, so maybe the part mapping between SQL and Objects should happen in specializied class)
As a side note: generally, it's not a great idea, to give many ways to do exactly the same thing (e.g. saving an organization). This will probably just cause inconsistencies over time (consider that you will be adding some validation logic in the future, but might forget to also add it in the second place).
I hope this helps you :)
Disclaimer: I name your Organization type as OrganizationEntity in this post.
Pretty simply, it's the other way around.
The OrganisationMapper gets an OrganisationEntity object and persists it to wherever you want to, by means you can choose.
For your problem:
move the saveToDb() method from your OrganisationEntity to the OrganisationMapper and pass it an object to be saved.
I don't know why Mapper should do any opperations on DB? Mapper sounds like converting Entity (Organization) into something that can be an input for DB operation ie. Query Object.
You should rename your class into DAO or Repository. It would be better name.
IMHO, the best idea would be to have:
Organization as an object that holds domain logic
OrganizationMapper should convert your domain object into some kind of query object
OrganizationDao should take Organization as an input param and use OrganizationMapper to convert it and do operation on DB.
BTW, why you are not using some kind of an ORM like Doctrine for example? It would make your life easier :)
You can't do that in php. Imagine if it would be posibble. Then instance of Organization would have a property OrganizationMapper, which would have a property Organization. So, property of a property of an instance of the class would be the instance itself! It is only possible in languages with pointers like c++. So, I see only 2 solutions here:
Put the classes together
Have a single link (maybe have 1 class that calls another while second doesn't call first.)
I've been researching and reading a lot about working with separate layers in PHP to create maintainable and readable code.
However, I see a lot of code where the entity and the database access is placed in one class.
For example:
class User{
public $id;
public $username;
public $database;
function add(){
$database->query ....
}
}
I find this rather strange because here you are mixing the User class with database elements which makes it more difficult to maintain.
I like working like this:
a separate database class
a user class
a userData class
This works like this:
$database = new Database();
$database->openConnection();
$dataUser = new DataUser($db);
$user = new User(1,"myname");
$dataUser->saveUser($user);
So I'm wondering, am I working the right way or is the first way a better way to create code?
I find may way very easy to maintain because you have a separate entity and a separate database class to handle the database actions.
What i do :
My models are not Entities linked to the database(when i'm not using doctrine) , so no "active record" methods. An object doesnt know how to fetch its dependencies ( for instance , a user may have n comments, my model doesnt know how to get comments ).
class User{
private $name;
private $password;
// getter and setters
}
i have services that hold some business logic that can fetch models from providers, a service can have many providers.
class UserService{
function __construct(IUserProvider $userProvider){
$this->userProvider = $userProvider
}
function getUsers(){
// return an array of user objects
return $this->userProvider->getUsers();
}
}
finally i have a data provider that knows how to request datas from the database , a text file , a json file , a webservice :
class UserProvider implements IUserProvider{
function __construct(Connection $connection){
$this->connection = $connection;
}
function getUsers(){
return $this->toUsers($this->connection->fetchAssoc("Select * from users"));
}
function toUsers(array $datas){
// convert user records to an array of User
(...)
return $users;
}
}
then the interface
interface IUserProvider{
/**#return array an array of User */
function getUsers();
}
if i need to get a user comments , then my comment service knows how fetch comments from a user id. So to get a user and its comments , i need 2 requests to the database. one from the UserProvider , the other from the CommentProvider.
so i have 3 layers :
my application layer ( display users , respond to requests whatever ... )
my service layer ( which has to work with a command line interface and is not aware of my web application , except for password encoding which is usually binded to the framework i use , and ACL stuffs maybe ...)
my data access layer which knows nothing about the other layers ,
the only way my layers communicate is through Models i pass from layer to layer.
And all my classes are built with a dependency injection container, so the wiring is not a problem.
Here is an exemple of an app i made,it's open source : https://github.com/Mparaiso/silex-bookmarkly
Any thoughts welcome.
easy to maintain because you have a separate entity and a separate
database class
It appears you're saying that you wish to move away from an Active Record approach to a Data Mapper/Entity/Repository approach. That's a good direction to move in because it employs better separation of concerns. You can build this yourself but you might want to take a look at solutions like Doctrine where it allows you to do something along the lines of:
$product = new Product();
$product->setName($newProductName);
$entityManager->persist($product);
The $product entity is just a POPO (Plain Old PHP Object) that contains the record data and is unaware of how it's persisted and, when persistence is needed, is passed into the entity manager to take care of the storing.
Personally, I think abstracting UserData from User is likely to be overkill. As, in this case, UserData is likely to be very similar to ProductData for example - they're still going to contain an add($data), find($id) etc.
In your case, User is a model in the MVC approach, and is totally acceptable to contain Database store/retrieve logic. You will however likely find that you are, again recreating the same DB methods in the User class that you have in other Models. This is where you may start to look at an ORM implementation. Whereby the common DB access methods are defined in an abstract class that all your models then extend and override as necessary.
Please be brutally honest, and tear my work apart if you have to.
So I'm re-writing a small web-application that I recently made. The reason for this is simply that the code got pretty messy and I want to learn and apply better OO design. What this application should do is just simple CRUD.
I have a database with 3 tables, companies and partners which are in no relation to each other and city which has a 1:n relation with companies and partners. Very simple, really. Now, I have several questions which i will state at the end of my post. Here i'll just try to explain:
My first approach was that I created classes company, partner and city, fetched all datasets from the database and created objects from that:
class company {
private $id = null;
private $name = null;
private $city = null;
//many more attributes
function __construct( $id, $name, $city, [...] ) {
$this->id = $id;
$this->name = $name;
$this->city = $city;
//huge constructor
}
/*
* getters + setters here
*
* no need to paste the partner class as it looks just like this one
*
*/
}
And that is all these classes did. I fetched every dataset from the database and constructed company, partner and city objects (the attribute city within these classes is an object with several attributes itself) and saved them into two arrays arr_companies and arr_partners, which then held these objects...and it worked fine like that.
Now, what I wanted is to update, insert, delete into the database, and all 3 classes (city, company, partner) need this functionality. My approach was that I created a new class with a constructor that would basically take 2 strings command and object, e.g. ('update', 'company') and it would then update the company directly in the database leaving my objects untouched. That made me really sad, because I had such nicely constructed objects and I didn't know how to make use of them.
Questions:
Is it bad to have such huge constructors (my biggest one would take
28 parameters)?
Should you have a separate class for database
operations or is it better to have maybe an abstract class or
interface for it and let the subclasses themselves handle update, delete, insert?
Is it common to just write, delete from the database whenever or should I just apply these changes to my objects and only execute the commands to the database later, for example when the session ends?
I figure an application like this must have been done a fantastillion times before. What is the proper approach here? create objects, work with objects, save them to the database?
I have so many questions but I think many of them I just don't know how to ask.
Please note that if possible I would not like to use an ORM at this point.
Thank you very much for your time.
Questions posed in OP:
"Is it bad to have such huge constructors (my biggest one would take 28 parameters)"?
Yes. Imagine the calling code. You would have to pass 28 different values, not to mention each call would have to respect the exact order specified in the constructor. If one parameter was out of place, you could wreck havoc with parameter dependent algorithms. If you really need to pass a large number of parameters, I would recommend passing them in as an array (posted an example to another SO question).
"Should you have a separate class for database operations or is it better to have maybe an abstract class or interface for it and let the subclasses themselves handle update, delete, insert?"
Generally speaking, when creating classes, you want to try to identify the nouns that best represent your business needs. In your specific case you would probably have three classes; Company, Partner, and City.
Now within each class (noun), your methods would be in the form of verbs, so symantically your calling code makes sense: if ($company->getName() === 'forbes')
As you mentioned, each class needs a database object (dbo) to work with, so you could implement any number of patterns to expose datase connections to your classes; singleton, singleton with factory, or dependency injection, etc.
Abstract (parent) classes are great for sharing common algorithms across child classes, and should be identified when you are in the psuedo-code stage of your design. Parent classes also allow you to force child classes to have methods by declaring abstract methods within the parent.
Interfaces are a useful tool in certain situations, but I find they are less flexible than declaring abstract methods in parent class. But are good in situations where classes do not share a common parent.
"Is it common to just write, delete from the database whenever or should I just apply these changes to my objects and only execute the commands to the database later, for example when the session ends"?
CRUD activity should happen at the time the action is executed. If you wait for the session to end, you may run into situations where a session is pre-maturely ended due to a user closing a browser, for example. To better protect your data you can wrap your CRUD activity within transactions.
If you are running a high-traffic application, you can implement a queuing system and queue up the work to be done.
"I figure an application like this must have been done a fantastillion times before. What is the proper approach here? create objects, work with objects, save them to the database"?
You are correct, this has been done before, and are commonly referred to as ORMs (object relation mappers). Basically, an ORM will introspect your database schema, and create objects (and relations) which represent your schema. So instead of working with native SQL, you are working with objects. Although you can use SQL for custom business needs, but in the case of Doctrine, you would use Doctrine Query Language (DQL) vs native SQL.
An ORM I would highly recommend is Doctrine.
If you do not want to use an ORM, you can add CRUD methods to your primary classes. I Opted for an interface so your classes don't have to extend from a parent comprised of database operations. Also, check out this post on using a singleton/factory for exposing your classes database object(s).
Consider the following:
// Company.php
class Company implements iDatabaseOperation
public function delete()
{
// Lets use a DBO singleton/factory for DB access
// Uses PDO, which is strongly recommended
$dbo = Database::factory(Database::DATABASE_NAME);
$dbo->beginTransaction();
try {
$sql =
"DELETE FROM " .
" company " .
"WHERE " .
" id = :companyId " .
"LIMIT 1";
$stmt = $dbo->prepare($sql);
$stmt->bindValue(':companyId', $this->getId());
$stmt->execute();
$dbo->commit();
} catch (Exception $e) {
$dbo->rollback();
error_log($e->getMessage();
$e = null; // Php's garbage collection sucks
}
}
}
// iDatabaseOperation.php
interface iDatabaseOperation
{
public function delete();
public function update();
public function insert();
}
It is realy bad. Code is completele unreadable in this case. You have options
to use setters (can add validation logic inside, better readability, no need to fill empty fields with null)
to have separate class builder for each domain class (takes some memory for additional object). Example in java hope you can understand:
class CompanyBuilder {
private final Company c;
public CompanyBuilder() {
c = new Company();
}
CompanyBuilder addId(String id){c.id = id;}
// id should be package visible and class should be located in the same package with builder
CompanyBuilder addName(String name){...}
CompanyBuilder addCity(String city){...}
Company build(){ return c;}
}
hybrid solution to have methods to organise chain(worse debugging, better readability). In java will be methods:
class Company {
...
Company addId(String id){
this.id = id;
return this;
}
Company addName(String name){...}
...
}
Usage:
Company c = new Company().addId("1").addName("Name1");
maybe you can create more granular objects to reuse them later and add specific logic in correct place. For instance it can be Address(Location) object for company.
Follow single responsibility principle. SOLID description on wiki.
It helps to change database specific code without affection of other part of system in your case. Well, separate domain and database specific code, have common interface or abstract class(if you have common logic for all of domain classes - liskov principle). In subclasses implement domain specific part.
If you do not want to lose data you should save them each time or have cluster of servers or have distributed cache. If it is ok to lose save them in the end of session as batch. It will increase youre performance. Also you should save in transaction each time if you have concurrent updates.
Approach is get data from database/construct objects from this data or new objects/ work(update) objects/write data from objects to database
just write more code and read stackoverflow
Finally I suggest to read "Clean Code: A Handbook of Agile Software Craftsmanship" R.Martin.
You are essentially writing your own ORM. So, I wouldn't discount just switching to one that's already been written for you. The advantage to rolling your own is that you gain an understanding of how it works as your write it. But the disadvantage is that someone else has probably already done it better. But assuming you want to continue on...
General Advice: Remember to always break the problem down into simpler and simpler pieces. Each class should only perform a simple function. Also, you should not have to worry about caching updates... unless perhaps your database is on the other end of a remote connection over a modem.
Specific Advice follows:
I would setup your entity instance classes to house data and not to do a lot of data loading. Use other classes and logic for loading the data. I would use the constructor of the entity class only to populate the data that pertains to the class (and it's children).
A simple thing to do is to use static methods on the entity class for loading and saving data. E.g.
class city {
private $id = null;
private $name = null;
function __construct( $id, $name ) {
$this->id = $id;
$this->name = $name;
}
// getters and setters
...
// ---------------------
// static functions
// ---------------------
public static function loadById($cityId) {
// pull up the city by id
$retval = new city(row["id"], row["name"]);
// close db connection
return $retval;
}
public static function loadByCustomerId($customerId) {
// pull up multiple cities by customer id
// loop through each row and make a new city object
// return a hash or array of cities
}
public static function update($city) {
// generate your update statement with $city->values
}
// other methods for inserting and deleting cities
...
}
So now the code to get and update cities would look something like this:
// loading city data
$city = city::loadById(1); // returns a city instance
$cities = city::loadByCustomerId(1); // returns an array of city instances
// updating city data
$city->name = "Chicago"; // was "chicago"
city::update($city); // saves the change we made to $city
The static methods are not the best way to implement this, but it gets you pointed in the right direction. A repository pattern would be better, but that's beyond the scope of this one answer. I find that often I don't see the merit in a more involved solution like the repository pattern until I run into problems with the simpler solutions.
What you are doing looks greate. What you can add is an intermediate layer which maps your business object to your database(object relation mapping). There are a lot of object relational mapping api out there. Check this wikipedia list for ones you can use for PHP
I think a constructor with 28 parameters is too much, you should others classes managing some attributes having some stuff in common. You should give us what kind of others attributes you instanciated, and it could help you to find a way to make more common objects.
I think you should also create a class managing the operations and the database like a DBHandler with delete, update, and so on..
In my opinion, do modifications on tuples in your database directly after functions are called are important.
Why? Because it could avoid conflict, like the case you try to update an object which is supposed to be deleted for example, if you do modifications on your database at the end.
You might want to look at ruby on rails.
You don't necessarily have to switch over to it, but look at how they implement the MVC pattern and achieve CRUD.