Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

cristian9509's avatar

Coding SOLID with multiple classes

I currently have this setup: ConnectionInterface (XmlConnection or DbConnection). My data provider currently uses a XmlConnection but that may change.

XmlConnection can download many xml files with different content. That content must individually be proccessed and modified to be able to be displayed on my page and also be written in my own database. Therefore I would need something like this XmlTimes and XmlSpeeds and I might add more later (XmlConstruction, etc). If my provider changes to a Db then I would have DbTimes and DbSpeeds plus anything else that I would add later. These classes contain theodifications needed to make data consistent so I can write it to my database.

So when I build for example my TimesRepository all my ideas break the open closed principle.

ConnectionInterface is bind with XmlConnection

TimesRepository Construct with ConnectionInterface and an XmlTimes object.

If my provider changes to a DbConnection i then bind ConnectionInterface with DbConnection but then inside my TimesRepository I would have to change to a DbTimes object. therefore I break open closed principle.

How can I make it then SOLID?

My code:

<?php namespace App\Repositories\Traffic;

interface ConnectionInterface {
    public function setSource($source);
    function connect();
}
<?php namespace App\Repositories\Traffic;

class XmlConnection implements ConnectionInterface {    
    private $username, $password;
    private $curlConn;
    private $source = NULL;

    public function __construct()
    {
        $this->username = env('XML_CONNECTION_USERNAME');
        $this->password = env('XML_CONNECTION_PASSWORD');
        $this->curlConn = curl_init();
    }

    public function setSource($source)
    {
        $this->source = $source;
    }

    public function connect()
    {
        if($this->source == NULL)
            return 'Error';

        $url = 'https://...';
        curl_setopt($this->curlConn, CURLOPT_URL, $url . $this->source);

        curl_setopt($this->curlConn, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($this->curlConn, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($this->curlConn, CURLOPT_HEADER, 0);
        curl_setopt($this->curlConn, CURLOPT_USERPWD, $this->username . ':' . $this->password);

        $curlOut = curl_exec($this->curlConn);
        curl_close($this->curlConn);

    // file is gz archived
        return gzdecode($curlOut);
    }
}

Next I need to build a class that contains all the modifications I need for XmlTimesRepository (and of course for the other Repositories I would need) and then I guess I need another class TimesRepository which deals with the data after it was modified and does not know where the data came from XML or from a DB. This is where I am stuck!

0 likes
8 replies
cristian9509's avatar

@olimorris I just added some code. I watched all the SOLID videos here on laracasts and currently I am struggling with the open-closed principle. In the video Jeff shows exactly how the principle works but does not provide the example on exactly how would you implement it completely (the Checkout example). I know what I should do (at least, I think I know) but I don't know how to do it!

olimorris's avatar

Ahhh I see. It's a bit clearer now. Could you not just use a service class to bring all of the repositories together? Also, it may be possible to refactor some functionality out of all of the repositories and put it into an abstract repository

cristian9509's avatar

@JarekTkaczyk Okay, let's try again!

ConnectionInterface
    - XmlConnection
        - Modifications for XML DataSource1
        - Modifications for XML DataSource2
        - ...
        - Modifications for XML DataSourceN

    - DbConnection
        - Modifications for Database DataSource1
        - Modifications for Database DataSource2
        - ...
        - Modifications for Database DataSourceN

All the "Modifications" classes should implement a general ModificationsInterface. That should contain a few functions plus some specific member variables that holds info such as source file (XML) or source table (DB) and what exactly needs to be modified.

XML DataSource1 and Database DataSource1 yelds same data only from different source type. Therefore I need to have different implementations for both since nodes names in the XML may differ from field names in the Database.

DataRepository - will make the connection using whatever class is bind to the ConnectionInterface, and based on what DataSource is requested, will make necessary modifications and return data that is consistent with my own Database (field names, etc).

My questions is this: How can I design so that when my data provider changes from XML to a Database connection, I just bind my DbConnection (which I will build, along with the necessary Modifications for DataSources) and then everything should work properly?

This way I don't break the the open-closed principle!

My current setup is like this:

ConnectionInterface is bind to XmlConnection

DataRepository for DataSourceX
- Connect using the ConnectionInterface
- modify data using the Modifications for XML DataSourceX
- return data consistent with my own Database

If I have to change to DbConnection:

ConnectionInterface is bind to DbConnection

DataRepository for DataSourceX
- Connect using the ConnectionInterface
- modify data using the Modifications for Database DataSourceX ************** breaking open-close principle
- return data consistent with my own Database
jekinney's avatar

Yes an abstract class that houses all the duplicate code is the way to go imo. Many times you need the find method, put your methods like that in your abstract class then extend it. Pulls together through the constructor and you'll have access to those methods.

JarekTkaczyk's avatar

@cristian9509 Still I don't see the issue. What is the flow there? I guess you have an interface doing this:

/**
 * @return Some\Interface\Or\DataObject
 */
public function getDataSource();

Now, your DbConnection and XmlConnection returns the same interface or dataObject, so it doesn't matter what happens under the hood. The only thing you have to do is swapping the interface binding in the IoC. No need to change anything in the code.

Please or to participate in this conversation.