88use Illuminate \Support \Facades \Crypt ;
99use Illuminate \Support \Facades \DB ;
1010use Illuminate \Support \Facades \File ;
11+ use Illuminate \Support \Facades \Process ;
1112use ProcessMaker \Multitenancy \Tenant ;
1213
1314class TenantsCreate extends Command
@@ -17,7 +18,17 @@ class TenantsCreate extends Command
1718 *
1819 * @var string
1920 */
20- protected $ signature = 'tenants:create {--name=} {--url=} {--database=} {--username=} {--password=} {--storage-folder=} {--lang-folder=} {--app-key=} ' ;
21+ protected $ signature = 'tenants:create
22+ {--name=}
23+ {--url=}
24+ {--database=}
25+ {--username=}
26+ {--password=}
27+ {--storage-folder=}
28+ {--lang-folder=}
29+ {--app-key=}
30+ {--skip-initialize-folders}
31+ {--skip-setup-notifications} ' ;
2132
2233 /**
2334 * The console command description.
@@ -31,6 +42,17 @@ class TenantsCreate extends Command
3142 */
3243 public function handle ()
3344 {
45+ $ infoCallback = function ($ type , $ message ) {
46+ if ($ type === 'out ' ) {
47+ $ this ->info ($ message );
48+ } else {
49+ $ this ->error ($ message );
50+ }
51+ };
52+
53+ // Check if rsync exists
54+ Process::run ('which rsync ' )->throw ();
55+
3456 $ requiredOptions = ['name ' , 'database ' , 'url ' ];
3557
3658 foreach ($ requiredOptions as $ option ) {
@@ -82,21 +104,8 @@ public function handle()
82104 if ($ storageFolderOption ) {
83105 if (File::isDirectory ($ storageFolderOption )) {
84106 $ this ->info ('Moving storage folder to ' . $ tenantStoragePath );
85- $ subfoldersToExclude = '/^(tenant_\d+|logs|transitions)$/i ' ;
86- foreach (File::directories ($ storageFolderOption ) as $ subfolder ) {
87- if (preg_match ($ subfoldersToExclude , basename ($ subfolder ))) {
88- $ this ->info ('Skipping ' . $ subfolder );
89- continue ;
90- }
91- $ this ->info ('Moving ' . $ subfolder . ' to ' . $ tenantStoragePath );
92- rename ($ subfolder , $ tenantStoragePath . '/ ' . basename ($ subfolder ));
93- }
94-
95- // Move all files from the root storage folder to the tenant storage folder
96- foreach (File::files ($ storageFolderOption ) as $ file ) {
97- $ this ->info ('Moving ' . $ file . ' to ' . $ tenantStoragePath );
98- rename ($ file , $ tenantStoragePath . '/ ' . basename ($ file ));
99- }
107+ $ cmd = "rsync -avz --exclude='tenant_*' --exclude='logs' --exclude='transitions' " . $ storageFolderOption . '/ ' . $ tenantStoragePath ;
108+ Process::run ($ cmd , $ infoCallback )->throw ();
100109 } else {
101110 $ this ->error ('Storage folder does not exist: ' . $ storageFolderOption );
102111
@@ -110,13 +119,14 @@ public function handle()
110119 $ tenantLangPath = resource_path ('lang/tenant_ ' . $ tenant ->id );
111120 if ($ langFolderOption ) {
112121 if (File::isDirectory ($ langFolderOption )) {
113- $ this ->info ('Moving lang folder to ' . $ tenantLangPath );
122+ $ this ->info ('Copying lang folder to ' . $ tenantLangPath );
114123 if (File::isDirectory ($ tenantLangPath )) {
115124 $ this ->error ('Tenant lang path already exists: ' . $ tenantLangPath );
116125
117126 return 1 ;
118127 } else {
119- rename ($ langFolderOption , $ tenantLangPath );
128+ $ cmd = "rsync -avz --exclude='tenant_*' " . $ langFolderOption . '/ ' . $ tenantLangPath ;
129+ Process::run ($ cmd , $ infoCallback )->throw ();
120130 }
121131 } else {
122132 $ this ->error ('Lang folder does not exist: ' . $ langFolderOption );
@@ -130,16 +140,13 @@ public function handle()
130140 }
131141 }
132142
133- $ cmd = sprintf (
134- "rsync -azv --ignore-existing --exclude='tenant_*' %s %s " ,
135- escapeshellarg ($ sourceLangPath . '/ ' ),
136- escapeshellarg ($ tenantLangPath )
137- );
138- exec ($ cmd , $ output , $ returnVar );
139- if ($ returnVar !== 0 ) {
140- $ this ->error ('Failed to rsync lang folder to tenant: ' . implode (PHP_EOL , $ output ));
141-
142- return 1 ;
143+ if (!$ this ->option ('skip-initialize-folders ' )) {
144+ $ cmd = sprintf (
145+ "rsync -azv --ignore-existing --exclude='tenant_*' %s %s " ,
146+ escapeshellarg ($ sourceLangPath . '/ ' ),
147+ escapeshellarg ($ tenantLangPath )
148+ );
149+ Process::run ($ cmd , $ infoCallback )->throw ();
143150 }
144151
145152 $ subfolders = [
@@ -163,9 +170,11 @@ public function handle()
163170 'api-docs ' ,
164171 ];
165172
166- foreach ($ subfolders as $ subfolder ) {
167- if (!File::isDirectory ($ tenantStoragePath . '/ ' . $ subfolder )) {
168- mkdir ($ tenantStoragePath . '/ ' . $ subfolder , 0755 , true );
173+ if (!$ this ->option ('skip-initialize-folders ' )) {
174+ foreach ($ subfolders as $ subfolder ) {
175+ if (!File::isDirectory ($ tenantStoragePath . '/ ' . $ subfolder )) {
176+ mkdir ($ tenantStoragePath . '/ ' . $ subfolder , 0755 , true );
177+ }
169178 }
170179 }
171180
@@ -183,20 +192,15 @@ public function handle()
183192 // Setup database
184193 DB ::connection ('landlord ' )->statement ("CREATE DATABASE IF NOT EXISTS ` {$ this ->option ('database ' )}` " );
185194
186- // Hold off on this for now.
187- // $this->tenantArtisan('tenant:storage-link', $tenant->id);
188-
189- // Must be run after migrations so skip it. (provider somewhere complains about a table missing)
190- // $this->tenantArtisan('passport:keys --force', $tenant->id);
191-
192- $ this ->info ("Empty tenant created. \n" );
193- $ this ->info ("With the tenant set (using TENANT= {$ tenant ->id } env prefix) you must now: " );
194- $ this ->line ('- Run migrations ' );
195- $ this ->line ('- Seed the database ' );
196- $ this ->line ('- Run the install command for each package ' );
197- $ this ->line ('- Run artisan upgrade ' );
198- $ this ->line ('- Generate passport keys with artisan passport:keys ' );
199- $ this ->info ("For example, `TENANT= {$ tenant ->id } php artisan migrate:fresh --seed` " );
195+ $ this ->info ("Empty tenant created. ID: {$ tenant ->id }" );
196+ if (!$ this ->option ('skip-setup-notifications ' )) {
197+ $ this ->info ("You will need to do the following using TENANT= {$ tenant ->id } env prefix " );
198+ $ this ->line ('- Run migrations and seed the database ' );
199+ $ this ->line ('- Run the install command for each package ' );
200+ $ this ->line ('- Run artisan upgrade ' );
201+ $ this ->line ('- Install passport by calling passport:install ' );
202+ $ this ->info ("For example, `TENANT= {$ tenant ->id } php artisan migrate:fresh --seed` " );
203+ }
200204 }
201205
202206 private function tenantArtisan ($ command , $ tenantId )
0 commit comments