first upload all files

This commit is contained in:
NW
2023-06-11 13:14:03 +01:00
parent f14dbc52b5
commit c08b36d1b6
1705 changed files with 106852 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
<?php
namespace FleetCart\Console\Commands;
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputArgument;
use FleetCart\Scaffold\Module\Generators\EntityGenerator;
class ScaffoldEntityCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'scaffold:entity';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Scaffold a new entity with all its resources.';
/**
* The instance of EntityGenerator.
*
* @var \FleetCart\Scaffold\Module\Generators\EntityGenerator
*/
private $entityGenerator;
/**
* Create a new command instance.
*
* @param \FleetCart\Scaffold\Module\Generators\EntityGenerator $entityGenerator
*/
public function __construct(EntityGenerator $entityGenerator)
{
parent::__construct();
$this->entityGenerator = $entityGenerator;
}
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
$this->entityGenerator
->module($this->argument('module'))
->generate([$this->argument('entity')], false);
$this->info('Entity generated.');
}
/**
* Get the console command arguments.
*
* @return array
*/
protected function getArguments()
{
return [
['entity', InputArgument::REQUIRED, 'The name of the entity.'],
['module', InputArgument::REQUIRED, 'The name of module will be used.'],
];
}
}

View File

@@ -0,0 +1,130 @@
<?php
namespace FleetCart\Console\Commands;
use Illuminate\Console\Command;
use FleetCart\Scaffold\Module\ModuleScaffold;
class ScaffoldModuleCommand extends Command
{
/**
* The console command name.
*
* @var string
*/
protected $name = 'scaffold:module';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Scaffold a new module';
/**
* The instance of ModuleScaffold.
*
* @var \FleetCart\Scaffold\Module\ModuleScaffold
*/
private $scaffolder;
/**
* Create a new command instance.
*
* @param \FleetCart\Scaffold\Module\ModuleScaffold $scaffolder
*/
public function __construct(ModuleScaffold $scaffolder)
{
parent::__construct();
$this->scaffolder = $scaffolder;
}
/**
* Execute the console command.
*
* @return void
*/
public function handle()
{
$module = $this->askModuleName();
$entities = $this->askEntities();
$this->scaffolder->scaffold($module, $entities);
$this->info('Module has been generated.');
}
/**
* Ask for module name.
*
* @return array
*/
private function askModuleName()
{
do {
$moduleName = $this->ask('Please enter the module name in the following format: vendor/name');
list($vendor, $name) = $this->extractModuleName($moduleName);
} while ($this->moduleExists($name));
return compact('vendor', 'name');
}
/**
* Extract the given module name.
*
* @param string $moduleName
* @return array
*/
private function extractModuleName($moduleName)
{
do {
$name = explode('/', $moduleName);
if (count($name) !== 2) {
$this->error('Module name must be in the following format: vendor/name');
$moduleName = $this->ask('Please enter the module name in the following format: vendor/name');
}
} while (count($name) !== 2);
return [$name[0], ucfirst(camel_case($name[1]))];
}
/**
* Determine the given module is exists.
*
* @param string $name
*/
private function moduleExists($name)
{
if (is_dir(config('modules.paths.modules') . "/{$name}")) {
$this->error("The module [$name] is already exists.");
return true;
}
return false;
}
/**
* Ask for entities.
*
* @return array
*/
private function askEntities()
{
$entities = [];
do {
$entity = $this->ask('Enter entity name. Leaving option empty will continue script', false);
if ($entity !== '') {
$entities[] = ucfirst($entity);
}
} while ($entity !== '');
return $entities;
}
}

31
app/Console/Kernel.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
namespace FleetCart\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
Commands\ScaffoldModuleCommand::class,
Commands\ScaffoldEntityCommand::class,
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')
// ->hourly();
}
}

167
app/Exceptions/Handler.php Normal file
View File

@@ -0,0 +1,167 @@
<?php
namespace FleetCart\Exceptions;
use Throwable;
use Illuminate\Http\Request;
use Swift_TransportException;
use Modules\Sms\Exceptions\SmsException;
use Illuminate\Validation\ValidationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class Handler extends ExceptionHandler
{
/**
* A list of the exception types that should not be reported.
*
* @var array
*/
protected $dontReport = [
//
];
/**
* A list of the inputs that are never flashed for validation exceptions.
*
* @var array
*/
protected $dontFlash = [
'password',
'password_confirmation',
];
/**
* Report or log an exception.
*
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
*
* @param \Throwable $e
* @return void
*/
public function report(Throwable $e)
{
parent::report($e);
}
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Throwable $e
* @return \Illuminate\Http\Response
*/
public function render($request, Throwable $e)
{
if ($e instanceof Swift_TransportException) {
return $this->handleSwiftException($request, $e);
}
if ($e instanceof SmsException) {
return $this->handleSmsException($request, $e);
}
if ($e instanceof ValidationException && $request->ajax()) {
return response()->json([
'message' => trans('core::messages.the_given_data_was_invalid'),
'errors' => $e->validator->getMessageBag(),
], 422);
}
if ($this->shouldRedirectToAdminDashboard($e)) {
return redirect()->route('admin.dashboard.index');
}
if ($this->shouldShowNotFoundPage($e)) {
return response()->view('errors.404');
}
return parent::render($request, $e);
}
/**
* Handle swift transport exception.
*
* @param \Illuminate\Http\Request $request
* @param \Swift_TransportException $e
* @return mixed
*
* @throws \Swift_TransportException
*/
private function handleSwiftException(Request $request, Swift_TransportException $e)
{
if (config('app.debug')) {
throw $e;
}
if ($request->ajax()) {
abort(400, trans('core::messages.mail_is_not_configured'));
}
return back()->withInput()
->with('error', trans('core::messages.mail_is_not_configured'));
}
/**
* Handle sms exception.
*
* @param \Illuminate\Http\Request $request
* @param \Modules\Sms\Exceptions\SmsException $e
* @return mixed
*
* @throws \Modules\Sms\Exceptions\SmsException
*/
private function handleSmsException(Request $request, SmsException $e)
{
if (config('app.debug')) {
throw $e;
}
if ($request->ajax()) {
abort(400, $e->getMessage());
}
return back()->withInput()->with('error', $e->getMessage());
}
/**
* Determine whether response should redirect to the admin dashboard.
*
* @param \Throwable $e
* @return bool
*/
private function shouldRedirectToAdminDashboard(Throwable $e)
{
if (config('app.debug') || ! $this->inAdminPanel()) {
return false;
}
return $e instanceof NotFoundHttpException || $e instanceof ModelNotFoundException;
}
/**
* Determine if the response should show not found page.
*
* @param \Throwable $e
* @return bool
*/
private function shouldShowNotFoundPage(Throwable $e)
{
if ($this->inAdminPanel()) {
return false;
}
return $e instanceof NotFoundHttpException || $e instanceof ModelNotFoundException;
}
/**
* Determine if the request is from admin panel.
*
* @return bool
*/
private function inAdminPanel()
{
return $this->container->has('inAdminPanel') && $this->container['inAdminPanel'];
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace FleetCart\Exceptions;
use Exception;
use FleetCart\License;
class InvalidLicenseException extends Exception
{
protected $message;
public function __construct($message)
{
$this->message = $message;
resolve(License::class)->deleteLicenseFile();
}
public function render()
{
return redirect()->route('license.create')
->with('error', $this->message);
}
}

20
app/FleetCart.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
namespace FleetCart;
class FleetCart
{
/**
* The FleetCart version.
*
* @var string
*/
const VERSION = '3.1.0';
/**
* The envato item ID.
*
* @var string
*/
const ITEM_ID = '23014826';
}

View File

@@ -0,0 +1,69 @@
<?php
namespace FleetCart\Http\Controllers;
use Exception;
use FleetCart\Install\App;
use FleetCart\Install\Store;
use FleetCart\Install\Database;
use FleetCart\Install\Requirement;
use Illuminate\Routing\Controller;
use FleetCart\Install\AdminAccount;
use FleetCart\Http\Requests\InstallRequest;
use Jackiedo\DotenvEditor\Facades\DotenvEditor;
use FleetCart\Http\Middleware\RedirectIfInstalled;
class InstallController extends Controller
{
public function __construct()
{
$this->middleware(RedirectIfInstalled::class);
}
public function preInstallation(Requirement $requirement)
{
return view('install.pre_installation', compact('requirement'));
}
public function getConfiguration(Requirement $requirement)
{
if (! $requirement->satisfied()) {
return redirect()->route('install.pre_installation');
}
return view('install.configuration', compact('requirement'));
}
public function postConfiguration(
InstallRequest $request,
Database $database,
AdminAccount $admin,
Store $store,
App $app
) {
@set_time_limit(0);
try {
$database->setup($request->db);
$admin->setup($request->admin);
$store->setup($request->store);
$app->setup();
} catch (Exception $e) {
return back()->withInput()
->with('error', $e->getMessage());
}
return redirect('install/complete');
}
public function complete()
{
if (config('app.installed')) {
return redirect()->route('home');
}
DotenvEditor::setKey('APP_INSTALLED', 'true')->save();
return view('install.complete');
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace FleetCart\Http\Controllers;
use FleetCart\License;
use Illuminate\Routing\Controller;
use FleetCart\Http\Middleware\RedirectIfShouldNotCreateLicense;
class LicenseController extends Controller
{
public function __construct()
{
$this->middleware(RedirectIfShouldNotCreateLicense::class);
}
public function create()
{
return view('license.create');
}
public function store(License $license)
{
request()->validate([
'purchase_code' => 'required',
], [
'required' => 'The purchase code field is required.',
]);
$license->activate(request('purchase_code'));
return redirect()->intended();
}
}

62
app/Http/Kernel.php Normal file
View File

@@ -0,0 +1,62 @@
<?php
namespace FleetCart\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\FleetCart\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\FleetCart\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\FleetCart\Http\Middleware\TrimStrings::class,
\FleetCart\Http\Middleware\ConvertStringBooleans::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\FleetCart\Http\Middleware\TrustProxies::class,
\FleetCart\Http\Middleware\RedirectToInstallerIfNotInstalled::class,
\FleetCart\Http\Middleware\RunUpdater::class,
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\FleetCart\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'bindings',
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array
*/
protected $routeMiddleware = [
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
}

View File

@@ -0,0 +1,41 @@
<?php
namespace FleetCart\Http\Middleware;
use Closure;
use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as BaseCheckForMaintenanceMode;
class CheckForMaintenanceMode extends BaseCheckForMaintenanceMode
{
/**
* The URIs that should be accessible while maintenance mode is enabled.
*
* @var array
*/
protected $except = [
'*/admin*',
];
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
* @throws \Illuminate\Foundation\Http\Exceptions\MaintenanceModeException
*/
public function handle($request, Closure $next)
{
if (
config('app.installed')
&& $this->app->isDownForMaintenance()
&& optional(auth()->user())->hasRoleName('Admin')
) {
return $next($request);
}
return parent::handle($request, $next);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace FleetCart\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TransformsRequest;
class ConvertStringBooleans extends TransformsRequest
{
/**
* Transform the given value.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
protected function transform($key, $value)
{
if ($value === 'true' || $value === 'TRUE') {
return true;
}
if ($value === 'false' || $value === 'FALSE') {
return false;
}
return $value;
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace FleetCart\Http\Middleware;
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
class EncryptCookies extends Middleware
{
/**
* The names of the cookies that should not be encrypted.
*
* @var array
*/
protected $except = [
'currency',
];
}

View File

@@ -0,0 +1,24 @@
<?php
namespace FleetCart\Http\Middleware;
use Closure;
class RedirectIfInstalled
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (config('app.installed')) {
return redirect()->route('home');
}
return $next($request);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace FleetCart\Http\Middleware;
use Closure;
use FleetCart\License;
class RedirectIfShouldNotCreateLicense
{
private $license;
public function __construct(License $license)
{
$this->license = $license;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($this->license->valid() || ! $this->license->shouldCreateLicense()) {
return redirect()->intended('/admin');
}
return $next($request);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace FleetCart\Http\Middleware;
use Closure;
class RedirectToInstallerIfNotInstalled
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (! config('app.installed') && ! $request->is('install/*')) {
return redirect()->route('install.pre_installation');
}
return $next($request);
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace FleetCart\Http\Middleware;
use Closure;
use FleetCart\Updater;
class RunUpdater
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (config('app.installed') && file_exists(storage_path('app/update'))) {
Updater::run();
}
return $next($request);
}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace FleetCart\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\TrimStrings as BaseTrimmer;
class TrimStrings extends BaseTrimmer
{
/**
* The names of the attributes that should not be trimmed.
*
* @var array
*/
protected $except = [
'password',
'password_confirmation',
];
}

View File

@@ -0,0 +1,28 @@
<?php
namespace FleetCart\Http\Middleware;
use Illuminate\Http\Request;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array
*/
protected $proxies = '*';
/**
* The current proxy header mappings.
*
* @var array
*/
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB;
}

View File

@@ -0,0 +1,17 @@
<?php
namespace FleetCart\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
//
];
}

View File

@@ -0,0 +1,77 @@
<?php
namespace FleetCart\Http\Requests;
use Illuminate\Validation\Rule;
use Modules\Core\Http\Requests\Request;
class InstallRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'db.host' => 'required',
'db.port' => 'required',
'db.username' => 'required',
'db.password' => 'nullable',
'db.database' => 'required',
'admin.first_name' => 'required',
'admin.last_name' => 'required',
'admin.email' => 'required|email',
'admin.phone' => 'required',
'admin.password' => 'required|confirmed|min:6',
'store.store_name' => 'required',
'store.store_email' => 'required|email',
'store.store_phone' => 'required',
'store.search_engine' => ['required', Rule::in(['mysql', 'algolia', 'meilisearch'])],
'store.algolia_app_id' => 'required_if:store.search_engine,algolia',
'store.algolia_secret' => 'required_if:store.search_engine,algolia',
'store.meilisearch_host' => 'required_if:store.search_engine,meilisearch',
'store.meilisearch_key' => 'required_if:store.search_engine,meilisearch',
];
}
/**
* Get custom attributes for validator errors.
*
* @return array
*/
public function attributes()
{
return [
'db.host' => 'host',
'db.port' => 'port',
'db.username' => 'username',
'db.password' => 'password',
'db.database' => 'datbase',
'admin.first_name' => 'first name',
'admin.last_name' => 'last name',
'admin.email' => 'email',
'admin.phone' => 'phone',
'admin.password' => 'password',
'store.store_name' => 'store name',
'store.store_email' => 'store email',
'store.store_phone' => 'store phone',
'store.search_engine' => 'search engine',
'store.algolia_app_id' => 'algolia application id',
'store.algolia_secret' => 'algolia admin api key',
'store.meilisearch_host' => 'meilisearch host',
'store.meilisearch_key' => 'meilisearch key',
];
}
}

View File

@@ -0,0 +1,148 @@
<?php
namespace FleetCart\Install;
use Modules\User\Entities\Role;
use Modules\User\Entities\User;
use Cartalyst\Sentinel\Laravel\Facades\Activation;
class AdminAccount
{
public function setup($data)
{
$role = Role::create(['name' => 'Admin', 'permissions' => $this->getAdminRolePermissions()]);
$admin = User::create([
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
'email' => $data['email'],
'phone' => $data['phone'],
'password' => bcrypt($data['password']),
]);
$activation = Activation::create($admin);
Activation::complete($admin, $activation->code);
$admin->roles()->attach($role);
}
private function getAdminRolePermissions()
{
return [
// users
'admin.users.index' => true,
'admin.users.create' => true,
'admin.users.edit' => true,
'admin.users.destroy' => true,
// roles
'admin.roles.index' => true,
'admin.roles.create' => true,
'admin.roles.edit' => true,
'admin.roles.destroy' => true,
// products
'admin.products.index' => true,
'admin.products.create' => true,
'admin.products.edit' => true,
'admin.products.destroy' => true,
// brands
'admin.brands.index' => true,
'admin.brands.create' => true,
'admin.brands.edit' => true,
'admin.brands.destroy' => true,
// attributes
'admin.attributes.index' => true,
'admin.attributes.create' => true,
'admin.attributes.edit' => true,
'admin.attributes.destroy' => true,
// attribute sets
'admin.attribute_sets.index' => true,
'admin.attribute_sets.create' => true,
'admin.attribute_sets.edit' => true,
'admin.attribute_sets.destroy' => true,
// options
'admin.options.index' => true,
'admin.options.create' => true,
'admin.options.edit' => true,
'admin.options.destroy' => true,
// filters
'admin.filters.index' => true,
'admin.filters.create' => true,
'admin.filters.edit' => true,
'admin.filters.destroy' => true,
// reviews
'admin.reviews.index' => true,
'admin.reviews.create' => true,
'admin.reviews.edit' => true,
'admin.reviews.destroy' => true,
// categories
'admin.categories.index' => true,
'admin.categories.create' => true,
'admin.categories.edit' => true,
'admin.categories.destroy' => true,
// tags
'admin.tags.index' => true,
'admin.tags.create' => true,
'admin.tags.edit' => true,
'admin.tags.destroy' => true,
// orders
'admin.orders.index' => true,
'admin.orders.show' => true,
'admin.orders.edit' => true,
// flash sales
'admin.flash_sales.index' => true,
'admin.flash_sales.create' => true,
'admin.flash_sales.edit' => true,
'admin.flash_sales.destroy' => true,
// transactions
'admin.transactions.index' => true,
// coupons
'admin.coupons.index' => true,
'admin.coupons.create' => true,
'admin.coupons.edit' => true,
'admin.coupons.destroy' => true,
// menus
'admin.menus.index' => true,
'admin.menus.create' => true,
'admin.menus.edit' => true,
'admin.menus.destroy' => true,
'admin.menu_items.index' => true,
'admin.menu_items.create' => true,
'admin.menu_items.edit' => true,
'admin.menu_items.destroy' => true,
// Media
'admin.media.index' => true,
'admin.media.create' => true,
'admin.media.destroy' => true,
// pages
'admin.pages.index' => true,
'admin.pages.create' => true,
'admin.pages.edit' => true,
'admin.pages.destroy' => true,
// currency rates
'admin.currency_rates.index' => true,
'admin.currency_rates.edit' => true,
// tax
'admin.taxes.index' => true,
'admin.taxes.create' => true,
'admin.taxes.edit' => true,
'admin.taxes.destroy' => true,
// translations
'admin.translations.index' => true,
'admin.translations.edit' => true,
// appearance
'admin.sliders.index' => true,
'admin.sliders.create' => true,
'admin.sliders.edit' => true,
'admin.sliders.destroy' => true,
// import
'admin.importer.index' => true,
'admin.importer.create' => true,
// reports
'admin.reports.index' => true,
// settings
'admin.settings.edit' => true,
// storefront
'admin.storefront.edit' => true,
];
}
}

111
app/Install/App.php Normal file
View File

@@ -0,0 +1,111 @@
<?php
namespace FleetCart\Install;
use Modules\User\Entities\Role;
use Modules\Setting\Entities\Setting;
use Illuminate\Support\Facades\Artisan;
use Modules\Currency\Entities\CurrencyRate;
use Jackiedo\DotenvEditor\Facades\DotenvEditor;
class App
{
public function setup()
{
$this->generateAppKey();
$this->setEnvVariables();
$this->createCustomerRole();
$this->setAppSettings();
$this->createDefaultCurrencyRate();
$this->createStorageFolder();
}
private function generateAppKey()
{
Artisan::call('key:generate', ['--force' => true]);
}
private function setEnvVariables()
{
$env = DotenvEditor::load();
$env->setKey('APP_ENV', 'production');
$env->setKey('APP_DEBUG', 'false');
$env->setKey('APP_CACHE', 'true');
$env->setKey('APP_URL', url('/'));
$env->save();
}
private function createCustomerRole()
{
Role::create(['name' => 'Customer']);
}
private function setAppSettings()
{
Setting::setMany([
'active_theme' => 'Storefront',
'supported_countries' => ['BD'],
'default_country' => 'BD',
'supported_locales' => ['en'],
'default_locale' => 'en',
'default_timezone' => 'Asia/Dhaka',
'customer_role' => 2,
'reviews_enabled' => true,
'auto_approve_reviews' => true,
'cookie_bar_enabled' => true,
'supported_currencies' => ['USD'],
'default_currency' => 'USD',
'send_order_invoice_email' => false,
'store_email' => 'admin@fleetcart.test',
'newsletter_enabled' => false,
'search_engine' => 'mysql',
'local_pickup_cost' => 0,
'flat_rate_cost' => 0,
'translatable' => [
'store_name' => 'FleetCart',
'free_shipping_label' => 'Free Shipping',
'local_pickup_label' => 'Local Pickup',
'flat_rate_label' => 'Flat Rate',
'paypal_label' => 'PayPal',
'paypal_description' => 'Pay via your PayPal account.',
'stripe_label' => 'Stripe',
'stripe_description' => 'Pay via credit or debit card.',
'paytm_label' => 'Paytm',
'paytm_description' => 'The best payment gateway provider in India for e-payment through credit card, debit card & net banking.',
'razorpay_label' => 'Razorpay',
'razorpay_description' => 'Pay securely by Credit or Debit card or Internet Banking through Razorpay.',
'instamojo_label' => 'Instamojo',
'instamojo_description' => 'CC/DB/NB/Wallets',
'authorizenet_label' => 'Authorize.net',
'authorizenet_description' => 'Accept payments anytime, anywhere',
'paystack_label' => 'Paystack',
'paystack_description' => 'Modern online and offline payments for Africa',
'flutterwave_label' => 'Flutterwave',
'flutterwave_description' => 'Endless possibilities for every business',
'mercadopago_label' => 'Mercado Pago',
'mercadopago_description' => 'From now on, do more with your money',
'cod_label' => 'Cash On Delivery',
'cod_description' => 'Pay with cash upon delivery.',
'bank_transfer_label' => 'Bank Transfer',
'bank_transfer_description' => 'Make your payment directly into our bank account. Please use your Order ID as the payment reference.',
'check_payment_label' => 'Check / Money Order',
'check_payment_description' => 'Please send a check to our store.',
],
'storefront_copyright_text' => 'Copyright © <a href="{{ store_url }}">{{ store_name }}</a> {{ year }}. All rights reserved.',
]);
}
private function createDefaultCurrencyRate()
{
CurrencyRate::create(['currency' => 'USD', 'rate' => 1]);
}
private function createStorageFolder()
{
if (!is_dir(public_path('storage'))) {
mkdir(public_path('storage'));
}
}
}

55
app/Install/Database.php Normal file
View File

@@ -0,0 +1,55 @@
<?php
namespace FleetCart\Install;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Artisan;
use Jackiedo\DotenvEditor\Facades\DotenvEditor;
class Database
{
public function setup($data)
{
$this->checkDatabaseConnection($data);
$this->setEnvVariables($data);
$this->migrateDatabase();
}
private function checkDatabaseConnection($data)
{
$this->setupDatabaseConnectionConfig($data);
DB::connection('mysql')->reconnect();
DB::connection('mysql')->getPdo();
}
private function setupDatabaseConnectionConfig($data)
{
config([
'database.default' => 'mysql',
'database.connections.mysql.host' => $data['host'],
'database.connections.mysql.port' => $data['port'],
'database.connections.mysql.database' => $data['database'],
'database.connections.mysql.username' => $data['username'],
'database.connections.mysql.password' => $data['password'],
]);
}
private function setEnvVariables($data)
{
$env = DotenvEditor::load();
$env->setKey('DB_HOST', $data['host']);
$env->setKey('DB_PORT', $data['port']);
$env->setKey('DB_DATABASE', $data['database']);
$env->setKey('DB_USERNAME', $data['username']);
$env->setKey('DB_PASSWORD', $data['password']);
$env->save();
}
private function migrateDatabase()
{
Artisan::call('migrate', ['--force' => true]);
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace FleetCart\Install;
class Requirement
{
public function extensions()
{
return [
'PHP >= 8.0.2' => version_compare(phpversion(), '8.0.2'),
'Intl PHP Extension' => extension_loaded('intl'),
'OpenSSL PHP Extension' => extension_loaded('openssl'),
'PDO PHP Extension' => extension_loaded('pdo'),
'Mbstring PHP Extension' => extension_loaded('mbstring'),
'Tokenizer PHP Extension' => extension_loaded('tokenizer'),
'XML PHP Extension' => extension_loaded('xml'),
'Ctype PHP Extension' => extension_loaded('ctype'),
'JSON PHP Extension' => extension_loaded('json'),
];
}
public function directories()
{
return [
'.env' => is_writable(base_path('.env')),
'storage' => is_writable(storage_path()),
'bootstrap/cache' => is_writable(app()->bootstrapPath('cache')),
];
}
public function satisfied()
{
return collect($this->extensions())
->merge($this->directories())
->every(function ($item) {
return $item;
});
}
}

22
app/Install/Store.php Normal file
View File

@@ -0,0 +1,22 @@
<?php
namespace FleetCart\Install;
use Modules\Setting\Entities\Setting;
class Store
{
public function setup($data)
{
Setting::setMany([
'translatable' => [
'store_name' => $data['store_name'],
],
'store_email' => $data['store_email'],
'store_phone' => $data['store_phone'],
'search_engine' => $data['search_engine'],
'algolia_app_id' => $data['algolia_app_id'],
'algolia_secret' => $data['algolia_secret'],
]);
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace FleetCart\Providers;
use Illuminate\Support\Facades\URL;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Request;
use Illuminate\Support\ServiceProvider;
use Jackiedo\DotenvEditor\DotenvEditorServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
Schema::defaultStringLength(191);
Paginator::useBootstrap();
if (Request::secure()) {
URL::forceScheme('https');
}
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
if (! config('app.installed')) {
$this->app->register(DotenvEditorServiceProvider::class);
}
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace FleetCart\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class RouteServiceProvider extends ServiceProvider
{
/**
* This namespace is applied to your controller routes.
*
* In addition, it is set as the URL generator's root namespace.
*
* @var string
*/
protected $namespace = 'FleetCart\Http\Controllers';
/**
* Define the routes for the application.
*
* @return void
*/
public function map()
{
$this->mapWebRoutes();
}
/**
* Define the "web" routes for the application.
*
* These routes all receive session state, CSRF protection, etc.
*
* @return void
*/
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
}

View File

@@ -0,0 +1,249 @@
<?php
namespace FleetCart\Scaffold\Module\Generators;
use DateTime;
class EntityGenerator extends Generator
{
/**
* Array of views to be generated.
*
* @var array
*/
protected $views = [
'views/index.stub' => 'Resources/views/admin/$ENTITY_NAME$/index.blade.php',
'views/create.stub' => 'Resources/views/admin/$ENTITY_NAME$/create.blade.php',
'views/edit.stub' => 'Resources/views/admin/$ENTITY_NAME$/edit.blade.php',
'views/shortcuts.stub' => 'Resources/views/admin/$ENTITY_NAME$/partials/shortcuts.blade.php',
];
/**
* Generate the given entities.
*
* @param array $entities
* @param bool $generateSidebar
* @return void
*/
public function generate(array $entities, $generateSidebar = true)
{
if (count($entities) !== 0 && $generateSidebar) {
$this->generateSidebarExtender($entities);
}
foreach ($entities as $entity) {
$this->appendPermissions($entity);
$this->generateMigrations($entity);
$this->generateEntity($entity);
$this->generateController($entity);
$this->generateRequests($entity);
$this->generateLang($entity);
$this->generateViews($entity);
$this->appendRoutes($entity);
$this->appendSidebarExtender($entity);
}
}
/**
* Generate a filled sidebar view composer
* Or an empty one of no entities.
*
* @param $entities
* @return void
*/
private function generateSidebarExtender($entities)
{
return $this->finder->put(
$this->getModulesPath('Sidebar/SidebarExtender.php'),
$this->getContentForStub('sidebar/sidebar-extender.stub', $entities[0])
);
}
/**
* Append permissions.
*
* @param string $entity
* @return void
*/
private function appendPermissions($entity)
{
$permissionsContent = $this->finder->get($this->getModulesPath('Config/permissions.php'));
$this->finder->put(
$this->getModulesPath('Config/permissions.php'),
str_replace('// append', $this->getContentForStub('config/permissions-append.stub', $entity), $permissionsContent)
);
}
/**
* Generate migrations file for eloquent entities.
*
* @param string $entity
* @return void
*/
private function generateMigrations($entity)
{
$entityName = snake_case(str_plural($entity));
$migrationFileName = $this->getDateTimePrefix() . "create_{$entityName}_table.php";
$this->finder->put(
$this->getModulesPath("Database/Migrations/{$migrationFileName}"),
$this->getContentForStub('migrations/create-table-migration.stub', $entity)
);
$migrationFileName = $this->getDateTimePrefix() . 'create_' . str_singular($entityName) . '_translations_table.php';
$this->finder->put(
$this->getModulesPath("Database/Migrations/{$migrationFileName}"),
$this->getContentForStub('migrations/create-translation-table-migration.stub', $entity)
);
}
/**
* Get the current time with microseconds.
*
* @return string
* @return void
*/
private function getDateTimePrefix()
{
$time = microtime(true);
$micro = sprintf('%06d', ($time - floor($time)) * 1000000);
$date = new DateTime(date('Y-m-d H:i:s.' . $micro, $time));
return $date->format('Y_m_d_Hisu_');
}
/**
* Generate entity.
*
* @param string $entity
* @return void
*/
private function generateEntity($entity)
{
$this->finder->put(
$this->getModulesPath("Entities/{$entity}.php"),
$this->getContentForStub('entities/entity.stub', $entity)
);
$this->finder->put(
$this->getModulesPath("Entities/{$entity}Translation.php"),
$this->getContentForStub('entities/translation-entity.stub', $entity)
);
}
/**
* Generate the controller for the given entity.
*
* @param string $entity
* @return void
*/
private function generateController($entity)
{
$this->createDirectory('Http/Controllers/Admin');
$this->finder->put(
$this->getModulesPath("Http/Controllers/Admin/{$entity}Controller.php"),
$this->getContentForStub('admin-controller.stub', $entity)
);
}
/**
* Generate the requests for the given entity.
*
* @param string $entity
* @return void
*/
private function generateRequests($entity)
{
$this->createDirectory('Http/Requests');
$this->finder->put(
$this->getModulesPath("Http/Requests/Save{$entity}Request.php"),
$this->getContentForStub('save-entity-request.stub', $entity)
);
}
/**
* Generate views for the given entity.
*
* @param string $entity
* @return void
*/
private function generateViews($entity)
{
$entityName = snake_case(str_plural($entity));
$this->createDirectory("Resources/views/admin/{$entityName}/partials");
foreach ($this->views as $stub => $view) {
$view = str_replace('$ENTITY_NAME$', $entityName, $view);
$this->finder->put(
$this->getModulesPath($view),
$this->getContentForStub($stub, $entity)
);
}
}
/**
* Generate language files for the given entity.
*
* @param string $entity
* @return void
*/
private function generateLang($entity)
{
$this->createDirectory('Resources/lang/en');
$entityName = snake_case(str_plural($entity));
$this->finder->put(
$this->getModulesPath("Resources/lang/en/{$entityName}.php"),
$this->getContentForStub('lang/entity.stub', $entity)
);
$this->finder->put(
$this->getModulesPath('Resources/lang/en/permissions.php'),
$this->getContentForStub('lang/permissions.stub', $entity)
);
$this->finder->put(
$this->getModulesPath('Resources/lang/en/attributes.php'),
$this->getContentForStub('lang/attributes.stub', $entity)
);
}
/**
* Append the routes for the given entity to the routes file.
*
* @param string $entity
* @return void
*/
private function appendRoutes($entity)
{
$routeContent = $this->finder->get($this->getModulesPath('Routes/admin.php'));
$this->finder->put(
$this->getModulesPath('Routes/admin.php'),
str_replace('// append', $this->getContentForStub('routes/routes-append.stub', $entity), $routeContent)
);
}
/**
* Append sidebar extender.
*
* @param string $entity
* @return void
*/
private function appendSidebarExtender($entity)
{
$sidebarComposerContent = $this->finder->get($this->getModulesPath('Sidebar/SidebarExtender.php'));
$this->finder->put(
$this->getModulesPath('Sidebar/SidebarExtender.php'),
str_replace('// append', $this->getContentForStub('sidebar/sidebar-extender-append.stub', $entity), $sidebarComposerContent)
);
}
}

View File

@@ -0,0 +1,58 @@
<?php
namespace FleetCart\Scaffold\Module\Generators;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
class FilesGenerator extends Generator
{
/**
* Generate the given files.
*
* @param array $files
* @return void
*/
public function generate(array $files)
{
foreach ($files as $stub => $file) {
$this->finder->put(
$this->getModulesPath($file),
$this->getContentFor($stub)
);
}
}
/**
* Generate the base module service provider.
*
* @return $this
*/
public function generateModuleProvider()
{
$this->finder->put(
$this->getModulesPath("Providers/{$this->name}ServiceProvider.php"),
$this->getContentFor('providers/module-service-provider.stub')
);
return $this;
}
/**
* Get the content for the given file.
*
* @param string $stub
* @return string
*
* @throws FileNotFoundException
*/
private function getContentFor($stub)
{
$stub = $this->finder->get($this->getStubPath($stub));
return str_replace(
['$MODULE$', '$LOWERCASE_MODULE$', '$PLURAL_MODULE$', '$UPPERCASE_PLURAL_MODULE$'],
[$this->name, strtolower($this->name), strtolower(str_plural($this->name)), str_plural($this->name)],
$stub
);
}
}

View File

@@ -0,0 +1,134 @@
<?php
namespace FleetCart\Scaffold\Module\Generators;
use Illuminate\Filesystem\Filesystem;
abstract class Generator
{
/**
* The instance of Filesystem.
*
* @var \Illuminate\Filesystem\Filesystem
*/
protected $finder;
/**
* Name of the module.
*
* @var string
*/
protected $name;
/**
* Create a new instance.
*
* @param \Illuminate\Filesystem\Filesystem $finder
*/
public function __construct(Filesystem $finder)
{
$this->finder = $finder;
}
/**
* Generate the given files.
*
* @param array $files
* @return void
*/
abstract public function generate(array $files);
/**
* Set the module name.
*
* @param string $name
* @return $this
*/
public function module($name)
{
$this->name = ucfirst($name);
return $this;
}
/**
* Return the current module path.
*
* @param string $path
* @return string
*/
protected function getModulesPath($path = '')
{
return config('modules.paths.modules') . "/{$this->name}/{$path}";
}
/**
* Create directory if not exists.
*
* @param string $path
* @return string
*/
protected function createDirectory($path)
{
$path = $this->getModulesPath($path);
if (! $this->finder->isDirectory($path)) {
$this->finder->makeDirectory($path, 0755, true);
}
return $path;
}
/**
* Get stub path for the given stub file.
*
* @param string $filename
* @return string
*/
protected function getStubPath($filename)
{
return __DIR__ . "/../stubs/{$filename}";
}
/**
* Get content of the given stub.
*
* @param string $stub
* @param string $class
* @return string
*/
protected function getContentForStub($stub, $class = '')
{
$stub = $this->finder->get($this->getStubPath($stub));
return str_replace([
'$MODULE_NAME$',
'$LOWERCASE_MODULE_NAME$',
'$LCFIRST_ENTITY_NAME$',
'$ENTITY_NAME$',
'$LOWERCASE_ENTITY_NAME$',
'$TITLE_CASE_ENTITY_NAME$',
'$SNAKE_CASE_ENTITY_NAME$',
'$KEBAB_CASE_ENTITY_NAME$',
'$PLURAL_ENTITY_NAME$',
'$PLURAL_LOWERCASE_ENTITY_NAME$',
'$PLURAL_TITLE_CASE_ENTITY_NAME$',
'$PLURAL_SNAKE_CASE_ENTITY_NAME$',
'$PLURAL_KEBAB_CASE_ENTITY_NAME$',
], [
$this->name,
strtolower($this->name),
lcfirst($class),
$class,
strtolower($class),
title_case(str_replace('_', ' ', snake_case($class))),
snake_case($class),
kebab_case($class),
str_plural($class),
str_plural(strtolower($class)),
title_case(str_replace('_', ' ', snake_case(str_plural($class)))),
snake_case(str_plural($class)),
kebab_case(str_plural($class)),
], $stub);
}
}

View File

@@ -0,0 +1,333 @@
<?php
namespace FleetCart\Scaffold\Module;
use Illuminate\Filesystem\Filesystem;
use Illuminate\Support\Facades\Artisan;
use FleetCart\Scaffold\Module\Generators\FilesGenerator;
use FleetCart\Scaffold\Module\Generators\EntityGenerator;
class ModuleScaffold
{
/**
* The vendor name of the module.
*
* @var string
*/
protected $vendor;
/**
* The module name which will be generated.
*
* @var string
*/
protected $name;
/**
* The instance of Filesystem.
*
* @var \Illuminate\Filesystem\Filesystem
*/
private $finder;
/**
* The instance of EntityGenerator.
*
* @var \FleetCart\Scaffold\Module\Generators\EntityGenerator
*/
private $entityGenerator;
/**
* The instance of FilesGenerator.
*
* @var \FleetCart\Scaffold\Module\Generators\FilesGenerator
*/
private $filesGenerator;
/**
* Array of files to be generated.
*
* @var array
*/
protected $files = [
'config/assets.stub' => 'Config/assets.php',
'config/permissions.stub' => 'Config/permissions.php',
'routes/routes.stub' => 'Routes/admin.php',
];
/**
* Create a new instance.
*
* @param \Illuminate\Filesystem\Filesystem $finder
* @param \FleetCart\Scaffold\Module\Generators\EntityGenerator $entityGenerator
* @param \FleetCart\Scaffold\Module\Generators\FilesGenerator $filesGenerator
*/
public function __construct(Filesystem $finder, EntityGenerator $entityGenerator, FilesGenerator $filesGenerator)
{
$this->finder = $finder;
$this->entityGenerator = $entityGenerator;
$this->filesGenerator = $filesGenerator;
}
/**
* @param array $module
* @param array $entities
* @return void
*/
public function scaffold(array $module, array $entities)
{
$this->vendor = $module['vendor'];
$this->name = $module['name'];
Artisan::call('module:make', ['name' => [$this->name]]);
$this->addFolders();
$this->removeUnneededFiles();
$this->addDataToComposerJsonFile();
$this->filesGenerator->module($this->name)
->generateModuleProvider()
->generate($this->files);
$this->addDataToModuleJson();
$this->cleanupModuleJsonFile();
$this->entityGenerator->module($this->getName())->generate($entities);
}
/**
* Get studly cased module name.
*
* @return string
*/
public function getName()
{
return studly_case($this->name);
}
/**
* Get the path on the module.
*
* @return string
*/
private function getModulesPath($path = '')
{
return config('modules.paths.modules') . "/{$this->getName()}/{$path}";
}
/**
* Get the paths on the module.
*
* @param array $paths
* @return array
*/
private function getModulesPaths(array $paths)
{
$list = [];
foreach ($paths as $path) {
$list[] = $this->getModulesPath($path);
}
return $list;
}
/**
* Remove vendor name from composer.json file.
*
* @return void
*/
private function renameVendorName()
{
$composerJsonContent = $this->finder->get($this->getModulesPath('composer.json'));
$composerJsonContent = str_replace('nwidart', $this->vendor, $composerJsonContent);
$this->finder->put($this->getModulesPath('composer.json'), $composerJsonContent);
}
/**
* Remove view files.
*
* @return void
*/
private function removeViewFiles()
{
$this->finder->delete($this->getModulesPath('Resources/views/index.blade.php'));
$this->finder->delete($this->getModulesPath('Resources/views/layouts/master.blade.php'));
$this->finder->deleteDirectory($this->getModulesPath('Resources/views/layouts'));
}
/**
* Add required folders.
*
* @return void
*/
private function addFolders()
{
$this->finder->makeDirectory($this->getModulesPath('Sidebar'));
}
/**
* Remove unneeded files and folders.
*
* @return void
*/
private function removeUnneededFiles()
{
$this->renameVendorName();
$this->removeViewFiles();
$this->finder->deleteDirectory($this->getModulesPath('Database/factories'));
$this->finder->deleteDirectory($this->getModulesPath('Database/Seeders'));
$this->finder->deleteDirectory($this->getModulesPath('Events'));
$this->finder->deleteDirectory($this->getModulesPath('Console'));
$this->finder->deleteDirectory($this->getModulesPath('Http/Middleware'));
$this->finder->deleteDirectory($this->getModulesPath('Jobs'));
$this->finder->deleteDirectory($this->getModulesPath('Mail'));
$this->finder->deleteDirectory($this->getModulesPath('Resources/assets'));
$this->finder->deleteDirectory($this->getModulesPath('Tests'));
$files = $this->getModulesPaths([
'Config/.gitkeep',
'Config/config.php',
'Entities/.gitkeep',
'Database/Migrations/.gitkeep',
'Http/Controllers/.gitkeep',
'Http/Requests/.gitkeep',
"Http/Controllers/{$this->name}Controller.php",
'Providers/.gitkeep',
'Providers/RouteServiceProvider.php',
'Resources/lang/.gitkeep',
'Resources/views/.gitkeep',
'Routes/.gitkeep',
'Routes/web.php',
'Routes/api.php',
'package.json',
'webpack.mix.js',
]);
$this->finder->delete($files);
}
/**
* Add data to module.json file.
*
* @return void
*/
private function addDataToModuleJson()
{
$moduleJson = $this->finder->get($this->getModulesPath('module.json'));
$moduleJson = $this->setModulePriority($moduleJson);
$this->finder->put($this->getModulesPath('module.json'), $moduleJson);
}
/**
* Set the module priority for composer.json file.
*
* @return string
*/
private function setModulePriority($content)
{
return str_replace('"priority": 0,', '"priority": 100,', $content);
}
/**
* Remove unneeded data from module.json file.
*
* @return void
*/
private function cleanupModuleJsonFile()
{
$moduleJson = $this->finder->get($this->getModulesPath('module.json'));
$moduleName = ucfirst($this->name);
// Update module description.
$search = <<<JSON
"description": "",
JSON;
$replace = <<<JSON
"description": "The FleetCart {$moduleName} Module.",
JSON;
$moduleJson = str_replace($search, $replace, $moduleJson);
// Remove "keywords" node.
$search = <<<JSON
"keywords": [],
JSON;
$moduleJson = str_replace($search, '', $moduleJson);
// Remove unneeded nodes.
$search = <<<JSON
],
"aliases": {},
"files": [],
"requires": []
JSON;
$moduleJson = str_replace($search, ']', $moduleJson);
$this->finder->put($this->getModulesPath('module.json'), $moduleJson);
}
/**
* Add data to composer.json file.
*
* @return void
*/
private function addDataToComposerJsonFile()
{
$composerJson = $this->finder->get($this->getModulesPath('composer.json'));
$moduleName = ucfirst($this->name);
$composerJsonText = '';
foreach (explode(PHP_EOL, $composerJson) as $lineNumber => $textLine) {
if ($lineNumber === 2) {
$composerJsonText .= " \"description\": \"The FleetCart {$moduleName} Module.\"," . PHP_EOL;
continue;
} elseif ($lineNumber >= 9 && $lineNumber <= 23) {
continue;
}
$composerJsonText .= $textLine . PHP_EOL;
}
$search = <<<JSON
],
JSON;
$replace = <<<JSON
],
"require": {
"php": ">=7.3.0"
},
"autoload": {
"psr-4": {
"Modules\\\\{$moduleName}\\\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"config": {
"sort-packages": true
},
"minimum-stability": "dev"
}
JSON;
$composerJson = str_replace($search, $replace, $composerJsonText);
$this->finder->put($this->getModulesPath('composer.json'), $composerJson);
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace Modules\$MODULE_NAME$\Http\Controllers\Admin;
use Illuminate\Routing\Controller;
use Modules\Admin\Traits\HasCrudActions;
use Modules\$MODULE_NAME$\Entities\$ENTITY_NAME$;
use Modules\$MODULE_NAME$\Http\Requests\Save$ENTITY_NAME$Request;
class $ENTITY_NAME$Controller extends Controller
{
use HasCrudActions;
/**
* Model for the resource.
*
* @var string
*/
protected $model = $ENTITY_NAME$::class;
/**
* Label of the resource.
*
* @var string
*/
protected $label = '$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$SNAKE_CASE_ENTITY_NAME$';
/**
* View path of the resource.
*
* @var string
*/
protected $viewPath = '$LOWERCASE_MODULE_NAME$::admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$';
/**
* Form requests for the resource.
*
* @var array
*/
protected $validation = Save$ENTITY_NAME$Request::class;
}

View File

@@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Define which assets will be available through the asset manager
|--------------------------------------------------------------------------
| These assets are registered on the asset manager
*/
'all_assets' => [
'admin.$LOWERCASE_MODULE$.css' => ['module' => '$LOWERCASE_MODULE$:admin/css/$LOWERCASE_MODULE$.css'],
'admin.$LOWERCASE_MODULE$.js' => ['module' => '$LOWERCASE_MODULE$:admin/js/$LOWERCASE_MODULE$.js'],
],
/*
|--------------------------------------------------------------------------
| Define which default assets will always be included in your pages
| through the asset pipeline
|--------------------------------------------------------------------------
*/
'required_assets' => [],
];

View File

@@ -0,0 +1,8 @@
'admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$' => [
'index' => '$LOWERCASE_MODULE_NAME$::permissions.index',
'create' => '$LOWERCASE_MODULE_NAME$::permissions.create',
'edit' => '$LOWERCASE_MODULE_NAME$::permissions.edit',
'destroy' => '$LOWERCASE_MODULE_NAME$::permissions.destroy',
],
// append

View File

@@ -0,0 +1,5 @@
<?php
return [
// append
];

View File

@@ -0,0 +1,39 @@
<?php
namespace Modules\$MODULE_NAME$\Entities;
use Modules\Support\Eloquent\Model;
use Modules\Support\Eloquent\Translatable;
class $ENTITY_NAME$ extends Model
{
use Translatable;
/**
* The relations to eager load on every query.
*
* @var array
*/
protected $with = ['translations'];
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [];
/**
* The attributes that are translatable.
*
* @var array
*/
public $translatedAttributes = [];
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Modules\$MODULE_NAME$\Entities;
use Modules\Support\Eloquent\TranslationModel;
class $ENTITY_NAME$Translation extends TranslationModel
{
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [];
}

View File

@@ -0,0 +1,5 @@
<?php
return [
//
];

View File

@@ -0,0 +1,6 @@
<?php
return [
'$SNAKE_CASE_ENTITY_NAME$' => '$TITLE_CASE_ENTITY_NAME$',
'$PLURAL_SNAKE_CASE_ENTITY_NAME$' => '$PLURAL_TITLE_CASE_ENTITY_NAME$',
];

View File

@@ -0,0 +1,8 @@
<?php
return [
'index' => 'Index $TITLE_CASE_ENTITY_NAME$',
'create' => 'Create $TITLE_CASE_ENTITY_NAME$',
'edit' => 'Edit $TITLE_CASE_ENTITY_NAME$',
'destroy' => 'Delete $TITLE_CASE_ENTITY_NAME$',
];

View File

@@ -0,0 +1,31 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class Create$PLURAL_ENTITY_NAME$Table extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('$PLURAL_SNAKE_CASE_ENTITY_NAME$', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('$PLURAL_SNAKE_CASE_ENTITY_NAME$');
}
}

View File

@@ -0,0 +1,35 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class Create$ENTITY_NAME$TranslationsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('$SNAKE_CASE_ENTITY_NAME$_translations', function (Blueprint $table) {
$table->increments('id');
$table->integer('$SNAKE_CASE_ENTITY_NAME$_id')->unsigned();
$table->string('locale');
$table->unique(['$SNAKE_CASE_ENTITY_NAME$_id', 'locale']);
$table->foreign('$SNAKE_CASE_ENTITY_NAME$_id')->references('id')->on('$PLURAL_SNAKE_CASE_ENTITY_NAME$')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('$SNAKE_CASE_ENTITY_NAME$_translations');
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Modules\$MODULE$\Providers;
use Modules\Support\Traits\AddsAsset;
use Illuminate\Support\ServiceProvider;
class $MODULE$ServiceProvider extends ServiceProvider
{
use AddsAsset;
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
//
}
}

View File

@@ -0,0 +1,37 @@
Route::get('$PLURAL_KEBAB_CASE_ENTITY_NAME$', [
'as' => 'admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.index',
'uses' => '$ENTITY_NAME$Controller@index',
'middleware' => 'can:admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.index',
]);
Route::get('$PLURAL_KEBAB_CASE_ENTITY_NAME$/create', [
'as' => 'admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.create',
'uses' => '$ENTITY_NAME$Controller@create',
'middleware' => 'can:admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.create',
]);
Route::post('$PLURAL_KEBAB_CASE_ENTITY_NAME$', [
'as' => 'admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.store',
'uses' => '$ENTITY_NAME$Controller@store',
'middleware' => 'can:admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.create',
]);
Route::get('$PLURAL_KEBAB_CASE_ENTITY_NAME$/{id}/edit', [
'as' => 'admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.edit',
'uses' => '$ENTITY_NAME$Controller@edit',
'middleware' => 'can:admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.edit',
]);
Route::put('$PLURAL_KEBAB_CASE_ENTITY_NAME$/{id}', [
'as' => 'admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.update',
'uses' => '$ENTITY_NAME$Controller@update',
'middleware' => 'can:admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.edit',
]);
Route::delete('$PLURAL_KEBAB_CASE_ENTITY_NAME$/{ids?}', [
'as' => 'admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.destroy',
'uses' => '$ENTITY_NAME$Controller@destroy',
'middleware' => 'can:admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.destroy',
]);
// append

View File

@@ -0,0 +1,5 @@
<?php
use Illuminate\Support\Facades\Route;
// append

View File

@@ -0,0 +1,25 @@
<?php
namespace Modules\$MODULE_NAME$\Http\Requests;
use Modules\Core\Http\Requests\Request;
class Save$ENTITY_NAME$Request extends Request
{
/**
* Available attributes.
*
* @var string
*/
protected $availableAttributes = '$LOWERCASE_MODULE_NAME$::attributes';
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [];
}
}

View File

@@ -0,0 +1,9 @@
$item->item(trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$PLURAL_SNAKE_CASE_ENTITY_NAME$'), function (Item $item) {
$item->weight(5);
$item->route('admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.index');
$item->authorize(
$this->auth->hasAccess('admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.index')
);
});
// append

View File

@@ -0,0 +1,26 @@
<?php
namespace Modules\$MODULE_NAME$\Sidebar;
use Maatwebsite\Sidebar\Menu;
use Maatwebsite\Sidebar\Item;
use Maatwebsite\Sidebar\Group;
use Modules\Admin\Sidebar\BaseSidebarExtender;
class SidebarExtender extends BaseSidebarExtender
{
public function extend(Menu $menu)
{
$menu->group(trans('admin::sidebar.content'), function (Group $group) {
$group->item(trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$PLURAL_SNAKE_CASE_ENTITY_NAME$'), function (Item $item) {
$item->icon('fa fa-copy');
$item->weight(0);
$item->authorize(
/* append */
);
// append
});
});
}
}

View File

@@ -0,0 +1,16 @@
@extends('admin::layout')
@component('admin::components.page.header')
@slot('title', trans('admin::resource.create', ['resource' => trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$SNAKE_CASE_ENTITY_NAME$')]))
<li><a href="{{ route('admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.index') }}">{{ trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$PLURAL_SNAKE_CASE_ENTITY_NAME$') }}</a></li>
<li class="active">{{ trans('admin::resource.create', ['resource' => trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$SNAKE_CASE_ENTITY_NAME$')]) }}</li>
@endcomponent
@section('content')
<form method="POST" action="{{ route('admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.store') }}" class="form-horizontal" id="$KEBAB_CASE_ENTITY_NAME$-create-form" novalidate>
{{ csrf_field() }}
</form>
@endsection
@include('$LOWERCASE_MODULE_NAME$::admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.partials.shortcuts')

View File

@@ -0,0 +1,18 @@
@extends('admin::layout')
@component('admin::components.page.header')
@slot('title', trans('admin::resource.edit', ['resource' => trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$SNAKE_CASE_ENTITY_NAME$')]))
@slot('subtitle', '')
<li><a href="{{ route('admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.index') }}">{{ trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$PLURAL_SNAKE_CASE_ENTITY_NAME$') }}</a></li>
<li class="active">{{ trans('admin::resource.edit', ['resource' => trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$SNAKE_CASE_ENTITY_NAME$')]) }}</li>
@endcomponent
@section('content')
<form method="POST" action="{{ route('admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.update', $$LCFIRST_ENTITY_NAME$) }}" class="form-horizontal" id="$KEBAB_CASE_ENTITY_NAME$-edit-form" novalidate>
{{ csrf_field() }}
{{ method_field('put') }}
</form>
@endsection
@include('$LOWERCASE_MODULE_NAME$::admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.partials.shortcuts')

View File

@@ -0,0 +1 @@
@include('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$LOWERCASE_ENTITY_NAME$.partials.shortcuts')

View File

@@ -0,0 +1,32 @@
@extends('admin::layout')
@component('admin::components.page.header')
@slot('title', trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$PLURAL_SNAKE_CASE_ENTITY_NAME$'))
<li class="active">{{ trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$PLURAL_SNAKE_CASE_ENTITY_NAME$') }}</li>
@endcomponent
@component('admin::components.page.index_table')
@slot('buttons', ['create'])
@slot('resource', '$PLURAL_SNAKE_CASE_ENTITY_NAME$')
@slot('name', trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$SNAKE_CASE_ENTITY_NAME$'))
@component('admin::components.table')
@slot('thead')
<tr>
@include('admin::partials.table.select_all')
</tr>
@endslot
@endcomponent
@endcomponent
@push('scripts')
<script>
new DataTable('#$PLURAL_SNAKE_CASE_ENTITY_NAME$-table .table', {
columns: [
{ data: 'checkbox', orderable: false, searchable: false, width: '3%' },
//
],
});
</script>
@endpush

View File

@@ -0,0 +1,14 @@
@push('shortcuts')
<dl class="dl-horizontal">
<dt><code>b</code></dt>
<dd>{{ trans('admin::admin.shortcuts.back_to_index', ['name' => trans('$LOWERCASE_MODULE_NAME$::$PLURAL_SNAKE_CASE_ENTITY_NAME$.$SNAKE_CASE_ENTITY_NAME$')]) }}</dd>
</dl>
@endpush
@push('scripts')
<script>
keypressAction([
{ key: 'b', route: "{{ route('admin.$PLURAL_SNAKE_CASE_ENTITY_NAME$.index') }}" }
]);
</script>
@endpush

17
app/Scripts/V2_0_0.php Normal file
View File

@@ -0,0 +1,17 @@
<?php
namespace FleetCart\Scripts;
use FleetCart\FleetCart;
use Illuminate\Support\Facades\DB;
class V2_0_0
{
public function run()
{
if (version_compare(FleetCart::VERSION, '2.0.0', '=')) {
DB::delete("DELETE FROM `settings` WHERE `key` LIKE 'storefront_%' AND NOT `key` = 'storefront_copyright_text'");
DB::delete("DELETE FROM `translations` WHERE `key` LIKE 'storefront::%'");
}
}
}

72
app/Updater.php Normal file
View File

@@ -0,0 +1,72 @@
<?php
namespace FleetCart;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Artisan;
class Updater
{
public static function run()
{
@set_time_limit(0);
self::migrate();
self::clearViewCache();
self::clearConfigCache();
self::clearRouteCache();
self::clearAppCache();
self::runScripts();
File::delete(storage_path('app/update'));
}
private static function migrate()
{
if (config('app.installed')) {
Artisan::call('migrate', ['--force' => true]);
}
}
private static function clearViewCache()
{
Artisan::call('view:clear');
}
private static function clearConfigCache()
{
Artisan::call('config:clear');
}
private static function clearRouteCache()
{
Artisan::call('route:trans:clear');
}
private static function clearAppCache()
{
Artisan::call('cache:clear');
}
private static function runScripts()
{
$previouslyRan = DB::table('updater_scripts')->get();
$ran = [];
foreach (File::files(app_path('Scripts')) as $file) {
require $file->getRealPath();
$script = $file->getBasename('.php');
if (! $previouslyRan->contains($script)) {
resolve("FleetCart\\Scripts\\{$script}")->run();
$ran[] = ['script' => $script];
}
}
DB::table('updater_scripts')->insert($ran);
}
}