

Overview — phx\_gen\_solid v0.3.0

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/guides/overview.md#L1 "View Source")

Overview

===============================================================================================================================

> Still early in development & subject to change

> 

> 

`mix phx.gen.solid` exists to generate the boilerplate usually required when

utilizing the SOLID principles, outlined below, in a larger phoenix project.

By default it provides fairly general templates for each of the handlers,

services, finders, and values. However, all of the templates are completely

overrideable.

[currently-supported-generators](#currently-supported-generators)

 Currently Supported Generators

--------------------------------------------------------------------------------------------------

* [`Mix.Tasks.Phx.Gen.Solid.Value`](Mix.Tasks.Phx.Gen.Solid.Value.html) - used to generate a value

* `Mix.Tasks.Phx.Gen.Solid.Handler` - TODO

* [`Mix.Tasks.Phx.Gen.Solid.Service`](Mix.Tasks.Phx.Gen.Solid.Service.html) - used to generate C~~R~~UD services

* `Mix.Tasks.Phx.Gen.Solid.Finder` - TODO

[solid-principles](#solid-principles)

 SOLID Principles

--------------------------------------------------------

The best way to contain cyclomatic complexity is by employing SOLID principles whenever applicable:

> Single-responsibility principle - A class/module should only have a single responsibility

> 

> 

> Open-closed principle - Software entities should be open to extension but closed to modification

> 

> 

> Liskov Substitution principle - Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.

> 

> 

> Interface Segregation principle - Many client-specific interfaces are better than one general-purpose interface.

> 

> 

> Dependency inversion principle - Abstractions over concretions

> 

> 

[4-patterns](#4-patterns)

 4 Patterns

--------------------------------------

A way to enforce the SOLID principles is by implementing a combination of 4

design patterns and their interactions to guide codebase scalability.

* Handlers

* Services

* Finders

* Values

![Pattern Interaction Map](assets/patterns.png)

### 

[handlers](#handlers)

 Handlers

Handlers are orchestators. They exist only to dispatch and compose. It orders

execution of tasks and/or fetches data to put a response back together.

**Do**

* Organize by business logic, domain, or sub-domain

* Orchestrate high level operations

* Command services, finders, values or other handlers

* Multiple public functions

* Keep controllers thin

* Make it easy to read

* Flow control (if, case, pattern match, etc.)

**Don't**

* Directly create/modify data structures

* Execute any read/write operations

Below is an example of a handler that creates a user, sends a notification, and

fetches some data.

```

defmodule Remoteoss.Handler.Registration do

 alias Remoteoss.Accounts.Service.{CreateUser, SendNotification}

 alias Remoteoss.Accounts.Finder.SuperHeroName

 def setup\_user(name) do

 with {:ok, user} <- CreateUser.call(name),

 :ok <- SendNotification.call(user),

 super\_hero\_details <- SuperHeroName.find(name) do

 {user, super\_hero\_details}

 else

 error ->

 error

 end

 end

end

```

### 

[services](#services)

 Services

Services are the execution arm. Services execute actions, write data, invoke

third party services, etc.

**Do**

* Organize by Application Logic

* Reusable across Handlers and other Services

* Commands services, finders and values

* Focuses on achieving one single goal

* Exposes a single public function: `call`

* Create/modify data structures

* Execute and take actions

**Don't**

* Use a service to achieve multiple goals

* Call Handlers

* If too big you need to break it into smaller services or your service is

actually a handler

Below is an example of a service that creates a user.

```

defmodule Remoteoss.Accounts.Service.CreateUser do

 alias Remoteoss.Accounts

 alias Remoteoss.Service.ActivityLog

 require Logger

 def call(name) do

 with {:ok, user} <- Accounts.create\_user(%{name: name}),

 :ok <- ActivityLog.call(:create\_user) do

 {:ok, user}

 else

 {:error, %Ecto.Changeset{} = changeset} ->

 {:error, {:invalid\_params, changeset.errors}}

 error ->

 error

 end

 end

end

```

### 

[finders](#finders)

 Finders

Finders fetch data, they don't mutate nor write, only read and present.

Non-complex database queries may also exist in Phoenix Contexts. A query can be

considered complex when their are several conditions for filtering, ordering,

and/or pagination. Rule of thumb is when passing a params or opts Map variable

to the function, a Finder is more appropriate.

**Do**

* Organized by Application Logic

* Reusable across Handlers and Services

* Focuses on achieving one single goal

* Exposes a single public function: `find`

* Read data structure

* Uses Values to return complex data

* Finders only read and look up data

**Don't**

* Call any services

* Create/modify data structures

Below is an example of a finder that finds a user.

```

defmodule Remoteoss.Accounts.Finder.UserWithName do

 alias Remoteoss.Accounts

 def find(name) when is\_binary(name) do

 case Accounts.get\_user\_by\_name(name) do

 nil -> {:error, :not\_found}

 user -> {:ok, user}

 end

 end

 def find(\_), do: {:error, :invalid\_name}

end

```

### 

[values](#values)

 Values

Values allow us to compose data structures such as responses,

intermediate objects, etc.

**Do**

* Organize by Application Logic

* Reusable across Handlers, Services, and Finders

* Focuses on composing a data structure

* Exposes a single public function: `build`

* Use composition to build through simple logic

* Only returns a [`List`](https://hexdocs.pm/elixir/List.html) or a [`Map`](https://hexdocs.pm/elixir/Map.html)

**Don't**

* Call any Services, Handlers or Finders

Below is an example of a value that builds a user object to be used in a JSON

response. Note this utilizes the helper functions generated with

[`Mix.Tasks.Phx.Gen.Solid.Value`](Mix.Tasks.Phx.Gen.Solid.Value.html).

```

defmodule Remoteoss.Accounts.Value.User do

 alias Remoteoss.Value

 @valid\_fields [:id, :name]

 def build(user, valid\_fields \\ @valid\_fields)

 def build(nil, \_), do: nil

 def build(user, valid\_fields) do

 user

 |> Value.init()

 |> Value.only(valid\_fields)

 end

end

```

[← Previous Page

 

API Reference](api-reference.html)





PhxGenSolid.Generator — phx\_gen\_solid v0.3.0

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/phx_gen_solid/generator.ex#L1 "View Source")

PhxGenSolid.Generator

(phx\_gen\_solid v0.3.0)

=================================================================================================================================================================================

[Link to this section](#summary)

 Summary

==========================================

[Functions](#functions)

------------------------

[copy\_new\_files(context, binding, paths, files\_fn)](#copy_new_files/4)

[copy\_new\_files(context, binding, paths, files\_fn, opts)](#copy_new_files/5)

[paths()](#paths/0)

[prompt\_for\_conflicts(context, files\_fn)](#prompt_for_conflicts/2)

[prompt\_for\_conflicts(context, files\_fn, opts)](#prompt_for_conflicts/3)

[raise\_with\_help(msg)](#raise_with_help/1)

[web\_app\_name(context)](#web_app_name/1)

[Link to this section](#functions)

Functions

=============================================

[Link to this function](#copy_new_files/4 "Link to this function")

copy\_new\_files(context, binding, paths, files\_fn)

====================================================

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/phx_gen_solid/generator.ex#L18 "View Source")

[Link to this function](#copy_new_files/5 "Link to this function")

copy\_new\_files(context, binding, paths, files\_fn, opts)

==========================================================

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/phx_gen_solid/generator.ex#L25 "View Source")

[Link to this function](#paths/0 "Link to this function")

paths()

=======

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/phx_gen_solid/generator.ex#L8 "View Source")

[Link to this function](#prompt_for_conflicts/2 "Link to this function")

prompt\_for\_conflicts(context, files\_fn)

==========================================

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/phx_gen_solid/generator.ex#L32 "View Source")

[Link to this function](#prompt_for_conflicts/3 "Link to this function")

prompt\_for\_conflicts(context, files\_fn, opts)

================================================

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/phx_gen_solid/generator.ex#L38 "View Source")

[Link to this function](#raise_with_help/1 "Link to this function")

raise\_with\_help(msg)

======================

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/phx_gen_solid/generator.ex#L44 "View Source")

[Link to this function](#web_app_name/1 "Link to this function")

web\_app\_name(context)

=======================

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/phx_gen_solid/generator.ex#L12 "View Source")





mix phx.gen.solid.service — phx\_gen\_solid v0.3.0

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/mix/tasks/phx.gen.solid.service.ex#L1 "View Source")

mix phx.gen.solid.service

(phx\_gen\_solid v0.3.0)

=============================================================================================================================================================================================

Generates C~~R~~UD Services for a resource.

```

mix phx.gen.solid.service Accounts User users

```

The first argument is the context module followed by the schema module and its

plural name.

This creates the following services:

* `MyApp.Accounts.Service.CreateUser`

* `MyApp.Accounts.Service.UpdateUser`

* `MyApp.Accounts.Service.DeleteUser`

For more information about the generated Services, see the [Overview](overview.html).

[Link to this section](#summary)

 Summary

==========================================

[Functions](#functions)

------------------------

[raise\_with\_help(msg)](#raise_with_help/1)

[Link to this section](#functions)

Functions

=============================================

[Link to this function](#raise_with_help/1 "Link to this function")

raise\_with\_help(msg)

======================

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/mix/tasks/phx.gen.solid.service.ex#L54 "View Source")





mix phx.gen.solid.value — phx\_gen\_solid v0.3.0

 try {

 var settings = JSON.parse(localStorage.getItem('ex\_doc:settings') || '{}');

 if (settings.theme === 'dark' ||

 ((settings.theme === 'system' || settings.theme == null) &&

 window.matchMedia('(prefers-color-scheme: dark)').matches)

 ) {

 document.body.classList.add('dark')

 }

 } catch (error) { }

 

Settings

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/mix/tasks/phx.gen.solid.value.ex#L1 "View Source")

mix phx.gen.solid.value

(phx\_gen\_solid v0.3.0)

=========================================================================================================================================================================================

Generates Value logic for a resource.

```

mix phx.gen.solid.value Accounts User users id name age

```

The first argument is the context module followed by the schema module and its

plural name.

This creates a new Value in `MyApp.Accounts.Value.User`. By default the

allowed fields for this value will be the arguments you passed into the

generator, in this case, `@valid_fields [:id, :slug, :name]`.

**Options**

* `--helpers` - This will generate the Value helpers context in `MyApp.Value`.

 Module name can be overridden by `--value-context`.

* `--value-context MODULE` - This will be the name used for the helpers alias

 and/or helper modue name when generated. Defaults to `MyApp.Value`.

The generated Value relies on a few helper functions also generated by this

task. By default it will be placed in your projects context folder.

For more information about the generated Value, see the [Overview](overview.html).

[Link to this section](#summary)

 Summary

==========================================

[Functions](#functions)

------------------------

[raise\_with\_help(msg)](#raise_with_help/1)

[Link to this section](#functions)

Functions

=============================================

[Link to this function](#raise_with_help/1 "Link to this function")

raise\_with\_help(msg)

======================

[View Source](https://github.com/remoteoss/phx_gen_solid/blob/v0.3.0/lib/mix/tasks/phx.gen.solid.value.ex#L68 "View Source")

