Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CRUD and OOD. How to approach this?

Tags:

oop

php

mysql

crud

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.

like image 847
drwww Avatar asked Jan 11 '12 19:01

drwww


People also ask

What is CRUD approach?

CRUD Meaning: CRUD is an acronym that comes from the world of computer programming and refers to the four functions that are considered necessary to implement a persistent storage application: create, read, update and delete.

How do you perform CRUD?

CRUD refers to the four basic operations a software application should be able to perform – Create, Read, Update, and Delete. In such apps, users must be able to create data, have access to the data in the UI by reading the data, update or edit the data, and delete the data.

What are CRUD tools?

In computer programming, create, read, update, and delete (CRUD) are the four basic operations of persistent storage. CRUD is also sometimes used to describe user interface conventions that facilitate viewing, searching, and changing information using computer-based forms and reports.

Why is CRUD useful?

CRUD has a number of advantages, including: It simplifies security control by meeting a variety of access criteria. It makes application design easier and more scalable by simplifying and facilitating it. When compared to ad-hoc SQL statements, it performs better.


1 Answers

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();
}
like image 73
Mike Purcell Avatar answered Sep 30 '22 11:09

Mike Purcell