Giter VIP home page Giter VIP logo

packagit's Introduction

Packagit

Packagit is amazing laravel modules management, you could manage huge project with many separate laravel modules.

You could run packagit or a short name p, such as p new Auth, a module named Auth would be created.

You can make artisan command running anywhere, All the packagit commands are same with artisan like following table.

artisan packagit
php artisan tinker p tinker
php artisan make:controller p make:controller
php artisan make:migration p make:migration
php artisan make:job p make:job
php artisan test p test
php artisan ... p ...

for example, you have a project named starter, directories layout:

starter
    └── modules
        ├── Auth
        ├── Components
        └── Wechat

change path to starter/modules/Auth, and run p make:controller:

cd starter/modules/Auth
p make:controller DemoController

DemoController.php would be created for Auth module.

modules/Auth/src/Http/
└── Controllers
   └── DemoController.php

change path to starter/app/Http/Controllers, and p make:controller:

cd starter/app/Http/Controllers
p make:controller DemoController

DemoController.php would be created for starter, because of current path doesn't include any module.

So when you run p make:xxx laravel command, packagit would scan the path, if current is in a module path, it will create for the module, otherwise for the project.

Installation

composer global require packagit/packagit

You MUST install packagit with global, and add composer bin to the $PATH environment.

Following command would help you find the global bin path:

composer global config bin-dir --absolute --global

# such as $HOME/.composer/vendor/bin, add to $PATH
# save to ~/.zshrc or ~/.bashrc
export PATH=$HOME/.composer/vendor/bin:$PATH

Usage

1. Custom package namespace (Optional)

run p custom

config/packagit.php file would be created, you could customize namespace by edit this file, skip here if you don't need custom.

2. Create a new module

run packagit new ModuleName

you also could group many modules as Components or others you want.

packagit new Components/NetUtil
packagit new Components/Updater
packagit new Components/Downloader

A Module Structure:

├── README.md
├── composer.json
├── config
│   └── config.php
├── database
│   ├── factories
│   ├── migrations
│   └── seeders
│       └── DatabaseSeeder.php
├── package.json
├── resources
├── routes
│   ├── api.php
│   └── web.php
├── src
│   ├── Models
│   └── Providers
│       ├── CommandServiceProvider.php
│       ├── RouteServiceProvider.php
│       └── ServiceProvider.php
├── tests
│   ├── Feature
│   └── Unit
└── webpack.mix.js

Load modules in project

1、composer require wikimedia/composer-merge-plugin

edit project/composer.json => extra => merge-plugins:

    "extra": {
        "merge-plugin": {
            "include": [
                "modules/*/composer.json",
                "modules/Components/*/composer.json"
            ],
            "recurse": false,
            "replace": true,
            "ignore-duplicates": false,
            "merge-dev": true,
            "merge-extra": true,
            "merge-extra-deep": true
        },
        "laravel": {
            "dont-discover": []
        }
    },

2、composer dump-autoload

3、edit project/config/app.php

    'providers' => [
        \Packagit\[MoudleName]\Providers\ServiceProvider::class, 
    ],

All done, modules should work well.

License

The Apache License 2. Please see License File for more information.

packagit's People

Contributors

mouyong avatar myxiaoao avatar yinyao-tech avatar zencodex avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

packagit's Issues

laravel9 bug

p custom                       

   Error 

  Class "Laravel\Package\Exceptions\FileAlreadyExistException" not found

  at /Users/chensuilong/.composer/vendor/packagit/packagit/src/Commands/CustomCommand.php:43
     39▕      */
     40▕     public function handle()
     41▕     {
     42▕         $to = config_path('packagit.php');
  ➜  43▕         throw_if(file_exists($to), new FileAlreadyExistException('config/packagit.php is already existing'));
     44▕ 
     45▕         $from = dirname(__DIR__, 2) . '/config/config.php';
     46▕         copy($from, $to);
     47▕         $this->line('Config file copied to  ['.$to.']');
(base) 

运行数据填充和模型工厂的时候报错..

image

p db:seed --class=ArticleSeeder
Work Module: /modules/ArticleApi

   Error 

  Class "Database\Factories\App\Models\ArticleFactory" not found

  at /Users/chensuilong/Desktop/phpproject/laravel9xx/laravel9/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Factories/Factory.php:770
    766▕     public static function factoryForModel(string $modelName)
    767▕     {
    768▕         $factory = static::resolveFactoryName($modelName);
    769▕ 
  ➜ 770▕         return $factory::new();
    771▕     }
    772▕ 
    773▕     /**
    774▕      * Specify the callback that should be invoked to guess factory names based on dynamic relationship names.

      +1 vendor frames 
  2   /Users/chensuilong/Desktop/phpproject/laravel9xx/laravel9/database/seeders/ArticleSeeder.php:28
      App\Models\Article::factory()

参考教程
https://learnku.com/docs/laravel/9.x/database-testing/12261#defining-model-factories

正常目录下摆放是可以运行成功的.... 用您的包以后似乎路径有些错误 无法运行数据填充~~

望大佬测试一下 谢谢

laravel9/modules/ArticleApi/database/factories/ArticleFactory.php

<?php

namespace ll\ArticleApi\Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;
use ll\ArticleApi\Models\Article;

class ArticleFactory extends Factory
{
    protected $model = Article::class;
    public function definition()
    {
        return [
            'title' => $this->faker->title(),
            'content' => $this->faker->text(),
            'show' => 1,
        ];
    }
}

laravel9/modules/ArticleApi/database/seeders/ArticleSeeder.php

<?php

namespace ll\ArticleApi\Database\Seeders;

use Illuminate\Database\Seeder;
use ll\ArticleApi\Models\Article;
use ll\ArticleApi\Models\Tag;

class ArticleSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {

        Article::factory()
            ->count(10)
            ->has(Tag::factory()->count(3))
            ->create();
    }
}

laravel9/modules/ArticleApi/src/Models/Article.php

<?php

namespace ll\ArticleApi\Models;

use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasFactory;
    use HasDateTimeFormatter;
    use SoftDeletes;
    protected $fillable = [
        'title', 'content', 'show',
    ];
    public function tags()
    {
        return $this->belongsToMany(Tag::class)->withTimestamps();
    }

}


laravel9/modules/ArticleApi/src/Models/Tag.php

<?php

namespace ll\ArticleApi\Models;


use Dcat\Admin\Traits\HasDateTimeFormatter;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Tag extends Model
{
    use HasFactory;
    use HasDateTimeFormatter;
    protected $fillable = ['name'];

    public function articles()
    {
        return $this->belongsToMany(Article::class);
    }
}

数据库迁移文件

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateArticle extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        if (Schema::hasTable('articles')) {
            return true;
        }
        Schema::create('articles', function (Blueprint $table) {
            $table->id()->unsigned()->index();

//            $table->foreignId ('user_id');

            $table->string('title', 200)->default('')->comment('文章标题');
//            $table->string ('cover_url')->default ('')->comment ('文章封面图片');
//            $table->string ('desc', 200)->default ('')->comment ('文章摘要');
            $table->string('tags', 255)->default('')->comment('文章标签');
            $table->mediumText('content')->comment('内容');
            $table->tinyInteger('show')->default(0)->comment('是否显示');
            $table->timestamps();
            $table->softDeletes();
        });

        Schema::create('tags', function (Blueprint $table) {
            $table->id()->unsigned()->index();
            $table->string('name');
            $table->timestamps();
        });
        Schema::create('article_tag', function (Blueprint $table) {
            $table->bigInteger('article_id')->unsigned()->index();
            $table->foreign('article_id')->references('id')->on('articles')->onDelete('cascade');

            $table->bigInteger('tag_id')->unsigned()->index();
            $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');

            $table->timestamps();

        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('article_tag');
        Schema::dropIfExists('articles');
        Schema::dropIfExists('tags');
    }
}


laravel 9 p db:seed 执行失败~~

image

 p db:seed
Work Module: /modules/ArticleApi

   Illuminate\Contracts\Container\BindingResolutionException 

  Target class [Packagit\ArticleApi\Packagit\ArticleApi\Database\Seeders\DatabaseSeeder] does not exist.

感觉是找错了路径...

大佬的包挺好用的...我试着写控制器和路由没问题~~很舒服

执行流程应该调整下吧

  1. p custom 生成自定义配置文件
  2. p new 生成模块

同时 custom 的时候,应该就可以安装 wikimedia/composer-merge-plugin 同时配置 composer ;
app.php 的 providers 在模块中,已经声明了,这里应该不需要再配置了吧。

@zencodex

Commands not finding current folder's module

When I am inside my module's folder, and run a command p make:controller it creates a controller under app/Http/Controllers rather than app\Jobs\src\Http\Controllers

config.php

<?php

/**
 * DON'T CHANGE ANYTHING EXCEPT FOLLOWING
 *
 * 1. namespace
 * 2. composer.*
 *
 */
return [

    // YOU COULD CUSTOM HERE
    'namespace' => 'Somecv',

    /*
    |--------------------------------------------------------------------------
    | Composer File Template
    |--------------------------------------------------------------------------
    |
    | YOU COULD CUSTOM HERE
    |
    */
    'composer'  => [
        'vendor' => 'somecv',
        'author' => [
            'name'  => 'Somecv',
            'email' => '[email protected]',
        ],
    ],

    'paths' => [
        'modules' => base_path('app'),

        /*
        |--------------------------------------------------------------------------
        | Modules assets path
        |--------------------------------------------------------------------------
        |
        | Here you may update the modules assets path.
        |
        */

        'assets' => public_path('modules'),
        /*
        |--------------------------------------------------------------------------
        | The migrations path
        |--------------------------------------------------------------------------
        |
        | Where you run 'module:publish-migration' command, where do you publish the
        | the migration files?
        |
        */

        'migration' => base_path('database/migrations'),

        /*
        |--------------------------------------------------------------------------
        | Generator path
        |--------------------------------------------------------------------------
        | Customise the paths where the folders will be generated.
        | Set the generate key to false to not generate that folder
        */
        'generator' => [
            'config'        => ['path' => 'config', 'generate' => true],
            'command'       => ['path' => 'src/Console', 'generate' => false],
            'migration'     => ['path' => 'database/migrations', 'generate' => true],
            'seeder'        => ['path' => 'database/seeders', 'generate' => true],
            'factory'       => ['path' => 'database/factories', 'generate' => true],
            'model'         => ['path' => 'src/Models', 'generate' => true],
            'routes'        => ['path' => 'routes', 'generate' => true],
            'controller'    => ['path' => 'src/Http/Controllers', 'generate' => false],
            'filter'        => ['path' => 'src/Http/Middleware', 'generate' => false],
            'request'       => ['path' => 'src/Http/Requests', 'generate' => false],
            'provider'      => ['path' => 'src/Providers', 'generate' => true],
            'assets'        => ['path' => 'resources/assets', 'generate' => true],
            'lang'          => ['path' => 'resources/lang', 'generate' => true],
            'views'         => ['path' => 'resources/views', 'generate' => true],
            'test'          => ['path' => 'tests/Unit', 'generate' => true],
            'test-feature'  => ['path' => 'tests/Feature', 'generate' => true],
            'repository'    => ['path' => 'src/Repositories', 'generate' => false],
            'event'         => ['path' => 'src/Events', 'generate' => false],
            'listener'      => ['path' => 'src/Listeners', 'generate' => false],
            'policies'      => ['path' => 'src/Policies', 'generate' => false],
            'rules'         => ['path' => 'src/Rules', 'generate' => false],
            'jobs'          => ['path' => 'src/Jobs', 'generate' => false],
            'emails'        => ['path' => 'src/Mail', 'generate' => false],
            'notifications' => ['path' => 'src/Notifications', 'generate' => false],
            'resource'      => ['path' => 'src/Http/Resources', 'generate' => false],
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Module Stubs
    |--------------------------------------------------------------------------
    |
    | Default module stubs.
    |
    */
    'stubs' => [
        'path'         => dirname(__DIR__) . '/src/Commands/stubs',
        'files'        => [
            'routes/web'        => 'routes/web.php',
            'routes/api'        => 'routes/api.php',
            'views/index'       => 'resources/views/index.blade.php',
            'views/master'      => 'resources/views/layouts/master.blade.php',
            'scaffold/config'   => 'config/config.php',
            'scaffold/provider' => 'src/Providers/ServiceProvider.php',
            'seeder'            => 'database/seeders/DatabaseSeeder.php',
            'route-provider'    => 'src/Providers/RouteServiceProvider.php',
            'command-provider'  => 'src/Providers/CommandServiceProvider.php',
            'composer'          => 'composer.json',
            'assets/js/app'     => 'resources/assets/js/app.js',
            'assets/sass/app'   => 'resources/assets/sass/app.scss',
            'webpack'           => 'webpack.mix.js',
            'package'           => 'package.json',
            'readme'            => 'README.md'
        ],
        'replacements' => [
            'routes/web'        => ['LOWER_NAME', 'STUDLY_NAME'],
            'routes/api'        => ['LOWER_NAME'],
            'readme'            => ['LOWER_NAME', 'STUDLY_NAME'],
            'webpack'           => ['LOWER_NAME'],
            'views/index'       => ['LOWER_NAME'],
            'views/master'      => ['LOWER_NAME', 'STUDLY_NAME'],
            'scaffold/config'   => ['STUDLY_NAME'],
            'scaffold/provider' => ['NAMESPACE', 'LOWER_NAME'],
            'seeder'            => ['NAMESPACE'],
            'route-provider'    => ['NAMESPACE', 'STUDLY_NAME', 'MODULE_NAMESPACE'],
            'command-provider'  => ['NAMESPACE'],
            'composer'          => [
                'LOWER_NAME',
                'STUDLY_NAME',
                'VENDOR',
                'AUTHOR_NAME',
                'AUTHOR_EMAIL',
                'MODULE_NAMESPACE',
                'PROVIDER_NAMESPACE',
            ],
        ],
        'gitkeep'      => true,
    ],

];

服务提供者是否可以自动加载呢?

开发完成了项目后,一般期望能使用 composer.jsonextra 配置,完成服务提供者的自动加载,并且期望能通过事件、数据的的方式完成插件的各方面管理。不希望改动到文件 app/config.php 与主项目的各项文件内容。

这里之前的参考资料:

注册模块的命名空间:https://gitee.com/fresns/plugin-manager/blob/master/src/Providers/PluginServiceProvider.php#L35-38

注册每一个插件的命名空间、别名:https://gitee.com/fresns/plugin-manager/blob/master/src/Support/Plugin.php#L118-120

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.