This project follows PSR-4 coding standards and those recommended by Sylius and Symfony projects in this order. It is extended based on experience of the whole BitBag team for everybody's sake.
- Use
*.yml
for defining services, doctrine, routing and validation definitions. - Don't use annotations. Don't mess up the definition with implementation.
- Use YAML for all configs except XML for Doctrine entities declaration.
- Don't use PHPDoc. Use it only in interfaces that return array of objects or collections, like:
interface Foo
{
/**
* @return Collection|ItemInterface[]
*/
public function getItems(): Collection;
}
- Use inline PHPDoc only for fields inside the class, like:
final class Foo
{
/** @var int */
private $foo;
/** @var string */
private $bar;
public function getFoo(): ?int
{
return $this->foo;
}
public function getBar(): ?string
{
return $this->bar;
}
}
- Keep a blank line above the
@return
method definition in case it has more than@return
annotation, for instance
interface Foo
{
/**
* @param string $key
*
* @return Collection|ItemInterface[]
*/
public function getItemsWithoutKey(string $key): Collection;
}
- Use strict types declaration in each class header, like:
<?php
declare(strict_types=1);
namespace Foo\Bar;
final class Foo
{
}
- Before you implement any new functional feature, write Behat scenario first (Gherkin,
*.feature
file). - After writing the scenario, write a proper scenario execution (Contexts, Pages).
- Before starting implementing new functional code, make sure all your core logic is covered with PHPSpec (code without framework dependencies, like Commands, Forms, Configuration, Fixtures, etc.)
- Make your code as simple as it's possible (follow single responsibilty principle).
- Use interfaces for any core logic class implementation, especially Models and Services (so that you follow single responsibilty principle).
- Use
final
any time it is possible (in order to avoid infinite inheritance chain, in order to customize some parts use Decorator and Dependency Injection patterns). - For Symfony services definitions in a single bundle use
form.yml
,event_listener.yml
, etc. Don't put everything in theservices.yml
file, do it in public projects with only a few services. If you have more than one type of service inside your app, create a separate config file underservices/
directory. - Any
*.php
file created by the BitBag developer, especially in Open Source, needs to have at least the following definition where the author is the user who created this file:
<?php
/**
* This file was created by the developers from BitBag.
* Feel free to contact us once you face any issues or want to start
* another great project.
* You can find more information about us on https://bitbag.shop and write us
* an email on [email protected].
*/
namespace Foo;
use Foo\Bar\App;
final class Bar implements BarInterface
{
public const SOME_CONST = 'foo';
public const SOME_OTHER_CONST = 'bar';
/** @var string */
private $someProperty;
public function inheritedMethod(): string
{
//some body
}
private function someFunction(SomeServiceInterface $someService): ?NullOrInterfacedObject
{
$items = $someService->getCollection();
/** @var WeUseThisBlockDefinitionIfNecessaryOfCourseWithInterface $someOtherProperty */
$someOtherProperty = $someService->getSomething();
// Use break line between any operation in your code. Imagine the code as block diagram, where every new line is an arrow between operations.
foreach ($items as $item) {
$item->doSomething();
if (false === $item->getProperty()) { // Always use strict comparison with expected result on the left
return;
}
continue;
}
$someService->someOutputAction();
$this->someProperty->someOtherOutputAction();
return $someOtherProperty;
}
}
Once you use PHPStorm (and yes, you do if you work at BitBag),
you can open your IDE preferences (PHPStorm -> Preferences
) and search for File and Code Templates
.
PHP Class Doc Comment, PHP File Header, PHP Interface Doc Comment
are those templates that should at least be customized.
- Use Behat Contexts are divided into
Hooks
- generic app Background,Setup
specific resource background,Ui
- specific interaction. - Commit messages should be written (if only it's possible) with the following convention:
[Project spec state][Bundle] max 64 characters description in english written in Present Simple.
- If there is an opened issue on Jira for a specific task, your branch should be named
sit_[ISSUE_NUMBER]
. If not, it should be named with the first letter of your name and your surname. In my case (Mikołaj Król) it would bemkrol
. - Be careful with using static fields.
- Be more careful when you think Singleton is something you need in project.
- Laravel is not that bad.
- Just kidding.
- Open source is made by forks if only more than one person is in charge of maintenance of specific package.
- We follow http://docs.sylius.org/en/latest/contributing/ contribution standards
null === $var->getResult($anotherVar)
instead of$var->getResult($anotherVar) === null
- If that's not obvious yet, be careful with
static
, probably you will never need to use it. - No
/.idea
and other local config files in.gitignore
. Put them into global gitignore file, read more on https://help.github.com/articles/ignoring-files/#create-a-global-gitignore. - We are working on NIX systems and we don't like Windows nor are we solving it's existance goal and other problems.
- Repositories and Entities in public projects should not be defined as
final
. - Entity fields in public projects (vendors) should be
protected
instad ofprivate
. - Decorate resource factories with decoration pattern and do not call resource instance with
new
keyword directly. Instead, inject resource factory into constructor and callcreateNew()
on it. SeeSylius\Component\Product\Factory\ProductFactory
,sylius.custom_factory.product
service definition and https://symfony.com/doc/current/service_container/service_decoration.html. Thepriority
flag we are starting with equals 1 and is increased by one for each other decoration. - For customizing forms use Symfony Form Extension.
- We follow command pattern implemented in SyliusShopApiPlugin. This means we use the same bus libraries and similar
Command, CommandHandler, ViewRepository, ViewFactory, View
approach.
Be smart and keep in mind that once you do something stupid, I will find you and I will force you to work with Laravel or Magento. There is nothing called stupid question, but please ask it in a smart way :). It's better to talk about a feature with the whole team for 30 minutes than lose 8 hours on implementing some dummy code that will destroy the current codebase order and deep the technical debt.