Development

NOTE: Every package should be as flexible as possible through published files (configs, views, translations and more),
put hooks in views, setting custom events, extending classes, pipelines and other means necessary - this is especially true for
administrations modules.

  1. Create directory structure
├──  src
│   ├── config
│   │   ├── marinar_PACKAGE.php
│   │   ├── package.php
│   ├── Contracts
│   ├── Database
│   │   ├── Seeds
│   │   │   ├── MarinarPACKAGEInstallSeeder.php
│   │   │   ├── MarinarPACKAGERemoveSeeder.php
│   ├── stubs
│   │   ├── project
│   │   │   ├── config
│   │   │   │   ├── marinar_PACKAGE.php
│   │   ├── public_html
│   ├── hooks
│   │   ├── map.php
│   ├── PACKAGE.php
├── composer.json
├── README.md
  1. package composer.json
{
    "name": "marinar/PACKAGE",
    "description": "PACKAGE module",
    "type": "library",
    "license": "MIT",
    "authors": [
        {
            "name": "NAME",
            "email": "YOUR_MAIL@dev.nddesign.no"
        }
    ],
    "autoload": {
        "psr-4": {
            "Marinar\\PACKAGE\\": "src/"
        }
    },

    "require": {
        "marinar/helpers": "*"
    },
    "extra": {
        "marinar": {
            "module": true,
            "plugin": false,
            "addon_to": false
        },
        "laravel": {
            "aliases": {
                "MarinarPACKAGE": "Marinar\\PACKAGE\\MarinarPACKAGE"
            }
        }
    }
}
  1. In project composer.json add
"repositories": [
        {
            "type": "path",
            "url": "packages/marinar/PACKAGE"
        }
        ...
"repositories": [
        {
            "type": "path",
            "url": "packages/marinar/PACKAGE",            
            "options": {
                "symlink": false
            }
        }
        ...
  1. Create the package Facade
    namespace Marinar\PACKAGE;
    
    use Marinar\PACKAGE\Database\Seeders\MarinarPACKAGEInstallSeeder;
    
    class MarinarPACKAGE {
        
        public static function getPackageMainDir() {
            return __DIR__;
        }
    
        public static function injects() {
            return MarinarPACKAGEInstallSeeder::class;
        }
    }
  1. Create the package configuration file - src/stubs/project/config/marinar_PACKAGE.php
    return [
        /**
         * Behavior when package is installed or update
         * true - normal
         * false - do not do anything
         */
        'install_behavior' => env('MARINAR_PACKAGE_INSTALL_BEHAVIOR', env('MARINAR_INSTALL_BEHAVIOR', true)),
    
        /**
         * Behavior when package is removed from composer
         * true - delete all
         * false - delete all, but not changed stubs files
         * 1 - delete all, but keep the stub files and injection
         * 2 - keep everything
         */
        'delete_behavior' => env('MARINAR_PACKAGE_DELETE_BEHAVIOR', env('MARINAR_DELETE_BEHAVIOR', false)),
    
        /**
         * File stubs that return arrays that are configurable,
         * If path is directory - its files and sub directories
         */
        'values_stubs' => [
            __DIR__,
            dirname(__DIR__).DIRECTORY_SEPARATOR.'lang'
        ],
    
        /**
         * Exclude stubs to be updated
         * If path is directory - exclude all its files
         * If path is file - only it
         */
        'exclude_stubs' => [
        ],
    
        /**
         * Exclude addon injections
         * file_path => [ '@hook1', '@hook2' ]
         * file_path => * - all from this file
         */
        'exclude_injects' => [],
    
        /**
         * Addons hooked to the package
         */
        'addons' => [
            // @HOOK_ADDONS
        ],
        // @HOOK_CONFIGS
    ];
  1. Create hooks map - src/hooks/map.php. The key is the file, which will be injected and the value array [HOOK KEY => template or file]. Injection files with extension .php will remove the <?php from the begging
<?php
use Marinar\PACKAGE\MarinarPACKAGE;

$packageDir = MarinarPACKAGE::getPackageMainDir();
return [
    implode(DIRECTORY_SEPARATOR, [ base_path(), 'resources', 'views', 'components', 'admin', 'box_sidebar.blade.php']) => [
        "{{--  @HOOK_ADMIN_SIDEBAR  --}}" => "\t<x-admin.sidebar.PACKAGE_option />\n",
    ],
    implode(DIRECTORY_SEPARATOR, [ base_path(), 'config', 'marinar.php']) => [
        "// @HOOK_MARINAR_CONFIG_ADDONS" => implode(DIRECTORY_SEPARATOR, [$packageDir, 'hooks', 'HOOK_USER_AFTER_ROLES.blade.php'])
    ]
];
  1. Create the package install seeder - database/seeds/MarinarPACKAGEInstallSeeder.php
namespace Marinar\PACKAGE\Database\Seeds;

use Illuminate\Database\Seeder;
use Marinar\PACKAGE\MarinarPACKAGE;

class MarinarPACKAGEInstallSeeder extends Seeder
{

    use \Marinar\Marinar\Traits\MarinarSeedersTrait;

    public static function configure() {
        static::$packageName = 'marinar_PACKAGE';
        static::$packageDir = MarinarPACKAGE::getPackageMainDir();
    }

    public function run() {
        if(!in_array(env('APP_ENV'), ['dev', 'local'])) return;

        $this->autoInstall();

        $this->refComponents->info("Done!");
    }
}
  1. Create the package remove seeder - database/seeds/MarinarPACKAGERemoveSeeder.php
    namespace Marinar\PACKAGE\Database\Seeders;

    use Illuminate\Database\Seeder;
    use Marinar\Users\MarinarPACKAGE;
    use Spatie\Permission\Models\Permission;

    class MarinarPACAKGERemoveSeeder extends Seeder {

        use \Marinar\Marinar\Traits\MarinarSeedersTrait;

        public static function configure() {
            static::$packageName = 'marinar_PACKAGE';
            static::$packageDir = MarinarPACKAGE::getPackageMainDir();
        }

        public function run() {
            if(!in_array(env('APP_ENV'), ['dev', 'local'])) return;

            $this->autoRemove();

            $this->refComponents->info("Done!");
        }

        public function clearDB() { //just for example - it's not required
            $this->refComponents->task("Clear DB", function() {
                Permission::whereIn('name', [
                    'users.view',
                    'user.create',
                    'user.view',
                    'user.update',
                    'user.delete',
                ])
                ->where('guard_name', 'admin')
                ->delete();
                app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
                return true;
            });
        }
    }
  1. Create config/package.php - for auto install and remove commands
//    $dbDir = [ dirname(__DIR__), 'Database', 'migrations' ];
//    $dbDir = implode( DIRECTORY_SEPARATOR, $dbDir );
	return [
		'install' => [
            'php artisan db:seed --class="\Marinar\PACKAGE\Database\Seeders\MarinarPACKAGEInstallSeeder"',
		],
		'remove' => [
            'php artisan db:seed --class="\Marinar\PACKAGE\Database\Seeders\MarinarPACKAGERemoveSeeder"',
        ]
	];

Module

Modules are packages for administrating. They give tools and interfaces for list, create, change and delete information.

Plugin

Plugins are packages which give logic, which can be used in different modules or addons.
It's good practice to give some functionality, which can be used for validations and submiting (Facade methods).

Addon

Addons are extensions to modules. Addon package can be module itself and can be connected to multiple modules, too.

For addons connected to some administration module you can:

Infopage::macro('someMethod', function($args) {  //macro
    //do you stuff
});
Infopage::mixin( new OrderableMixin, false ); //mixin
Infopage::$addonStatics['ordField'] = 'ord'; //for public static property
Infopage::$addonFillable[] = 'ord';
//EVENTS
Infopage::creating( Infopage::class.'@onCreating_orderable' );
Infopage::updating( Infopage::class.'@onUpdating_orderable');
Infopage::updated( Infopage::class.'@onUpdated_orderable');
Infopage::deleted( Infopage::class.'@onDeleted_orderable' );
//END EVENTS

Deployment

  1. Make GIT bare repository on Turshia
ssh lpackages@193.93.255.240
cd gits
git init --bare PACKAGE.git
git remote add turshia ssh://lpackages@193.93.255.240/home/lpackages/gits/PACKAGE.git

Note: Add home/lpackages/gits/PACKAGE.git/hooks/post-update with content git update-server-info to can clone through http protocol.

  1. Make repository in GITHUB

  2. Tag your package version

git tag v1.0.0
  1. Push master and tag remote repositories
git push turshia master
git push turshia --tags
git push -u github master
git push -u github --tags

Fixing last version

  1. Remove the old GIT tag and add new
git tag -d v1.0.0
git push turshia :v1.0.0
git push -u github :v1.0.0
  1. Commit your changes

  2. Add new GIT tag and push to remote repositories

git tag v1.0.0
git push turshia master
git push turshia --tags
git push -u github master
git push -u github --tags