Style Guide
Coding Style: PSR-12
General Overview
As stated in the PHP-Fig PSR-2 Coding Style Guide the PSR-2 Standard is deprecated as of 2019-08-10. Hence we should use PSR-12 which extends, expands and replaces PSR-2, the coding style guide and requires adherence to PSR-1, the basic coding standard.
Furthermore it is advised to stick to the PSR4 autoloading standard.
I will try to give a brief overview over these standards in this document .
To illustrate how code should be formatted, a short example is given below:
Files and Lines
- MUST use the Unix LF (linefeed) line ending only.
- MUST end with a non-blank line, terminated with a single LF.
- MUST have an opening
<?php
tag and the closing ?> tag MUST be omitted from files containing only PHP.
- MUST use only UTF-8 without BOM for PHP code
- The header of a PHP file may consist of a number of different blocks. If present, each of the blocks below MUST be separated by a single blank line
- Each block MUST be in the order listed below, although blocks that are not relevant may be omitted. → see PSR-12 Code Example
- There MUST NOT be a hard limit on line length. The soft limit on line length MUST be 120 characters.
- Lines SHOULD NOT be longer than 80 characters; lines longer than that SHOULD be split into multiple subsequent lines of no more than 80 characters each.
- There MUST NOT be trailing whitespace at the end of lines.
- Blank lines MAY be added to improve readability and to indicate related blocks of code except where explicitly forbidden.
- There MUST NOT be more than one statement per line.
- Code MUST use an indent of 4 spaces for each indent level, and MUST NOT use tabs for indenting.
Classes and Functions
- When instantiating a new class, parentheses MUST always be present even when there are no arguments passed to the constructor.
- The
extends
andimplements
keywords MUST be declared on the same line as the class name.
- The opening brace for the class MUST go on its own line; the closing brace for the class MUST go on the next line after the body.
- Lists of
implements
and, in the case of interfaces,extends
MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one interface per line.
- The
use
keyword used inside the classes to implement traits MUST be declared on the next line after the opening brace. Each individual trait that is imported into a class MUST be included one-per-line and each inclusion MUST have its ownuse
import statement.
- When the class has nothing after the
use
import statement, the class closing brace MUST be on the next line after theuse
import statement. Otherwise, it MUST have a blank line after theuse
import statement.
- Visibility MUST be declared on all methods. (public, protected, private)
- Method names MUST NOT be prefixed with a single underscore to indicate protected or private visibility. That is, an underscore prefix explicitly has no meaning.
- Method and function names MUST NOT be declared with space after the method name. In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma.
- The opening brace MUST go on its own line, and the closing brace MUST go on the next line following the body.
- There MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis.
- Method and function arguments with default values MUST go at the end of the argument list.
- Argument lists MAY be split across multiple lines, where each subsequent line is indented once. When doing so, the first item in the list MUST be on the next line, and there MUST be only one argument per line.
- When the argument list is split across multiple lines, the closing parenthesis and opening brace MUST be placed together on their own line with one space between them.
- When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis, there MUST NOT be a space after the opening parenthesis, and there MUST NOT be a space before the closing parenthesis. In the argument list, there MUST NOT be a space before each comma, and there MUST be one space after each comma.
Control Structures
- There MUST be one space after the control structure keyword
- There MUST NOT be a space after the opening parenthesis
- There MUST NOT be a space before the closing parenthesis
- There MUST be one space between the closing parenthesis and the opening brace
- The structure body MUST be indented once
- The body MUST be on the next line after the opening brace
- The closing brace MUST be on the next line after the body
- The body of each structure MUST be enclosed by braces. This standardizes how the structures look and reduces the likelihood of introducing errors as new lines get added to the body.
- All control keywords SHOULD look like single words (elsif)
PSR-4 Auto-Loading
For detailed information look into the PSR-4 Spec.
Naming Conventions
Blade files
camelCase according to https://spatie.be/guidelines/laravel-php#content-views
Classes
Type | Naming Convention | Folder | Example | Additional Notes | Artisan Command |
---|---|---|---|---|---|
Command | Pascal Case [CommandSingular]Command.php | app/Console/Commands/ modules/[moduleName]/Console/ | SettlementRunCommand.php | Command should be callable with [module]:[command] or nms:[command] | make:command module:make-command |
Controller | Pascal Case [ModelSingular]Controller | app/Http/Controllers/ modules/[moduleName]/Http/Controllers/ | UserController.php SlaController.php | Several Controllers can be grouped if they belong together. (i.e. Authentication) | make:controller module:make-controller |
Custom Collections | Pascal Case [ModelSingular]Collection | app/Collections/ modules/[moduleName]/Collections/ | AbilityCollection.php * | Need to Extend EloquentCollection and Model-Method "newCollection()" should return instance of Custom Collection | none |
Event | Pascal Case - Past tense of Action that occured, no Suffix | app/Events/ modules/[moduleName]/Events/ | ModemRestarted.php * UserRegistered.php * | make:event module:make-event | |
Exception | Pascal Case [ExceptionName]Exception | app/Exceptions modules/[moduleName]/Exceptions | PostTooLargeException.php HttpResponseException.php | Extends the Original Exception Class and helps to have finer grained Errors | |
Factory | Pascal Case [ModelSingular]Factory | database/factories/ modules/[moduleName]/Database/Factories | UserFactory.php * ModemFactory.php * | Like Migrations, Factories have no Namespace Used to generate dummy Data (Single Model) and for Tests | make:factory module:make-factory |
Job | Pascal Case [SingularNoun]Job | app/Jobs modules/[moduleName]/Jobs | RedisJob.php ModemRefreshJob.php * | Processes that need to be Queued | make:job module:make-job |
Listener | Pascal Case - Present Tense that describes the Action that is taken | app/Listeners modules/[moduleName]/Listeners | LogPayment.php * RestartModem.php * | Can be bound to one or More Events and is a Subtask that needs to happen when the event is triggered | make:listener module:make-listener |
Pascal Case - Named after the action you want to inform about | app/mails modules/[moduleName]/mails | NewCommentOnTicket.php * ContractChanged.php * | How to use Mailable Classes | make:mail module:make-mail | |
Middleware | Pascal Case - Named after the action you want to do | app/Http/Middleware modules/[moduleName]/Http/Middleware | EncryptCookies.php SetLanguage.php | Can be enabled or configured using the Kernel.php in app/Http | make:middleware module:make-middleware |
Migration | Snake Case with all lower case [YYYY_MM_DD_HHiiss_action_table] | database/migrations modules/[moduleName]/Database/Migrations | 2018_08_24_134622_update_users_table.php 2018_09_07_000100_create_sla_table.php | Actions can be: "bugfix","change", "create","update","delete", If possible only change one Table per Migration file Class name of Migration should be the action in Pascal Case and has no Namespace | make:migration module:make-migration add "extendsBaseMigration" |
Model | Pascal Case - Singular | app/ modules/[moduleName]/Entities/ | User.php Modem.php | Eloquent Model, to easily work with DB | make:model module:make-model |
Notification | Pascal Case - like mail, named after the action you want to inform about | app/Notifications modules/[moduleName]/Notifications | NewCommentOnTicket.php * ContractChanged.php * | Notification Doc | make:notification module:make-notification |
Observer | Pascal Case [SingularModel]Observer | app/Observers modules/[moduleName]/Observers | UserObserver.php * ModemObserver.php * | We have them in the Model File right now → they should however be ported to their own files. | make: module:make- |
Policy | Pascal Case [SingularModel]Policy | app/Policies modules/[moduleName]/Policies | UserPolicy.php * ModemPolicy * | Custom Request Policy to change Access permissions → We use Bouncer and therefore no real usage for us - but here to have a complete list | make:policy module:make-policy |
Provider | Pascal Case [Entity]ServiceProvider | app/Providers modules/[moduleName]/Providers | AppServiceProvider.php EventServiceProvider.php | make:provider module:make-provider | |
FormRequest | Pascal Case [SingularModel]Request | app/Http/Requests modules/[moduleName]/Http/Requests | UserRequest.php * | Custom Form Requests to cleanup Controllers and keep the request related logic here | make:request module:make-request |
Validation rule | Pascal Case - name of the [thing] you want to validate | app/Rules modules/[moduleName]/Rules | SerialNumber.php * IpAdress.php * | make:rule module:make-rule | |
Seeder | Pascal Case [SingularModel]Seeder | database/seeds modules/[moduleName]/Database/Seeders | CostCenterSeeder.php * ProductSeeder.php * | Either to prefill the Database with data or generate Dummy Data with multiple Models → should call factory | make:seeder module:make-seeder |
Test | Pascal Case Unit: [SingularModel]Test Feature: [Action]Test | app/Tests/[Unit/Feature] modules/[moduleName]/Tests/[Unit/Feature] | BaseModelTest.php * ModemTest.php * RefreshModemTest.php * | make:test module:make-test | |
Interface | Pascal Case [Name]Contract | app/Contracts modules/[moduleName]/Contracts | CdrContract.php * ConfigFileContract.php * | Used to have an Agreement(API) between several classes, that thei have to adhere to | |
Trait | Pascal Case - verb form or some kind of active form (has/can) | app/Traits modules/[moduleName]/Traits | HasRolesAndAbilities.php Notifiable.php | Used to have related Code that is used in more than one Class in one Place. | |
Utility / PHP Class | Pascal Case | app/Utility modules/[moduleName]/Utility | NmsPrimeHelpers.php SettlementRunZipper.php | Plain PHP Classes that are no Eloquent Models or have some Utility Logic |
*These are Examples for Filenames, but they do not Exist in the System at the time of writing this page
Database
Entity | Type | Naming Convention | Examples | NMSPrime complies to this |
---|---|---|---|---|
Tables | Standard | Plural | modems, users | no |
Pivot | Singular Snake Case in Alphabetic order | role_user | mostly | |
Columns | Standard | Snake Case Singular | name, street | no |
JSON/Array | Snake Case - Plural | serviceNumbers | no | |
boolean | CamelCase is[Singular] | no | ||
Primary Key | id | yes | ||
Foreign Keys | [ModelSingular]_id | configfile_id | yes | |
Polymorphic | adjective, usually ending on "able" - similar to trait. (i. e. likable) | ticketable → ticket.ticketable_id and ticket.ticketable_type | yes | |
timestamps | Snake Case and should end with "on", "at", (or for dates) "from", "to" | sometimes |
Functions, Methods and Variables
Entity | Type | Naming Convention | Examples | Comment |
---|---|---|---|---|
Artisan command options | kebab-case | |||
Functions | Classless | Camel Case - inside Helpers | ||
Variables | Constants | All Capital Snake Case | Try to avoid constants, rather use the configuration file system that Laravel provides. | |
Properties | [public/protected/private] [static] $CamelCase | |||
Laravel specific Eloquent properties | protected $connection protected $table protected $primaryKey public $incrementing protected $with protected $withCount protected $guarded protected $fillable protected $casts protected $dates |
| ||
Standard | $CamelCase | Try to use expressive variable names - ret and var are NOT expressive | ||
Methods | standard | [final/abstract] [public/protected/private] [static] CamelCase() | ||
Relationship | hasMany/belongsToMany/morphTo: public [ModelPlural]() hasOne/belongsTo: public [ModelSingular]() | |||
Laravel Magic Methods | set[name]Attribute get[name]Attribute increment[Attribute] decrement[Attrubute] fresh() | Laravel Doc |
NMS Prime Specific
String concatenation: TBD
PHP CodeSniffer Profile
TODO: Will work on a PHP Codesniffer and fixer configuration as precommit hook to apply most of the mentioned Styles automatically
Frontend
For Theming a mixture of Bootstrap and ColorAdmin is used. Due to this, a lot of functionality.
Color Standards
code | Color | Meaning |
---|---|---|
info | blue | Info Label: Default |
danger | red | Error or sth is critically wrong |
warning | yellow | Gives a hint that there is a threshhold exceeded or sth is close to a critical state |
active | grey | Actually used for inactive/outdated contracts, items - everything that is old |
Be aware that colorization is not yet implemented as written above in a lot of models/cases as of Oct 2019