Constructing objects for external libraries using a model in Laravel I want to know if it's more appropriate to use a separate class (such as a factory?) to construct an object. While the code works, I am concerned about bloating of the model and the tight coupling.

To construct the said object I need:


environment variables like api tokens
some of the user's attributes from the model
classes from the library


Here's the relevant snippet within my user model that creates an AdWordsSession object for use in the third-party library:

class User extends Authenticatable {
...
   public function adWordsSession($customer_id = null){
        if(!$this-&gt;google_auth_token) {
            return null;
        }

        if( $this-&gt;adWordsSesssion &amp;&amp;
            (
                (isset($customer_id) &amp;&amp; $this-&gt;adWordsSesssion-&gt;getClientCustomerId() == $customer_id) ||
                (!isset($customer_id) &amp;&amp; $this-&gt;adWordsSesssion-&gt;getClientCustomerId() == $this-&gt;adwords_customer_id)
            )
        ){
            return $this-&gt;adWordsSesssion;
        }

        $oAuth2Credential = (new OAuth2TokenBuilder)
            -&gt;withClientId(env('ADWORDS_CLIENT_ID'))
            -&gt;withClientSecret(env('ADWORDS_CLIENT_SECRET'))
            -&gt;withRefreshToken($this-&gt;google_auth_token)
            -&gt;build();

        $session = (new AdWordsSessionBuilder())
            -&gt;withDeveloperToken(env('ADWORDS_DEVELOPER_TOKEN'))
            -&gt;withUserAgent(env('ADWORDS_USER_AGENT'))
            -&gt;withClientCustomerId($customer_id ?: $this-&gt;adwords_customer_id)
            -&gt;withOAuth2Credential($oAuth2Credential)
            -&gt;build();

        $this-&gt;adWordsSesssion = $session;

        return $session;
    }
...
}


I am also interested to know if it applies to the reverse, using a class returned from the library (web service) to construct a model object. Should this be a static method of the model or a separate factory class. Code follows:

class AdWordsCampaign {
    public static function fromAdWordsClass(Campaign $campaign, AdWordsCampaign $adWordsCampaign = null): AdWordsCampaign {

        $self = $adWordsCampaign;

        if(is_null($adWordsCampaign)) {
            $self = new self;
            $self-&gt;criterions = $self-&gt;defaultCriterions();
            $self-&gt;extensions = $self-&gt;defaultExtensions();
        }

        if($campaign-&gt;getId()) {
            $self-&gt;fieldsHelper()-&gt;id = $campaign-&gt;getId();
            $self-&gt;setPublished();
        }

        $self-&gt;fieldsHelper()-&gt;name = $campaign-&gt;getName();
        $self-&gt;fieldsHelper()-&gt;status = $campaign-&gt;getStatus();
        $self-&gt;fieldsHelper()-&gt;advertisingChannelType = $campaign-&gt;getAdvertisingChannelType();
        $self-&gt;fieldsHelper()-&gt;advertisingChannelSubType = $campaign-&gt;getAdvertisingChannelSubType();

        $self-&gt;fieldsHelper()-&gt;budget = arrayify_object(
            $campaign-&gt;getBudget() ?
                $campaign-&gt;getBudget() :
                CampaignFields::defaultBudget()
        );

        return $self;
    }
}
I would implement this as a service in Laravel, and use IOC to resolve my dependencies.

I would make a service, called AdWordsCampaign. This would resolve its dependencies in constructor, namely OAuth2TokenBuilder and AdWordsSessionBuilder, although these two classes are good candidates for services themselves (a factory pattern is most of times is a sign you should abstract creation of class into a service provider).

Then I would implement a method in this service, adWordsSession which takes two parameters: a User instance and $customer_id. Then it has everything it needs to to its job.

I would also implement the reverse case using a service. Semantics are the same.

As for static method, I would avoid them. If you like them, use a Facade. They enable you to use a service anywhere you want.

I strongly suggest to read Laravel docs about services and providers and IOC and Facades. It will give you enough insight about how they work, and where to use them.

As a rule of thumb, whenever you see yourself using new * in your codes, it seems your could use a service/provider and inject it.