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
│   │   ├── migrations
│   │   ├── Seeds
│   │   │   ├── MarinarPACKAGESeeder.php
│   │   │   ├── MarinarPACKAGERemoveSeeder.php
│   ├── Http
│   │   ├── Controllers
│   │   ├── Middleware
│   │   ├── Requests
│   ├── Mixins
│   ├── Models
│   ├── ModelsBase
│   ├── resources
│   │   ├── lang
│   │   │   ├── en
│   │   ├── views
│   ├── routes
│   ├── Trait
│   ├── PACKAGE.php
│   ├── MarinarPACKAGEServiceProvider.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": {
            "providers": [
                "Marinar\\PACKAGE\\MarinarPACKAGEServiceProvider"
            ],
            "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. Run composer dump-autoload - to register the new classes

  2. Create the package ServiceProvicer

    namespace Marinar\PACKAGE;

    use Illuminate\Support\ServiceProvider;

    class MarinarPACKAGEServiceProvider extends ServiceProvider {
        public function boot() {
            MarinarOrders::preHandle();
            if(!\provider_url_check(config('marinar_PACKAGE.provider_route_prefixes')))
                return;
            $this->loadViewsFrom(__DIR__ . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'views', 'marinar_orders');
            $this->loadTranslationsFrom(__DIR__ . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'lang', 'marinar_orders');
            MarinarOrders::handle();
        }

        public function register() {
            config(['marinar_orders.package_dir' => __DIR__]);
            $this->mergeConfigFrom(__DIR__ . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'marinar_orders.php', 'marinar_PACKAGE');
            $this->publishes([
                __DIR__ . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . 'marinar_orders.php' => config_path('marinar_PACKAGE.php'),
            ], 'config');
            $this->publishes([
                __DIR__ . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'views' => resource_path('views/vendor/marinar_PACKAGE'),
            ], 'views');
            $this->publishes([
                __DIR__ . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'lang' => resource_path('lang/vendor/marinar_PACKAGE'),
            ], 'translations');
            $this->loadMigrationsFrom(__DIR__ . DIRECTORY_SEPARATOR . 'database' . DIRECTORY_SEPARATOR . 'migrations');

            MarinarOrders::regHandle();

            \PackagesSeeder::$package_seeders[] = \Marinar\PACKAGE\Database\Seeds\MarinarPACKAGESeeder::class;
            \TestDataSeeder::$package_seeders[] = \Marinar\PACKAGE\Database\Seeds\MarinarPACKAGETestSeeder::class;
        }
    }
  1. Create the package Facade
    namespace Marinar\PACKAGE;
    
    class MarinarPACKAGE {
        public static function route_links() {
            return __DIR__.DIRECTORY_SEPARATOR.'routes'.DIRECTORY_SEPARATOR.'web.php';
        }

        public static function lang_path() {
            return __DIR__.DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR.'lang';
        }

        public static function handle() {
            //...
        }
        
        public static function preHandle() {
            //...
        }
        
        public static function regHandle() {
            //...
        }
    }
  1. Create the package configuration file - config/marinar_PACKAGE.php
    return [
        //...
        //for script, which handle specific routes - facade `handle` method
        'provider_route_prefixes' => [ 
            'admin',
            'employee',
            'salon'
        ],
        //...
    ];
  1. Create the package module|addon|plugin seeder - database/seeds/MarinarPACKAGESeeder.php
namespace Marinar\PACKAGE\Database\Seeds;

use Illuminate\Database\Seeder;

class MarinarPACKAGESeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run() {
        $ordersModule = \App\Module::updateOrCreate([
            'package' => 'marinar/orders',
        ], [
            'package_prefix' => 'marinar_PACKAGE',
            'facade' => 'MarinarPACKAGE',
            'version' => '0.0.1', //your version - not required really
            'name' => 'PACKAGE',
            'icon' => 'fa fa-cubes', //admin icon
            'admin_uri' => 'package', //admin uri prefix
        ]);

    }
}
  1. Create the package remove seeder - database/seeds/MarinarPACKAGERemoveSeeder.php
namespace Marinar\PACKAGE\Database\Seeds;

use Illuminate\Database\Seeder;

class MarinarPACKAGERemoveSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run() {
        \App\Module::wherePackage('marinar/orders')->delete();
    }
}
  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 migrate --realpath --path="'.$dbDir.DIRECTORY_SEPARATOR.'2019_07_09_115803_create_infopages_table.php" -n',
        'php artisan db:seed --class="\Marinar\Infopages\Database\Seeds\MarinarInfopagesSeeder" -n'
    ],
    'remove' => [
        'php artisan migrate:refresh --realpath --path="'.$dbDir.DIRECTORY_SEPARATOR.'2019_07_09_115803_create_infopages_table.php" -n',
        'php artisan migrate:rollback --realpath --path="'.$dbDir.DIRECTORY_SEPARATOR.'2019_07_09_115803_create_infopages_table.php" -n',
        'php artisan db:seed --class="\Marinar\Infopages\Database\Seeds\MarinarInfopagesRemoveSeeder" -n'
    ]
];

Module

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

Modules should give options that help extending them:

@addons($addons, "infos_table_th_after_edit")
event( 'info.submited', [$info, $validatedData] );
$subBldQry = app(Pipeline::class)
    ->send( Infopage::getModel() )    
    ->through(array_merge(
        Addon::hookedFacadeMethods( Addon::sortedFacades('marinar/infopages'), 'index_sub_infos' ),
        (isset(static::$addon_methods['index_sub_infos'])? static::$addon_methods['index_sub_infos'] : [] )
    ))
    ->then(function($bldQry) use ($table) {
        $bldQry = $bldQry->orderBy("{$table}.id", 'ASC');
        return $bldQry;
    });
    public static $addon_validations = [
        'pipes' => [],
        'rules' => [],
        'messages' => [],
    ];

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).

Blade::aliasComponent('marinar_activiable::components.activiable', 'activiable');

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
InfopageController::$addon_methods['index'][] = function($data, \Closure $next) {
    list($bldQry, $viewData) = $data;
    $table = Infopage::getModel()->getTable();
    $ordField = Infopage::getOrdField();
    $bldQry = $bldQry->orderBy("{$table}.{$ordField}", 'ASC');
    return $next([$bldQry, $viewData]);
};
InfopageRequest::$addon_validations['pipes']['marinar_infopages_uriable'] = function($request, \Closure $next) {
    InfopageRequest::$addon_validations['rules'] = array_merge(
        MarinarUriable::validation_rules(
            config('marinar_infopages.input_bag'),
            array_keys(config('marinar_infopages_uriable.point_to_options')),
            'marinar_infopages_uriable::validation.uri',
            true, //with base
            true, //check for same slug
            ($chInfo = request()->route(config('marinar_infopages.route_param_chInfo')))
        ),
        InfopageRequest::$addon_validations['rules']
    );
    InfopageRequest::$addon_validations['messages'] = marinar_assoc_arr_merge(
        (array)trans('marinar_uriable::validation'),
        (array)trans('marinar_infopages_uriable::validation'),
        InfopageRequest::$addon_validations['messages']
    );

    $inputBag = config('marinar_infopages.input_bag');
    $request = MarinarUriable::validation_prework($request, $inputBag);

    //some prework on request
    return $next($request);
};

Example for hook static method which is used for lazy extending:

public static function request($request, \Closure $next) {
    InfopageRequest::$addon_validations['rules'] = array_merge(
        InfopageRequest::$addon_validations['rules'],
        MarinarMetable::validation_rules( 'marinar_infopages_metable::validation' )
    );
    InfopageRequest::$addon_validations['messages'] = marinar_assoc_arr_merge(
        (array)trans('marinar_metable::validation'),
        (array)trans('marinar_infopages_metable::validation'),
        InfopageRequest::$addon_validations['messages']
    );
    return $next($request);
}

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
  1. Make repository in GITHUB

  2. Tag your package version

git tag v0.0.1
  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 v0.0.1
git push turshia :v0.0.1
git push -u github :v0.0.1
  1. Commit your changes

  2. Add new GIT tag and push to remote repositories

git tag v0.0.1
git push turshia master
git push turshia --tags
git push -u github master
git push -u github --tags