├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml ├── public └── .gitkeep ├── src ├── DavinBao │ └── Workflow │ │ ├── ControllersCommand.php │ │ ├── HasFlowForResource.php │ │ ├── HasFlowForResourceController.php │ │ ├── HasNodeForRole.php │ │ ├── HasNodeForUser.php │ │ ├── MigrationCommand.php │ │ ├── ModelsCommand.php │ │ ├── RoutesCommand.php │ │ ├── Workflow.php │ │ ├── WorkflowFacade.php │ │ ├── WorkflowFlow.php │ │ ├── WorkflowNode.php │ │ ├── WorkflowResourceLog.php │ │ ├── WorkflowResourceflow.php │ │ ├── WorkflowResourcenode.php │ │ └── WorkflowServiceProvider.php ├── config │ ├── .gitkeep │ └── config.php ├── controllers │ └── .gitkeep ├── lang │ ├── .gitkeep │ └── zh_CN │ │ ├── button.php │ │ └── workflow.php ├── migrations │ └── .gitkeep └── views │ ├── .gitkeep │ ├── audit_detail.blade.php │ ├── audit_form.blade.php │ ├── binding_form.blade.php │ ├── flow_form.blade.php │ ├── flow_graph.blade.php │ └── generators │ ├── AdminFlowController.blade.php │ ├── AdminNodeController.blade.php │ ├── Flow.blade.php │ ├── Node.blade.php │ ├── Resourceflow.blade.php │ ├── Resourcelog.blade.php │ ├── Resourcenode.blade.php │ ├── migration.blade.php │ └── routes.blade.php └── tests ├── .gitkeep └── HasFlowForResourceTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | 3 | composer.phar 4 | 5 | composer.lock 6 | 7 | .DS_Store 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | - 5.6 8 | - hhvm 9 | 10 | before_script: 11 | - composer self-update 12 | - composer install --prefer-source --no-interaction --dev 13 | 14 | script: phpunit 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Workflow (Laravel5 Package) 3 | ======== 4 | 5 | ### thanks tao2581, If you need use to laravel 4, please add 6 | 7 | "davin-bao/workflow": "v1.0" 8 | 9 | Workflow package provides a simple way to add audit flow to **Laravel5**. 10 | 11 | ## Quick start 12 | 13 | ### Required setup 14 | 15 | In the `require` key of `composer.json` file add the following 16 | 17 | "davin-bao/workflow": "dev-master" 18 | 19 | Run the Composer update comand 20 | 21 | $ composer update 22 | 23 | In your `config/app.php` add `'DavinBao\Workflow\WorkflowServiceProvider'` to the end of the `$providers` array 24 | 25 | ```php 26 | 'providers' => array( 27 | 28 | 'Illuminate\Foundation\Providers\ArtisanServiceProvider', 29 | 'Illuminate\Auth\AuthServiceProvider', 30 | ... 31 | 'DavinBao\Workflow\WorkflowServiceProvider', 32 | 33 | ), 34 | ``` 35 | 36 | At the end of `config/app.php` add `'Workflow' => 'DavinBao\Workflow\WorkflowFacade'` to the `$aliases` array 37 | 38 | ```php 39 | 'aliases' => array( 40 | 41 | 'App' => 'Illuminate\Support\Facades\App', 42 | 'Artisan' => 'Illuminate\Support\Facades\Artisan', 43 | ... 44 | 'Workflow' => 'DavinBao\Workflow\WorkflowFacade', 45 | 46 | ), 47 | ``` 48 | 49 | ### Configuration 50 | 51 | ### Create Table 52 | 53 | Now generate the Workflow migration 54 | 55 | $ php artisan workflow:migration 56 | 57 | It will generate the `_workflow_setup_tables.php` migration. You may now run it with the artisan migrate command: 58 | Open: `_workflow_setup_tables.php` change " {{ 'entry_title; 83 | } 84 | 85 | public function getLogContent() 86 | { 87 | return $this->entry_content; 88 | } 89 | ``` 90 | ### Link the Controller 91 | ```php 92 | class AdminEntryController extends AdminController { 93 | use \DavinBao\Workflow\HasFlowForResourceController; 94 | } 95 | ``` 96 | ### Add roles for this controller 97 | ```php 98 | Route::get('entrys/{entry}/binding', 'AdminEntrysController@getBindingFlow'); 99 | Route::post('entrys/{entry}/binding', 'AdminEntrysController@postBindingFlow'); 100 | Route::get('entrys/{entry}/audit', 'AdminEntrysController@getAudit'); 101 | Route::post('entrys/{entry}/audit', 'AdminEntrysController@postAudit'); 102 | ``` 103 | ### Modify config 104 | 105 | Set the propertly values to the `config/auth.php` and `davin-bao/workflow/src/config/config.php` . 106 | 107 | ## Functions 108 | 109 | ### Get is binding audit flow 110 | ```php 111 | if(isset($entry->isBinding)) {///is binding, do something } 112 | ``` 113 | 114 | ### Get resource audit status 115 | ```php 116 | $entry->status() 117 | ``` 118 | 119 | ### Show flow Graph, show this resource audit flow status 120 | 121 | @if(isset($entry->isBinding)) 122 | {{ Workflow::makeFlowGraph($entry->flow(), $entry->orderID()) }} 123 | @endif 124 | 125 | ### Show audit flow all details 126 | 127 | @if(isset($entry->isBinding)) 128 | {{ Workflow::makeAuditDetail($entry) }} 129 | @endif 130 | 131 | ### Need I audit, show audit button 132 | ```php 133 | if(isset($entry->isBinding) && $entry->isMeAudit()) { /// show audit button } 134 | ``` 135 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tao2581/workflow", 3 | "description": "this is a workflow package for laravel5", 4 | "keywords": ["laravel","workflow"], 5 | "homepage": "https://github.com/davin-bao/workflow", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "davin-bao", 10 | "email": "davin.bao@gmail.com", 11 | "homepage": "http://davinbao.blog.com/", 12 | "role": "Developer" 13 | } 14 | ], 15 | "repositories": [ 16 | { 17 | "type": "vcs", 18 | "url": "git://github.com/orchestral/phpseclib.git" 19 | } 20 | ], 21 | "require": { 22 | "php": ">=5.3.0", 23 | "illuminate/support": "5.1.*", 24 | "laravelbook/ardent": "dev-master" 25 | }, 26 | "autoload": { 27 | "classmap": [ 28 | "src/migrations" 29 | ], 30 | "psr-0": { 31 | "DavinBao\\Workflow\\": "src/" 32 | } 33 | }, 34 | "minimum-stability": "dev" 35 | } 36 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davin-bao/workflow/8af8b33ef63e455a2a5a1cdf6ac7bc154d590488/public/.gitkeep -------------------------------------------------------------------------------- /src/DavinBao/Workflow/ControllersCommand.php: -------------------------------------------------------------------------------- 1 | addNamespace('workflow',substr(__DIR__,0,-17).'views'); 41 | } 42 | 43 | 44 | /** 45 | * Execute the console command. 46 | * 47 | * @return void 48 | */ 49 | public function fire() 50 | { 51 | $this->line(''); 52 | $this->info( "Controllers file: admin/AdminFlowController.php, admin/AdminNodeController.php" ); 53 | 54 | $message = "A single controllers, This a base be used with a workflow."; 55 | 56 | 57 | $this->comment( $message ); 58 | $this->line(''); 59 | 60 | if ( $this->confirm("Proceed with the append? [Yes|no]") ) 61 | { 62 | $this->line(''); 63 | 64 | $this->info( "Appending controller..." ); 65 | 66 | $controllers = array( 67 | 'AdminFlowController','AdminNodeController' 68 | ); 69 | $result = true; 70 | foreach($controllers as $controller){ 71 | $result = $result && $this->appendControllers($controller); 72 | } 73 | if( $result ) 74 | { 75 | $this->info( "app/http/controllers/admin/AdminFlowController.php and app/controllers/admin/AdminNodeController.php Patched successfully!" ); 76 | } 77 | else{ 78 | $this->error( 79 | "Coudn't append content, \nCheck the". 80 | " write permissions within the file." 81 | ); 82 | } 83 | 84 | $this->line(''); 85 | 86 | } 87 | } 88 | 89 | 90 | /** 91 | * Create the controller 92 | * 93 | * @param string $name 94 | * @return bool 95 | */ 96 | protected function appendControllers( $name = '' ) 97 | { 98 | $app = app(); 99 | $data_dir = $this->laravel->path.'/Http/Controllers/Admin'; 100 | $datas_file = $this->laravel->path."/Http/Controllers/Admin/$name.php"; 101 | $this->info( $datas_file ); 102 | $workflow_datas = $app['view']->make('workflow::generators.'.$name) 103 | ->render(); 104 | $workflow_datas = str_replace("{{ 'line($workflow_datas); 116 | fclose($fs); 117 | return true; 118 | } 119 | else 120 | { 121 | return false; 122 | } 123 | } 124 | else 125 | { 126 | return false; 127 | } 128 | } 129 | 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/DavinBao/Workflow/HasFlowForResource.php: -------------------------------------------------------------------------------- 1 | morphOne('DavinBao\Workflow\WorkFlowResourceflow', 'resource'); 23 | } 24 | 25 | public function getFlows($resource_type){ 26 | return WorkFlowFlow::where('resource_type','=',$resource_type)->get(); 27 | } 28 | 29 | public function isBindingFlow() { 30 | return $this->resourceflow != null; 31 | } 32 | 33 | public function bindingFlow($flow_id){ 34 | $resFlows = WorkFlowResourceflow::where('flow_id','=',$flow_id)->where('resource_id','=',$this->id)->get(); 35 | if(!$resFlows || $resFlows->count()<=0){ 36 | $resFlow = new WorkFlowResourceflow(); 37 | $resFlow->flow_id = $flow_id; 38 | $resFlow->resource_type = WorkFlowFlow::find($flow_id)->resource_type; 39 | $resFlow->resource_id = $this->id; 40 | $resFlow->save(); 41 | } 42 | } 43 | 44 | public function startFlow($auditUsers, $title, $content){ 45 | if(!$this->resourceflow) return false; 46 | $this->resourceflow->goFirst(); 47 | return $this->agree('',$auditUsers, $title, $content); 48 | } 49 | 50 | public function status(){ 51 | if(!$this->resourceflow) return false; 52 | return $this->resourceflow->status; 53 | } 54 | 55 | public function flow(){ 56 | if(!$this->resourceflow) return false; 57 | return $this->resourceflow->flow()->first(); 58 | } 59 | 60 | public function orderID(){ 61 | if(!$this->resourceflow) return false; 62 | return $this->resourceflow->node_orders; 63 | } 64 | 65 | /** 66 | * Get all audit users has role in current node of this flow 67 | * @return array $user 68 | */ 69 | public function getNextAuditUsers(){ 70 | if(!$this->resourceflow) return false; 71 | return $this->resourceflow->getNextAuditUsers(); 72 | } 73 | 74 | public function getNextNode(){ 75 | if(!$this->resourceflow) return false; 76 | return $this->resourceflow->getNextNode(); 77 | } 78 | 79 | public function getCurrentNode(){ 80 | if(!$this->resourceflow) return false; 81 | return $this->resourceflow->getCurrentNode(); 82 | } 83 | 84 | public function isFirstAudit(){ 85 | if($this->resourceflow->status == 'unstart' && $this->resourceflow->resourcenodes()->count()<=0){ 86 | return true; 87 | } 88 | return false; 89 | } 90 | 91 | public function isMeAudit(){ 92 | if(!$this->resourceflow) return false; 93 | $myNode = $this->resourceflow->getMyUnAuditResourceNode(); 94 | if($myNode !== null){ 95 | return true; 96 | } 97 | if($this->isFirstAudit() && $this->create_user_id == \Auth::user()->id){ 98 | return true; 99 | } 100 | 101 | //下一节点,是否需要我来签字 102 | // $cnode = $this->resourceflow->getCurrentNode(); 103 | // if($cnode){ 104 | // return $cnode->isContainsMe(); 105 | // } 106 | return false; 107 | } 108 | 109 | public function agree($comment, $auditUsers, $title = null, $content = null){ 110 | if(!$this->resourceflow) return false; 111 | //如果是创建时审批 112 | if($this->isFirstAudit()){ 113 | //设置未审批人为创建人 114 | $this->resourceflow->setNextAuditUsers(array($this->createUser)); 115 | } 116 | 117 | if($this->resourceflow->comment('agreed',$comment, $title, $content)) { 118 | //go next node 119 | //if have not next resource node ,to go next node 120 | $unauditedNode = $this->resourceflow->getAnotherUnAuditResourceNode(); 121 | if(!$unauditedNode || $unauditedNode->count()<=0){ 122 | $this->resourceflow->goNext(); 123 | } 124 | 125 | if($auditUsers && $auditUsers->count()>0) { 126 | $this->resourceflow->setNextAuditUsers($auditUsers); 127 | } 128 | return true; 129 | } 130 | 131 | return false; 132 | } 133 | 134 | public function disagree($callback, $comment, $title = null, $content = null){ 135 | if($this->status() != 'proceed') return false; 136 | if(!$this->resourceflow) return false; 137 | if($this->resourceflow->comment('disagreed',$comment, $title, $content)) { 138 | //run callback 139 | if ($callback) { 140 | return call_user_func($callback); 141 | } 142 | } 143 | 144 | return false; 145 | } 146 | 147 | public function shouldPublish(){ 148 | if(!$this->resourceflow) return false; 149 | if($this->resourceflow->getAnotherUnAuditResourceNode() == false && $this->resourceflow->getNextNode() == null){ 150 | return true; 151 | } 152 | return false; 153 | } 154 | 155 | public function discard(){ 156 | if(!$this->resourceflow) return false; 157 | return $this->resourceflow->discard(); 158 | } 159 | 160 | public function goFirst(){ 161 | if(!$this->resourceflow) return false; 162 | return $this->resourceflow->goFirst(); 163 | } 164 | 165 | /** 166 | * Before delete all constrained foreign relations 167 | * 168 | * @param bool $forced 169 | * @return bool 170 | */ 171 | public function beforeDelete( $forced = false ) 172 | { 173 | try { 174 | if($this->resourceflow){ 175 | $this->resourceflow->delete(); 176 | } 177 | } catch(Execption $e) {} 178 | 179 | return true; 180 | } 181 | 182 | public function getAuditByTimeLine(){ 183 | $auditsByDate = array(); 184 | $flow = $this->flow(); 185 | if(!$this->resourceflow) return false; 186 | $nodes = $this->resourceflow->resourcenodes()->get(); 187 | 188 | foreach ($nodes as $node) { 189 | $username = $node->user()->first()->name(); 190 | 191 | $nodename = \Lang::get('workflow::workflow.push'); 192 | if((int)$node->orders>0){ 193 | $nodename = $flow->nodes()->where('orders','=',$node->orders)->first()->node_name; 194 | } 195 | 196 | $auditsByDate[$node->updated_at->toDateString()][$node->id]['id'] = $node->id; 197 | $auditsByDate[$node->updated_at->toDateString()][$node->id]['username'] = $username; 198 | $auditsByDate[$node->updated_at->toDateString()][$node->id]['nodename'] = $nodename; 199 | $auditsByDate[$node->updated_at->toDateString()][$node->id]['result'] = $node->result; 200 | $auditsByDate[$node->updated_at->toDateString()][$node->id]['comment'] = $node->comment; 201 | $auditsByDate[$node->updated_at->toDateString()][$node->id]['updated_at'] = $node->updated_at->format('H:i'); 202 | } 203 | return $auditsByDate; 204 | } 205 | 206 | public static function getCompletedList(){ 207 | $cModel = get_called_class(); 208 | 209 | return $cModel::whereHas('resourceflow', function($query) 210 | { 211 | $query->where('status', '=', 'completed'); 212 | }); 213 | } 214 | 215 | public static function getAuditList(){ 216 | $cModel = get_called_class(); 217 | 218 | return $cModel::whereHas('resourceflow', function($query) 219 | { 220 | $query->whereIn('status', array('proceed','unstart')); 221 | }); 222 | } 223 | 224 | public function lastIsMe(){ 225 | $lastUser = $this->resourceflow->getLastAuditUser(); 226 | if($lastUser === null) return false; 227 | return $lastUser->id == \Auth::user()->id; 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/DavinBao/Workflow/HasFlowForResourceController.php: -------------------------------------------------------------------------------- 1 | id ) 20 | { 21 | $flows = $entry->getFlows($flow_type); 22 | 23 | //if this resource has binded flow, go to audit flow 24 | if($entry->isBindingFlow()){ 25 | return \Redirect::to('admin/'.$this->entryName.'/' . $entry->id . '/audit'); 26 | } 27 | 28 | //if no flow, return success 29 | if(!$flows || $flows->count() <= 0){ 30 | return \Redirect::to('admin/'.$this->entryName.'/' . $entry->id . '/edit')->with('success', \Lang::get('admin/'.$this->entryName.'/messages.create.success')); 31 | }else if($flows->count() == 1){ 32 | //if flow is only one, binding it 33 | $entry->bindingFlow($flows->first()->id); 34 | return \Redirect::to('admin/'.$this->entryName.'/' . $entry->id . '/audit'); 35 | } 36 | //if have muliti flows, show list for user select 37 | return \View::make(\Config::get('app.admin_template').'/flows/binding', compact('entry', 'flows')); 38 | } else { 39 | return \Redirect::to('admin/'.$this->entryName.'')->with('error', \Lang::get('admin/'.$this->entryName.'/messages.does_not_exist')); 40 | } 41 | } 42 | public function postBindingFlow($entry){ 43 | if( $entry->id ){ 44 | $entry->bindingFlow(\Input::get( 'flow_id' )); 45 | return \Redirect::to('admin/'.$this->entryName.'/' . $entry->id . '/audit'); 46 | } else { 47 | return \Redirect::to('admin/'.$this->entryName.'')->with('error', \Lang::get('admin/'.$this->entryName.'/messages.does_not_exist')); 48 | } 49 | } 50 | 51 | public function getAudit($entry){ 52 | if( $entry->id ){ 53 | $nextAuditUsers = $entry->getNextAuditUsers(); 54 | $currentNode = $entry->getCurrentNode(); 55 | $entryName = $this->entryName; 56 | //if auditUsers is one person and this entry unstart, auto audited it 57 | if(count($nextAuditUsers)==1 && $entry->status() == 'unstart'){ 58 | $result = $entry->startFlow($nextAuditUsers, $entry->getLogTitle(), $entry->getLogContent()); 59 | if($result){ 60 | return \Redirect::to('admin/'.$this->entryName.'/' . $entry->id . '/edit')->with('success', \Lang::get('workflow::workflow.action').\Lang::get('workflow::workflow.success')); 61 | }else{ 62 | return \Redirect::to('admin/'.$this->entryName.'/' . $entry->id . '/edit')->with('error', \Lang::get('workflow::workflow.action').\Lang::get('workflow::workflow.failed_unknown')); 63 | } 64 | }else { 65 | return \View::make(\Config::get('app.admin_template').'/flows/audit', compact('entry','entryName','nextAuditUsers','currentNode')); 66 | } 67 | } else { 68 | return \Redirect::to('admin/'.$this->entryName.'')->with('error', \Lang::get('admin/'.$this->entryName.'/messages.does_not_exist')); 69 | } 70 | } 71 | 72 | public function postAudit($entry){ 73 | 74 | $entry_name = lcfirst(get_class($entry)); 75 | 76 | if( $entry->id ){ 77 | $comment = \Input::get( 'comment' ); 78 | $nextAuditUserIds = \Input::get( 'audit_users' ); 79 | $nextAuditUsers = new \Illuminate\Database\Eloquent\Collection(); 80 | if($nextAuditUserIds && count($nextAuditUserIds)>0){ 81 | foreach($nextAuditUserIds as $id){ 82 | $nextAuditUsers->add(\User::find($id)); 83 | } 84 | } 85 | $submit = \Input::get( 'submit' ); 86 | switch($submit){ 87 | case 'agree': 88 | $result = $entry->agree($comment, $nextAuditUsers, $entry->getLogTitle(), $entry->getLogContent()); 89 | break; 90 | case 'discard': 91 | $result = $entry->disagree($entry_name .'::discard', $comment, $entry->getLogTitle(), $entry->getLogContent()); 92 | break; 93 | case 'gofirst': 94 | $result = $entry->disagree($entry_name .'::goFirst', $comment, $entry->getLogTitle(), $entry->getLogContent()); 95 | break; 96 | } 97 | 98 | if($result){ 99 | return \Redirect::to('admin/'.$this->entryName.'/' . $entry->id . '/edit')->with('success', \Lang::get('workflow::workflow.action').\Lang::get('workflow::workflow.success')); 100 | }else{ 101 | return \Redirect::to('admin/'.$this->entryName.'/' . $entry->id . '/edit')->with('error', \Lang::get('workflow::workflow.action').\Lang::get('workflow::workflow.failed_unknown')); 102 | } 103 | } 104 | return \Redirect::to('admin/'.$this->entryName.'')->with('error', \Lang::get('admin/'.$this->entryName.'/messages.does_not_exist')); 105 | } 106 | } -------------------------------------------------------------------------------- /src/DavinBao/Workflow/HasNodeForRole.php: -------------------------------------------------------------------------------- 1 | belongsToMany(Config::get('workflow::node'), Config::get('workflow::node_role_table')); 22 | } 23 | 24 | 25 | 26 | 27 | } -------------------------------------------------------------------------------- /src/DavinBao/Workflow/HasNodeForUser.php: -------------------------------------------------------------------------------- 1 | belongsToMany(Config::get('workflow::node'), Config::get('workflow::node_user_table')); 22 | } 23 | 24 | public function resourcenodes() 25 | { 26 | return $this->hasMany(Config::get('workflow::resourcenode')); 27 | } 28 | 29 | public function myUnAuditedResources(){ 30 | $resourceNodes = $this::whereHas('resourcenodes', function($q) 31 | { 32 | $q->where('result', '=', 'unaudited'); 33 | })->get(); 34 | 35 | $resources = array(); 36 | 37 | foreach ($resourceNodes as $resourceNode) { 38 | $resources[] = $resourceNode->flow()->resource(); 39 | } 40 | return $resources; 41 | } 42 | 43 | public function myAgreedResources(){ 44 | $resourceNodes = $this::whereHas('resourcenodes', function($q) 45 | { 46 | $q->where('result', '=', 'agreed'); 47 | })->get(); 48 | 49 | $resources = array(); 50 | 51 | foreach ($resourceNodes as $resourceNode) { 52 | $resources[] = $resourceNode->flow()->resource(); 53 | } 54 | return $resources; 55 | } 56 | 57 | public function myDisagreedResources(){ 58 | $resourceNodes = $this::whereHas('resourcenodes', function($q) 59 | { 60 | $q->where('result', '=', 'disagreed'); 61 | })->get(); 62 | 63 | $resources = array(); 64 | 65 | foreach ($resourceNodes as $resourceNode) { 66 | $resources[] = $resourceNode->flow()->resource(); 67 | } 68 | return $resources; 69 | } 70 | 71 | 72 | 73 | 74 | } -------------------------------------------------------------------------------- /src/DavinBao/Workflow/MigrationCommand.php: -------------------------------------------------------------------------------- 1 | -17 33 | $app['view']->addNamespace('workflow',substr(__DIR__,0,-17).'views'); 34 | } 35 | 36 | 37 | /** 38 | * Execute the console command. 39 | * 40 | * @return void 41 | */ 42 | public function fire() 43 | { 44 | 45 | $this->line(''); 46 | $this->info( "Tables: flows, nodes, node_role, node_user, resourceflow, resourcenode, resourcelog" ); 47 | $message = "An migration that creates 'flows', 'nodes', 'node_role', 'node_user', 'resourceflow', 'resourcenode', 'resourcelog'". 48 | " tables will be created in app/database/migrations directory "; 49 | 50 | $this->comment( $message ); 51 | $this->line(''); 52 | 53 | if ( $this->confirm("Proceed with the migration creation? [Yes|no]") ) 54 | { 55 | $this->line(''); 56 | 57 | $this->info( "Creating migration..." ); 58 | if( $this->createMigration() ) 59 | { 60 | $this->info( "Migration successfully created!" ); 61 | } 62 | else{ 63 | $this->error( 64 | "Coudn't create migration.\n Check the write permissions". 65 | " within the app/database/migrations directory." 66 | ); 67 | } 68 | 69 | $this->line(''); 70 | 71 | } 72 | } 73 | /** 74 | * Create the migration 75 | * 76 | * @param string $name 77 | * @return bool 78 | */ 79 | protected function createMigration() 80 | { 81 | // migrations目录应该是根目录 app->path => base_pash 82 | $migration_file = base_path()."/database/migrations/".date('Y_m_d_His')."_workflow_setup_tables.php"; 83 | $app = app(); 84 | $resource_type = ''; 85 | if(is_array($app['config']->get('resource_type'))){ 86 | $resource_type = implode(",", app()['config']->get('workflow::resource_type')); 87 | } 88 | 89 | $output = $app['view']->make('workflow::generators.migration')->with('res_type',$resource_type)->render(); 90 | 91 | if( ! file_exists( $migration_file ) ) 92 | { 93 | $fs = fopen($migration_file, 'x'); 94 | if ( $fs ) 95 | { 96 | fwrite($fs, $output); 97 | fclose($fs); 98 | return true; 99 | } 100 | else 101 | { 102 | return false; 103 | } 104 | } 105 | else 106 | { 107 | return false; 108 | } 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/DavinBao/Workflow/ModelsCommand.php: -------------------------------------------------------------------------------- 1 | addNamespace('workflow',substr(__DIR__,0,-8).'views'); 41 | } 42 | 43 | 44 | /** 45 | * Execute the console command. 46 | * 47 | * @return void 48 | */ 49 | public function fire() 50 | { 51 | $this->line(''); 52 | $this->info( "Models file: model/flow/flow.php, model/flow/node.php, model/flow/resourceFlow.php, model/flow/resourceNode.php, model/flow/resourceLog.php" ); 53 | 54 | $message = "A single model, This a base be used with a workflow."; 55 | 56 | 57 | $this->comment( $message ); 58 | $this->line(''); 59 | 60 | if ( $this->confirm("Proceed with the append? [Yes|no]") ) 61 | { 62 | $this->line(''); 63 | 64 | $this->info( "Appending models..." ); 65 | 66 | $models = array( 67 | 'Flow','Node','Resourceflow','Resourcenode','Resourcelog' 68 | ); 69 | $result = true; 70 | foreach($models as $model){ 71 | $result = $result && $this->appendModels($model); 72 | } 73 | if( $result ) 74 | { 75 | $this->info( "app/model/flow Patched successfully!" ); 76 | } 77 | else{ 78 | $this->error( 79 | "Coudn't append content, \nCheck the". 80 | " write permissions within the file." 81 | ); 82 | } 83 | 84 | $this->line(''); 85 | 86 | } 87 | } 88 | 89 | 90 | /** 91 | * Create the controller 92 | * 93 | * @param string $name 94 | * @return bool 95 | */ 96 | protected function appendModels( $name = '' ) 97 | { 98 | $app = app(); 99 | $model_dir = $this->laravel->path.'/models/Flow'; 100 | $models_file = $this->laravel->path."/models/Flow/$name.php"; 101 | $this->info( $models_file ); 102 | $workflow_models = $app['view']->make('workflow::generators.'.$name) 103 | ->render(); 104 | 105 | if (!file_exists($model_dir)) { 106 | mkdir($model_dir, 0777, true); 107 | } 108 | 109 | if( !file_exists( $models_file ) ) 110 | { 111 | $fs = fopen($models_file, 'x'); 112 | if ( $fs ) 113 | { 114 | fwrite($fs, $workflow_models); 115 | $this->line($workflow_models); 116 | fclose($fs); 117 | return true; 118 | } 119 | else 120 | { 121 | return false; 122 | } 123 | } 124 | else 125 | { 126 | return false; 127 | } 128 | } 129 | 130 | 131 | } -------------------------------------------------------------------------------- /src/DavinBao/Workflow/RoutesCommand.php: -------------------------------------------------------------------------------- 1 | addNamespace('workflow',substr(__DIR__,0,-17).'views'); 41 | } 42 | 43 | 44 | /** 45 | * Execute the console command. 46 | * 47 | * @return void 48 | */ 49 | public function fire() 50 | { 51 | $name = $this->option('rout_name'); 52 | 53 | $this->line(''); 54 | $this->info( "Routes file: app/http/routes.php" ); 55 | 56 | $message = "A single route to handle every action in a RESTful controller". 57 | " will be appended to your routes.php file. This may be used with a workflow". 58 | " controller generated using [-r|--restful] option."; 59 | 60 | 61 | $this->comment( $message ); 62 | $this->line(''); 63 | 64 | if ( $this->confirm("Proceed with the append? [Yes|no]") ) 65 | { 66 | $this->line(''); 67 | 68 | $this->info( "Appending routes..." ); 69 | if( $this->appendRoutes( $name ) ) 70 | { 71 | $this->info( "app/http/routes.php Patched successfully!" ); 72 | } 73 | else{ 74 | $this->error( 75 | "Coudn't append content to app/routes.php\nCheck the". 76 | " write permissions within the file." 77 | ); 78 | } 79 | 80 | $this->line(''); 81 | 82 | } 83 | } 84 | 85 | 86 | /** 87 | * Get the console command options. 88 | * 89 | * @return array 90 | */ 91 | protected function getOptions() 92 | { 93 | return array( 94 | array('rout_name', null, InputOption::VALUE_OPTIONAL, 'Name of the routes.', 'flow'), 95 | ); 96 | } 97 | 98 | 99 | /** 100 | * Create the controller 101 | * 102 | * @param string $name 103 | * @return bool 104 | */ 105 | protected function appendRoutes( $name = '' ) 106 | { 107 | $app = app(); 108 | $routes_file = $this->laravel->path.'/http/routes.php'; 109 | $workflow_routes = $app['view']->make('workflow::generators.routes') 110 | ->with('name', $name) 111 | ->render(); 112 | 113 | if( file_exists( $routes_file ) ) 114 | { 115 | $fs = fopen($routes_file, 'a'); 116 | if ( $fs ) 117 | { 118 | fwrite($fs, $workflow_routes); 119 | $this->line($workflow_routes); 120 | fclose($fs); 121 | return true; 122 | } 123 | else 124 | { 125 | return false; 126 | } 127 | } 128 | else 129 | { 130 | return false; 131 | } 132 | } 133 | 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/DavinBao/Workflow/Workflow.php: -------------------------------------------------------------------------------- 1 | _app = $app; 23 | } 24 | 25 | /** 26 | * Get the currently authenticated user or null. 27 | * 28 | * @access public 29 | * 30 | * @return Illuminate\Auth\UserInterface|null 31 | */ 32 | public function user() 33 | { 34 | return $this->_app['auth']->user(); 35 | } 36 | 37 | 38 | /** 39 | * Check whether the controller's action exists. 40 | * Returns the url if it does. Otherwise false. 41 | * @param $controllerAction 42 | * @return string 43 | */ 44 | public function checkAction( $action, $parameters = array(), $absolute = true ) 45 | { 46 | try { 47 | $url = $this->_app['url']->action($action, $parameters, $absolute); 48 | } catch( InvalidArgumentException $e ) { 49 | return false; 50 | } 51 | 52 | return $url; 53 | } 54 | /** 55 | * Display the default create flow view 56 | * 57 | * @deprecated 58 | * @return Illuminate\View\View 59 | */ 60 | public function makeFlowForm($flow = null, $roles = null) 61 | { 62 | //var_dump($this->_app['config']);exit; 63 | return $this->_app['view']->make( 'workflow::flow_form', compact( 'flow', 'roles') ); 64 | } 65 | 66 | public function makeFlowGraph($flow = null, $orderID = 0, $status='completed') 67 | { 68 | return $this->_app['view']->make( 'workflow::flow_graph', compact( 'flow', 'orderID', 'status') ); 69 | } 70 | 71 | public function makeBindingFlowForm($flows = array(), $entry = null) 72 | { 73 | return $this->_app['view']->make( 'workflow::binding_form', compact( 'flows', 'entry') ); 74 | } 75 | 76 | public function makeAuditFlowForm($entry = null, $nextAuditUsers = array(), $currentNode = null) 77 | { 78 | return $this->_app['view']->make( 'workflow::audit_form', compact( 'entry', 'nextAuditUsers','currentNode') ); 79 | } 80 | 81 | public function makeAuditDetail($entry) 82 | { 83 | return $this->_app['view']->make( 'workflow::audit_detail', compact('entry') ); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/DavinBao/Workflow/WorkflowFacade.php: -------------------------------------------------------------------------------- 1 | 'required|between:1,20' 37 | ); 38 | /** 39 | * Creates a new instance of the model 40 | */ 41 | public function __construct(array $attributes = array()) 42 | { 43 | parent::__construct($attributes); 44 | 45 | if ( ! static::$app ) 46 | static::$app = app(); 47 | 48 | $this->table = static::$app['config']->get('workflow::flows_table'); 49 | } 50 | 51 | /** 52 | * One-to-Many relations with Nodes 53 | */ 54 | public function nodes() 55 | { 56 | return $this->hasMany(static::$app['config']->get('workflow::node'), 'flow_id')->orderBy('orders'); 57 | } 58 | 59 | /** 60 | * @return \Illuminate\Database\Eloquent\Relations\BelongsTo 61 | */ 62 | public function flowable() 63 | { 64 | return $this->morphTo(); 65 | } 66 | 67 | public function updateNodesOrder($nodeIds){ 68 | $order = 1; 69 | foreach($nodeIds as $nodeId) { 70 | $node = $this->nodes()->find($nodeId); 71 | if($node) { 72 | $node->orders = $order++; 73 | $this->nodes()->save($node); 74 | } 75 | } 76 | } 77 | 78 | /** 79 | * Before delete all constrained foreign relations 80 | * 81 | * @param bool $forced 82 | * @return bool 83 | */ 84 | public function beforeDelete( $forced = false ) 85 | { 86 | try { 87 | \DB::table(static::$app['config']->get('workflow::nodes_table'))->where('flow_id', $this->id)->delete(); 88 | } catch(Execption $e) {} 89 | 90 | return true; 91 | } 92 | } -------------------------------------------------------------------------------- /src/DavinBao/Workflow/WorkflowNode.php: -------------------------------------------------------------------------------- 1 | 'required|between:1,20' 30 | ); 31 | 32 | /** 33 | * Creates a new instance of the model 34 | */ 35 | public function __construct(array $attributes = array()) 36 | { 37 | parent::__construct($attributes); 38 | $this->table = Config::get('workflow::nodes_table'); 39 | } 40 | /** 41 | * Many-to-One relations with flows 42 | */ 43 | public function flow() 44 | { 45 | return $this->belongsTo(Config::get('workflow::flow')); 46 | } 47 | 48 | /** 49 | * Many-to-Many relations with Users 50 | */ 51 | public function users() 52 | { 53 | return $this->belongsToMany(Config::get('auth.model'), Config::get('workflow::node_user_table')); 54 | } 55 | 56 | public function UsersString($count=3){ 57 | $userString = ""; 58 | foreach($this->users->take($count) as $user){ 59 | $username = $user->name(); 60 | if(strlen($username)>0) { 61 | $userString = $userString . $username . ","; 62 | } 63 | } 64 | return strlen($userString)>0?$userString.'...':''; 65 | } 66 | 67 | /** 68 | * Many-to-Many relations with Roles 69 | */ 70 | public function roles() 71 | { 72 | return $this->belongsToMany(Config::get('workflow::role'), Config::get('workflow::node_role_table')); 73 | } 74 | 75 | public function RolesString($count=3){ 76 | $roleString = ""; 77 | foreach($this->roles->take($count) as $role){ 78 | if(strlen($role->name)>0) { 79 | $roleString = $roleString . $role->name . ","; 80 | } 81 | } 82 | return strlen($roleString)>0?$roleString.'...':''; 83 | } 84 | //本人是否有权审批 85 | public function isContainsMe(){ 86 | foreach($this->users as $user){ 87 | if($user->id = \Auth::user()->id){ 88 | return true; 89 | } 90 | } 91 | foreach($this->roles as $role){ 92 | foreach($role->users as $user){ 93 | if($user->id = \Auth::user()->id){ 94 | return true; 95 | } 96 | } 97 | } 98 | return false; 99 | } 100 | 101 | /** 102 | * Before delete all constrained foreign relations 103 | * 104 | * @param bool $forced 105 | * @return bool 106 | */ 107 | public function beforeDelete( $forced = false ) 108 | { 109 | try { 110 | \DB::table(Config::get('workflow::node_user_table'))->where('node_id', $this->id)->delete(); 111 | \DB::table(Config::get('workflow::node_role_table'))->where('node_id', $this->id)->delete(); 112 | } catch(Execption $e) {} 113 | 114 | return true; 115 | } 116 | 117 | /** 118 | * Attach user to current role 119 | * @param $user 120 | */ 121 | public function attachUser( $user ) 122 | { 123 | if( is_object($user)) 124 | $user = $user->getKey(); 125 | 126 | if( is_array($user)) 127 | $user = $user['id']; 128 | 129 | $this->users()->attach( $user ); 130 | } 131 | 132 | /** 133 | * Detach permission form current user 134 | * @param $user 135 | */ 136 | public function detachUser( $user ) 137 | { 138 | if( is_object($user)) 139 | $user = $user->getKey(); 140 | 141 | if( is_array($user)) 142 | $user = $user['id']; 143 | 144 | $this->users()->detach( $user ); 145 | } 146 | 147 | /** 148 | * Attach multiple users to current node 149 | * 150 | * @param $users 151 | * @access public 152 | * @return void 153 | */ 154 | public function attachUsers($users) 155 | { 156 | foreach ($users as $user) 157 | { 158 | $this->attachUser($user); 159 | } 160 | } 161 | 162 | /** 163 | * Detach multiple users from current node 164 | * 165 | * @param $users 166 | * @access public 167 | * @return void 168 | */ 169 | public function detachUsers($users) 170 | { 171 | foreach ($users as $user) 172 | { 173 | $this->detachUser($user); 174 | } 175 | } 176 | 177 | /** 178 | * Attach role to current role 179 | * @param $role 180 | */ 181 | public function attachRole( $role ) 182 | { 183 | if( is_object($role)) 184 | $role = $role->getKey(); 185 | 186 | if( is_array($role)) 187 | $role = $role['id']; 188 | 189 | $this->roles()->attach( $role ); 190 | } 191 | 192 | /** 193 | * Detach permission form current role 194 | * @param $role 195 | */ 196 | public function detachRole( $role ) 197 | { 198 | if( is_object($role)) 199 | $role = $role->getKey(); 200 | 201 | if( is_array($role)) 202 | $role = $role['id']; 203 | 204 | $this->roles()->detach( $role ); 205 | } 206 | 207 | /** 208 | * Attach multiple roles to current node 209 | * 210 | * @param $roles 211 | * @access public 212 | * @return void 213 | */ 214 | public function attachRoles($roles) 215 | { 216 | foreach ($roles as $role) 217 | { 218 | $this->attachRole($role); 219 | } 220 | } 221 | 222 | /** 223 | * Detach multiple roles from current node 224 | * 225 | * @param $roles 226 | * @access public 227 | * @return void 228 | */ 229 | public function detachRoles($roles) 230 | { 231 | foreach ($roles as $role) 232 | { 233 | $this->detachRole($role); 234 | } 235 | } 236 | } -------------------------------------------------------------------------------- /src/DavinBao/Workflow/WorkflowResourceLog.php: -------------------------------------------------------------------------------- 1 | table = Config::get('workflow::resourcelog_table'); 38 | } 39 | 40 | public function resourcenode(){ 41 | return $this->hasOne('WorkFlowResourcenode'); 42 | } 43 | 44 | 45 | } -------------------------------------------------------------------------------- /src/DavinBao/Workflow/WorkflowResourceflow.php: -------------------------------------------------------------------------------- 1 | table = static::$app['config']->get('workflow::resourceflow_table'); 50 | } 51 | 52 | // public function bindRelationsData($resourceModel){ 53 | // self::$relationsData = array( 54 | // 'resource' => array(self::BELONGS_TO, $resourceModel), 55 | // 'flow' => array(self::BELONGS_TO, ), 56 | // '$resourceNode' => array(self::HAS_MANY, "WorkFlowResourcenode"), 57 | // ); 58 | // } 59 | 60 | public function flow() { 61 | return $this->belongsTo(static::$app['config']->get('workflow::flow')); 62 | } 63 | 64 | public function resourcenodes() { 65 | return $this->hasMany(static::$app['config']->get('workflow::resourcenode'), 'resourceflow_id'); 66 | } 67 | 68 | public function resource() 69 | { 70 | return $this->morphTo(); 71 | } 72 | 73 | public function getCurrentNode(){ 74 | return $this->flow()->first()->nodes()->where('orders','=', $this->node_orders)->first(); 75 | } 76 | 77 | public function getAnotherUnAuditResourceNode(){ 78 | $userId = static::$app['auth']->user()->id; 79 | return $this->resourcenodes()->where('user_id','<>', $userId) 80 | ->where('result','=','unaudited')->first(); 81 | //Or 82 | // return $this->whereHas('resourcenodes', function($q) use ($user) 83 | // { 84 | // $q->where('result', '=', 'unaudited') 85 | // ->where('user_id', '<>', $user->id); 86 | // })->get(); 87 | } 88 | public function getUnAuditResourceNodes(){ 89 | return $this->resourcenodes()->where('result','=','unaudited')->get(); 90 | } 91 | 92 | public function deleteAllUnAuditResourceNodes(){ 93 | $unAuditNodes = $this->getUnAuditResourceNodes(); 94 | if($unAuditNodes){ 95 | foreach($unAuditNodes as $node){ 96 | $node->delete(); 97 | } 98 | } 99 | return true; 100 | } 101 | 102 | public function getMyUnAuditResourceNode(){ 103 | $userId = static::$app['auth']->user()->id; 104 | //如果完成后再编辑,则应获取result == ‘agreed‘ 105 | $getNodeStatus = 'unaudited'; 106 | if($this->status == 'completed') $getNodeStatus = 'agreed'; 107 | return $this->resourcenodes()->where('user_id','=', $userId) 108 | ->where('result','=',$getNodeStatus)->orderby('orders','desc')->first(); 109 | } 110 | 111 | public function getNextNode(){ 112 | $nextOrder = (int)$this->node_orders + 1; 113 | 114 | $nextNode = \DB::table(static::$app['config']->get('workflow::nodes_table').' AS nodes') 115 | ->join(static::$app['config']->get('workflow::flows_table').' AS flows', 'flows.id', '=', 'nodes.flow_id') 116 | ->join(static::$app['config']->get('workflow::resourceflow_table').' AS resourceflows', 'flows.id', '=', 'resourceflows.flow_id') 117 | ->where('nodes.orders', '=', $nextOrder) 118 | ->where('resourceflows.id', '=', $this->id) 119 | ->select('nodes.id')->first(); 120 | if(!$nextNode){ 121 | return null; 122 | } 123 | $node_relition = static::$app['config']->get('workflow::node'); 124 | $node_instance = new $node_relition; 125 | return $node_instance::find($nextNode->id); 126 | } 127 | 128 | /** 129 | * 判断流程是否完结,并且当前用户结束该流程,则该用户有权限再编辑 130 | * @return null 131 | */ 132 | public function getLastAuditUser(){ 133 | if($this->status !== 'completed') return null; 134 | $node = $this->resourcenodes()->where('result','agreed')->orderby('orders', 'desc')->first(); 135 | return (!$node) ? null : $node->user; 136 | } 137 | 138 | public function getNextAuditUsers(){ 139 | $nextAuditUsers = new Collection(); 140 | 141 | $unauditedNode = $this->getAnotherUnAuditResourceNode(); 142 | 143 | // if this node is not finished(need another persion audit), return null array 144 | if($unauditedNode && $unauditedNode->count()>0){ 145 | return $nextAuditUsers; 146 | } 147 | //if this node is finished, get users in the next node 148 | $nextNode = $this->getNextNode(); 149 | 150 | if(!$nextNode || $nextNode->count() <= 0){ 151 | return $nextAuditUsers; 152 | } 153 | $nextAuditUsers = $nextNode->users()->get(); 154 | 155 | foreach($nextNode->roles()->get() as $role){ 156 | foreach($role->users()->get() as $user){ 157 | if(!$nextAuditUsers->contains($user->id)){ 158 | $nextAuditUsers->add($user); 159 | } 160 | } 161 | } 162 | return $nextAuditUsers; 163 | } 164 | 165 | public function setNextAuditUsers($nextAuditUsers = array()){ 166 | foreach($nextAuditUsers as $user){ 167 | $node = new WorkFlowResourcenode(); 168 | $node->user_id = $user->id; 169 | $node->orders = $this->node_orders; 170 | $this->resourcenodes()->save($node); 171 | } 172 | Log::error($node->errors()->all()); 173 | } 174 | 175 | public function comment($result, $comment, $title = null, $content = null){ 176 | //get current node, save audit infomation 177 | $currentResourceNode = $this->getMyUnAuditResourceNode(); 178 | if(!$currentResourceNode || $currentResourceNode->count()<=0){ 179 | return false; 180 | } 181 | //不能超过总流程节点数 182 | $maxOrder = $this->flow()->first()->nodes()->count(); 183 | $orders = $this->node_orders > $maxOrder ? $maxOrder : $this->node_orders; 184 | 185 | $currentResourceNode->result = $result; 186 | $currentResourceNode->comment = $comment; 187 | $currentResourceNode->orders = $orders; 188 | $currentResourceNode->recordLog($title, $content); 189 | if($currentResourceNode->save()){ 190 | return true; 191 | } 192 | return false; 193 | } 194 | 195 | /** 196 | * return this flow to first 197 | */ 198 | public function goFirst(){ 199 | //delete others unAndit nodes 200 | $this->deleteAllUnAuditResourceNodes(); 201 | //get first user id, if haven't , point to me 202 | $userId = static::$app['auth']->user()->id; 203 | $resNode = $this->resourcenodes()->where('orders', '=', 0)->get()->first(); 204 | if($resNode && $resNode->count() >0){ 205 | $userId = $resNode->user_id; 206 | } 207 | $firstNode = new WorkFlowResourcenode(); 208 | $firstNode->user_id = $userId; 209 | $firstNode->orders = 0; 210 | $this->resourcenodes()->save($firstNode); 211 | 212 | $this->node_orders = 0; 213 | $this->status = 'unstart'; 214 | return $this->save(); 215 | } 216 | 217 | /** 218 | * go to next node 219 | * @param $nextAuditUsers 220 | */ 221 | public function goNext(){ 222 | $currentOrder = $this->node_orders; 223 | $nextNodeOrder = $currentOrder + 1; 224 | 225 | $status = 'proceed'; 226 | $maxOrder = $this->flow()->first()->nodes()->count(); 227 | if($nextNodeOrder > $maxOrder){ 228 | $status = 'completed'; 229 | $nextNodeOrder = $maxOrder+1; 230 | } 231 | $this->node_orders = $nextNodeOrder; 232 | $this->status = $status; 233 | $this->save(); 234 | Log::error($this->errors()->all()); 235 | } 236 | 237 | /** 238 | * set this flow discard 239 | */ 240 | public function discard(){ 241 | //delete others unAndit nodes 242 | $this->deleteAllUnAuditResourceNodes(); 243 | //var_dump($this->getUnAuditResourceNodes());exit; 244 | $this->status = 'discard'; 245 | return $this->save(); 246 | } 247 | 248 | /** 249 | * set this flow archived 250 | */ 251 | public function archived(){ 252 | $this->status = 'archived'; 253 | return $this->save(); 254 | } 255 | 256 | /** 257 | * Before delete all constrained foreign relations 258 | * 259 | * @param bool $forced 260 | * @return bool 261 | */ 262 | public function beforeDelete( $forced = false ) 263 | { 264 | try { 265 | 266 | if($this->resourcenodes){ 267 | $this->resourcenodes->each(function($node){ 268 | $node->delete(); 269 | }); 270 | } 271 | } catch(Execption $e) {} 272 | 273 | return true; 274 | } 275 | 276 | 277 | } -------------------------------------------------------------------------------- /src/DavinBao/Workflow/WorkflowResourcenode.php: -------------------------------------------------------------------------------- 1 | 'required|numeric' 37 | ); 38 | 39 | /** 40 | * Creates a new instance of the model 41 | */ 42 | public function __construct(array $attributes = array()) 43 | { 44 | parent::__construct($attributes); 45 | 46 | if ( ! static::$app ) 47 | static::$app = app(); 48 | 49 | $this->table = static::$app['config']->get('workflow::resourcenode_table'); 50 | } 51 | 52 | public function flow(){ 53 | $this->belongsTo(static::$app['config']->get('workflow::resourceflow')); 54 | } 55 | 56 | public function user(){ 57 | return $this->belongsTo(static::$app['config']->get('auth.model')); 58 | } 59 | 60 | public function resourceLog(){ 61 | return $this->hasOne(static::$app['config']->get('workflow::resourcelog')); 62 | } 63 | 64 | public function recordLog($title, $content){ 65 | if(Config::get('workflow::record_log')){ 66 | $resourceLog = new WorkFlowResourcelog(); 67 | $resourceLog->title = $title; 68 | $resourceLog->content = $content; 69 | if($this->resourceLog()->save($resourceLog)){ 70 | return true; 71 | } 72 | } 73 | return false; 74 | } 75 | 76 | /** 77 | * Before delete all constrained foreign relations 78 | * 79 | * @param bool $forced 80 | * @return bool 81 | */ 82 | public function beforeDelete( $forced = false ) 83 | { 84 | try { 85 | if($this->resourceLog) { 86 | $this->resourceLog->delete(); 87 | } 88 | } catch(Execption $e) {} 89 | 90 | return true; 91 | } 92 | } -------------------------------------------------------------------------------- /src/DavinBao/Workflow/WorkflowServiceProvider.php: -------------------------------------------------------------------------------- 1 | package('davin-bao/workflow'); 22 | } 23 | 24 | /** 25 | * Register the service provider. 26 | * 27 | * @return void 28 | */ 29 | public function register() 30 | { 31 | // 32 | $this->registerWorkflow(); 33 | $this->registerCommands(); 34 | } 35 | 36 | /** 37 | * Register the application bindings. 38 | * 39 | * @return void 40 | */ 41 | private function registerWorkflow() 42 | { 43 | $this->app->bind('workflow', function($app) 44 | { 45 | return new Workflow($app); 46 | }); 47 | } 48 | 49 | /** 50 | * Get the services provided by the provider. 51 | * 52 | * @return array 53 | */ 54 | public function provides() 55 | { 56 | return array(); 57 | } 58 | 59 | public function registerCommands() 60 | { 61 | 62 | $this->app['command.workflow.migration'] = $this->app->share(function($app) 63 | { 64 | return new MigrationCommand($app); 65 | }); 66 | 67 | $this->app['command.workflow.routes'] = $this->app->share(function($app) 68 | { 69 | return new RoutesCommand($app); 70 | }); 71 | 72 | $this->app['command.workflow.models'] = $this->app->share(function($app) 73 | { 74 | return new ModelsCommand($app); 75 | }); 76 | 77 | $this->app['command.workflow.controllers'] = $this->app->share(function($app) 78 | { 79 | return new ControllersCommand($app); 80 | }); 81 | 82 | $this->commands( 83 | 'command.workflow.migration', 84 | 'command.workflow.routes', 85 | 'command.workflow.models', 86 | 'command.workflow.controllers' 87 | ); 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davin-bao/workflow/8af8b33ef63e455a2a5a1cdf6ac7bc154d590488/src/config/.gitkeep -------------------------------------------------------------------------------- /src/config/config.php: -------------------------------------------------------------------------------- 1 | true, 8 | 9 | /* 10 | |-------------------------------------------------------------------------- 11 | | Role Model 12 | |-------------------------------------------------------------------------- 13 | | 14 | | This is the Role model used by Workflow to create correct relations. Update 15 | | the role if it is in a different namespace. 16 | | 17 | */ 18 | 'role' => '\Role', 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Workflow Roles Table 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This is the Roles table used by Workflow to save roles to the database. 26 | | 27 | */ 28 | 'roles_table' => 'roles', 29 | 30 | 31 | 'resource_type' => array( 32 | '"Info"', '"Recruit"', '"SendDocument"' 33 | ), 34 | 35 | /* 36 | |-------------------------------------------------------------------------- 37 | | Workflow Flow Model 38 | |-------------------------------------------------------------------------- 39 | | 40 | | This is the Flow model used by Workflow to create correct relations. Update 41 | | the flow if it is in a different namespace. 42 | | 43 | */ 44 | 'flow' => '\Flow', 45 | 46 | /* 47 | |-------------------------------------------------------------------------- 48 | | Workflow Flows Table 49 | |-------------------------------------------------------------------------- 50 | | 51 | | This is the Flows table used by Workflow to save roles to the database. 52 | | 53 | */ 54 | 'flows_table' => 'flows', 55 | 56 | /* 57 | |-------------------------------------------------------------------------- 58 | | Workflow Node Model 59 | |-------------------------------------------------------------------------- 60 | | 61 | | This is the Node model used by Workflow to create correct relations. Update 62 | | the node if it is in a different namespace. 63 | | 64 | */ 65 | 'node' => '\Node', 66 | 67 | /* 68 | |-------------------------------------------------------------------------- 69 | | Workflow Nodes Table 70 | |-------------------------------------------------------------------------- 71 | | 72 | | This is the Nodes table used by Workflow to save Nodes to the database. 73 | | 74 | */ 75 | 'nodes_table' => 'nodes', 76 | 77 | /* 78 | |-------------------------------------------------------------------------- 79 | | Workflow node_role Table 80 | |-------------------------------------------------------------------------- 81 | | 82 | | This is the node_role table used by Workflow to save relationship between nodes and roles to the database. 83 | | 84 | */ 85 | 'node_role_table' => 'node_role', 86 | 87 | /* 88 | |-------------------------------------------------------------------------- 89 | | Workflow node_user Table 90 | |-------------------------------------------------------------------------- 91 | | 92 | | This is the node_user table used by Workflow to save relationship between nodes and users to the database. 93 | | 94 | */ 95 | 'node_user_table' => 'node_user', 96 | 97 | /* 98 | |-------------------------------------------------------------------------- 99 | | Workflow resource_flow Table 100 | |-------------------------------------------------------------------------- 101 | | 102 | | This is the resource_flow table used by Workflow to save relationship between resources and flows to the database. 103 | | 104 | */ 105 | 'resourceflow_table' => 'resourceflow', 106 | 'resourceflow' => '\Resourceflow', 107 | 108 | /* 109 | |-------------------------------------------------------------------------- 110 | | Workflow resourcenode Table 111 | |-------------------------------------------------------------------------- 112 | | 113 | | This is the resourcenode table used by Workflow to save relationship between resources and nodes to the database. 114 | | 115 | */ 116 | 'resourcenode_table' => 'resourcenode', 117 | 'resourcenode' => '\Resourcenode', 118 | 119 | /* 120 | |-------------------------------------------------------------------------- 121 | | Workflow resourcelog Table 122 | |-------------------------------------------------------------------------- 123 | | 124 | | This is the resourcelog table used by Workflow to save resource's log to the database. 125 | | 126 | */ 127 | 'resourcelog_table' => 'resourcelog', 128 | 'resourcelog' => '\Resourcelog', 129 | 130 | ); 131 | -------------------------------------------------------------------------------- /src/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davin-bao/workflow/8af8b33ef63e455a2a5a1cdf6ac7bc154d590488/src/controllers/.gitkeep -------------------------------------------------------------------------------- /src/lang/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davin-bao/workflow/8af8b33ef63e455a2a5a1cdf6ac7bc154d590488/src/lang/.gitkeep -------------------------------------------------------------------------------- /src/lang/zh_CN/button.php: -------------------------------------------------------------------------------- 1 | '查看', 6 | 'audit' =>'审核', 7 | 'read_more' => '查看详情', 8 | 'load_more' => '更多...', 9 | 'create' => '创建', 10 | 'edit' => '编辑', 11 | 'delete' => '删除', 12 | 'submit' => '提交', 13 | 'cancel' => '取消', 14 | 'ok' => '确定', 15 | 'return' => '返回', 16 | 'save' => '保存', 17 | 18 | 'show_all'=>'查看所有', 19 | 'show_audit'=>'待审核', 20 | 'show_completed'=>'已发布' 21 | ); 22 | -------------------------------------------------------------------------------- /src/lang/zh_CN/workflow.php: -------------------------------------------------------------------------------- 1 | '流程', 5 | 'node' => '节点', 6 | 'audit' =>'审核', 7 | 8 | 'name' => '名称', 9 | 'follower' => '参与者', 10 | 'select_all' => '全选', 11 | 'create' => '创建', 12 | 'edit' => '修改', 13 | 'delete' => '删除', 14 | 15 | 'success' => '成功', 16 | 'saved' => '已保存', 17 | 'general_info' => '基本信息', 18 | 'does_not_exist' => '该信息不存在', 19 | 'action' => '操作', 20 | 'failed_unknown' => '失败', 21 | 22 | 23 | 'start' => '开始', 24 | 'stop' => '结束', 25 | 26 | 'proceed' => '审核过程中', 27 | 'unstart' => '未审核', 28 | 'completed' => '已发布', 29 | 'discard' => '已废弃', 30 | 31 | 32 | 'select_this_role' => '选中这里,将会对该角色下的所有成员开放该节点的审批权限!', 33 | 'resource_type' => '可绑定资源类型', 34 | 'comment'=>'审核评语', 35 | 'audit_user' => '审核人', 36 | 'audit_result' => '审核结果', 37 | 'push' => '发文', 38 | 'agreed' => '通过', 39 | 'disagreed' => '不通过', 40 | 'unaudited' => '待审核', 41 | 'gofirst' => '发稿人重新核对后再审核', 42 | 'goback' => '上一个审核人重新审核', 43 | 'discard' => '废弃', 44 | 'publish' => '发布', 45 | 'archived' => '存档', 46 | 47 | 'audit_info' => '审核信息', 48 | 'show_log' => '查看日志', 49 | 50 | 'delete_flow_info' => '是否确定删除该审核流程信息?', 51 | ); 52 | -------------------------------------------------------------------------------- /src/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davin-bao/workflow/8af8b33ef63e455a2a5a1cdf6ac7bc154d590488/src/migrations/.gitkeep -------------------------------------------------------------------------------- /src/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davin-bao/workflow/8af8b33ef63e455a2a5a1cdf6ac7bc154d590488/src/views/.gitkeep -------------------------------------------------------------------------------- /src/views/audit_detail.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | @if($entry->getAuditByTimeLine()) 6 | 7 |
    8 | @foreach ( $entry->getAuditByTimeLine() as $key => $items ) 9 | 10 |
  • 11 | {{{ $key }}} 12 |
  • 13 | 14 | @foreach ( $items as $ikey => $item ) 15 | 16 |
  • 17 | @if ($item['result'] == 'agreed') 18 | 19 | @elseif($item['result'] == 'disagreed') 20 | 21 | @else 22 | 23 | @endif 24 |
    25 | {{{ $item['updated_at'] }}} 26 | 27 |

    {{{ $item['username'] }}} {{{ $item['nodename'] }}} 28 | @if ($item['result'] == 'agreed') 29 | 30 | @elseif($item['result'] == 'disagreed') 31 | 32 | @else 33 | 34 | @endif 35 | {{{ Lang::get('workflow::workflow.'.$item['result']) }}}

    36 | 37 |
    38 | 39 |     {{{ $item['comment'] }}} 40 |
    41 | 44 |
    45 |
  • 46 | 47 | 48 | @endforeach 49 | @endforeach 50 |
  • 51 | 52 |
  • 53 |
54 | 55 | @if ($entry->status() != '') {{{ Lang::get('workflow::workflow.'.$entry->status()) }}} @endif 56 | 57 | @endif 58 |
59 | 60 |
-------------------------------------------------------------------------------- /src/views/audit_form.blade.php: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 7 | 8 | 9 |
10 | 11 |
12 | 13 | 14 | 15 | 16 |
17 | 18 |
19 | 20 | 21 |
22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 |
37 |
38 |
39 | 40 | 58 | 59 | 60 |
61 |
62 | @if($entry->shouldPublish()) 63 | {{{ Lang::get('workflow::workflow.publish') }}} 64 | @else 65 | 66 | @endif 67 |
68 |
69 |
70 |
71 |
72 | 73 |
74 |
75 | 76 | 77 |
78 |
79 |
80 |
81 |
82 |
83 | 84 | 85 |
86 | 87 |
88 | 89 | 90 | 91 | 111 | 112 | 113 | {{-- Scripts --}} 114 | @section('scripts') 115 | 142 | @stop -------------------------------------------------------------------------------- /src/views/binding_form.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | 10 | {{ $errors->first('flow_id', '') }} 11 |
12 |
13 | -------------------------------------------------------------------------------- /src/views/flow_form.blade.php: -------------------------------------------------------------------------------- 1 | 2 |
3 | 8 |
9 | 10 |
11 | 12 | 15 | 16 | 17 | 18 |
19 | 20 |
21 | 22 | 23 | 24 | 25 |
26 | 27 |
28 | 29 | 30 | {{ $errors->first('flow_name', '') }} 31 |
32 | 33 | 34 |
35 | 36 |
37 | 48 | {{ $errors->first('resource_type', '') }} 49 |
50 |
51 | 52 | 53 | 64 | 65 |
66 | 67 | 68 |
69 | 70 | 71 | 72 |
73 |
74 | 76 | {{{ Lang::get('workflow::button.return') }}} 77 |
78 |
79 | 80 |
81 |
82 | 83 | 84 | 85 | 145 | 146 | 147 | {{-- Scripts --}} 148 | @section('scripts') 149 | 425 | @stop -------------------------------------------------------------------------------- /src/views/flow_graph.blade.php: -------------------------------------------------------------------------------- 1 | 2 | @section('styles') 3 | .btn.btn-circle { 4 | width: 40px; 5 | height: 40px; 6 | line-height: 40px; 7 | padding: 0; 8 | -webkit-border-radius: 50%; 9 | -moz-border-radius: 50%; 10 | border-radius: 50%; 11 | } 12 | @stop 13 | 14 |
15 | 16 | @if ($flow) 17 | @foreach ($flow->nodes as $node) 18 | 23 | 24 | @endforeach 25 | @endif 26 | 27 |
28 | -------------------------------------------------------------------------------- /src/views/generators/AdminFlowController.blade.php: -------------------------------------------------------------------------------- 1 | {{ 'flow = $flow; 15 | } 16 | 17 | /** 18 | * Display a listing of the resource. 19 | * 20 | * @return Response 21 | */ 22 | public function getIndex() 23 | { 24 | 25 | // Grab all the flows 26 | $flows = Flow::paginate(Config::get('app.pagenate_num')); 27 | 28 | // Show the page 29 | return View::make(Config::get('app.admin_template').'/flows/index', compact('flows')); 30 | } 31 | /** 32 | * Admin dashboard 33 | * 34 | */ 35 | public function getCreate() 36 | { 37 | $title = Lang::get('workflow::workflow.create'); 38 | $roles = Role::with('users')->get(); 39 | // Show the page 40 | return View::make(Config::get('app.admin_template').'/flows/create_edit', compact('title', 'roles')); 41 | } 42 | 43 | public function postCreate(){ 44 | $this->flow = new Flow(); 45 | $this->flow->flow_name = Input::get('flow_name'); 46 | $this->flow->resource_type = Input::get( 'resource_type' ); 47 | 48 | if ($this->flow->save(Flow::$rules) ) 49 | { 50 | $res = Array('result'=>true,'id'=>$this->flow->id, 'message'=>Lang::get('workflow::workflow.saved')); 51 | } 52 | else 53 | { 54 | // Get validation errors (see Ardent package) 55 | $error = $this->flow->errors()->all(); 56 | $res = Array('result'=>false,'id'=>1, 'message'=>$error); 57 | } 58 | 59 | echo json_encode($res); 60 | } 61 | 62 | public function getEdit($flow) { 63 | if ( $flow->id ) 64 | { 65 | $roles = Role::with('users')->get(); 66 | $title = Lang::get('workflow::workflow.create'); 67 | 68 | // Show the page 69 | return View::make(Config::get('app.admin_template').'/flows/create_edit', compact('title', 'flow', 'roles')); 70 | } 71 | else 72 | { 73 | return Redirect::to('admin/flows')->with('error', Lang::get('workflow::workflow.does_not_exist')); 74 | } 75 | } 76 | 77 | public function postEdit($flow){ 78 | 79 | // Validate the inputs 80 | $validator = Validator::make(Input::all(), Flow::$rules); 81 | 82 | // Check if the form validates with success 83 | if ($validator->passes()) 84 | { 85 | $flow->flow_name = Input::get( 'flow_name' ); 86 | $flow->resource_type = Input::get( 'resource_type' ); 87 | $nodeIds = Input::get('node_ids'); 88 | if(!$nodeIds || !is_array($nodeIds)){ 89 | $nodeIds = array(); 90 | } 91 | $flow->updateNodesOrder($nodeIds); 92 | 93 | // Was the role updated? 94 | if ($flow->save()) 95 | { 96 | $res = Array('result'=>true,'id'=>$flow->id, 'message'=>Lang::get('workflow::workflow.saved')); 97 | } 98 | else 99 | { 100 | // Redirect to the role page 101 | $res = Array('result'=>false,'id'=>$flow->id, 'message'=>$flow->errors()->all()); 102 | } 103 | }else{ 104 | $res = Array('result'=>false,'id'=>$flow->id, 'message'=>$validator->errors()->all()); 105 | } 106 | 107 | echo json_encode($res); 108 | } 109 | 110 | public function postCreateNode($flow){ 111 | $node = new Node(); 112 | $node->node_name =Lang::get('workflow::workflow.node').Lang::get('workflow::workflow.name'); 113 | 114 | if($flow->nodes()->save($node)){ 115 | $res = Array('result'=>true,'id'=>$node->id,'node_name'=>$node->node_name,'users'=>'','roles'=>'', 'message'=>Lang::get('workflow::workflow.saved')); 116 | }else{ 117 | $res = Array('result'=>false, 'message'=>$node->errors()->all()); 118 | } 119 | echo json_encode($res); 120 | } 121 | } -------------------------------------------------------------------------------- /src/views/generators/AdminNodeController.blade.php: -------------------------------------------------------------------------------- 1 | {{ 'node = $node; 16 | } 17 | 18 | public function getEdit($node) { 19 | if ( $node->id ) 20 | { 21 | $res = Array('result'=>true,'id'=>$node->id,'node_name'=>$node->node_name,'users'=>$node->users->toArray(),'roles'=>$node->roles->toArray(),'userstr'=>$node->UsersString(),'rolestr'=>$node->RolesString(), 'message'=>Lang::get('workflow::workflow.success')); 22 | } 23 | else 24 | { 25 | $res = Array('result'=>false,'id'=>$node->id, 'message'=>Lang::get('workflow::workflow.does_not_exist')); 26 | } 27 | echo json_encode($res); 28 | } 29 | 30 | public function postEdit($node){ 31 | 32 | // Validate the inputs 33 | $validator = Validator::make(Input::all(), Node::$rules); 34 | 35 | // Check if the form validates with success 36 | if ($validator->passes()) 37 | { 38 | $node->node_name = Input::get( 'node_name' ); 39 | $roles = Input::get('roles'); 40 | if(!is_array($roles)){ 41 | $roles = array(); 42 | } 43 | $users = Input::get('users'); 44 | if(!is_array($users)){ 45 | $users = array(); 46 | } 47 | $node->roles()->sync($roles); 48 | $node->users()->sync($users); 49 | 50 | // Was the role updated? 51 | if ($node->save()) 52 | { 53 | $res = Array('result'=>true,'id'=>$node->id, 'message'=>Lang::get('workflow::workflow.saved')); 54 | } 55 | else 56 | { 57 | // Redirect to the role page 58 | $res = Array('result'=>false,'id'=>$node->id, 'message'=>$node->errors()->all()); 59 | } 60 | }else{ 61 | $res = Array('result'=>false,'id'=>$node->id, 'message'=>$validator->errors()->all()); 62 | } 63 | 64 | echo json_encode($res); 65 | } 66 | 67 | public function postDelete($node) 68 | { 69 | 70 | if($node->delete()) { 71 | // Redirect to the role management page 72 | $res = Array('result'=>true,'id'=>$node->id, 'message'=>Lang::get('workflow::workflow.success')); 73 | }else{ 74 | $res = Array('result'=>true,'id'=>$node->id, 'message'=>$node->errors()->all()); 75 | } 76 | 77 | echo json_encode($res); 78 | } 79 | 80 | 81 | 82 | public function getShowlog(){ 83 | 84 | $resourcenode = \Resourcenode::find(\Input::get('id')); 85 | if ( $resourcenode ) 86 | { 87 | $log = $resourcenode->resourceLog()->first(); 88 | if($log) { 89 | $username = $resourcenode->user()->first()->name(); 90 | $result = $resourcenode->result; 91 | return \View::make(\Config::get('app.admin_template').'/Flows/show_log', compact('log','username','result')); 92 | } 93 | } 94 | return Redirect::to('admin/flows')->with('error', Lang::get('workflow::workflow.does_not_exist')); 95 | } 96 | 97 | } -------------------------------------------------------------------------------- /src/views/generators/Flow.blade.php: -------------------------------------------------------------------------------- 1 | {{ 'increments('id')->unsigned(); 19 | $table->string('flow_name')->unique(); 20 | $table->enum('resource_type', array({{ $res_type }})); 21 | $table->timestamps(); 22 | }); 23 | 24 | // Creates the nodes table 25 | Schema::create('nodes', function($table) 26 | { 27 | $table->increments('id')->unsigned(); 28 | $table->string('node_name'); 29 | $table->integer('flow_id')->unsigned(); 30 | $table->integer('orders')->unsigned()->default(1); 31 | $table->timestamps(); 32 | $table->foreign('flow_id')->references('id')->on('flows'); 33 | }); 34 | 35 | // Creates the node_role (Many-to-Many relation) table 36 | Schema::create('node_role', function($table) 37 | { 38 | $table->increments('id')->unsigned(); 39 | $table->integer('node_id')->unsigned(); 40 | $table->integer('role_id')->unsigned(); 41 | $table->foreign('node_id')->references('id')->on('nodes'); 42 | $table->foreign('role_id')->references('id')->on('roles'); // assumes a roles table 43 | }); 44 | 45 | // Creates the node_user (Many-to-Many relation) table 46 | Schema::create('node_user', function($table) 47 | { 48 | $table->increments('id')->unsigned(); 49 | $table->integer('node_id')->unsigned(); 50 | $table->integer('user_id')->unsigned(); 51 | $table->foreign('node_id')->references('id')->on('nodes'); 52 | $table->foreign('user_id')->references('id')->on('users'); // assumes a users table 53 | }); 54 | 55 | // Creates the resource_flows (Many-to-Many relation) table 56 | Schema::create('resourceflow', function($table) 57 | { 58 | $table->increments('id')->unsigned(); 59 | $table->integer('resource_id')->unsigned(); 60 | $table->enum('resource_type', array({{ $res_type }})); 61 | $table->integer('flow_id')->unsigned(); 62 | $table->enum('status', array('unstart','discard', 'proceed', 'completed', 'archived'))->default('unstart'); 63 | $table->integer('node_orders')->unsigned()->default(0); 64 | $table->timestamps(); 65 | $table->foreign('flow_id')->references('id')->on('flows'); 66 | }); 67 | 68 | // Creates the resource_node (Many-to-Many relation) table 69 | Schema::create('resourcenode', function($table) 70 | { 71 | $table->increments('id')->unsigned(); 72 | $table->integer('resourceflow_id')->unsigned(); 73 | $table->integer('user_id')->unsigned(); 74 | $table->integer('orders')->unsigned(); 75 | $table->text('comment'); 76 | $table->enum('result', array('agreed', 'disagreed', 'unaudited'))->default('unaudited'); 77 | $table->timestamps(); 78 | $table->foreign('resourceflow_id')->references('id')->on('resourceflow'); 79 | $table->foreign('user_id')->references('id')->on('users'); 80 | }); 81 | 82 | // Creates the resourcelog (One-to-Many relation) table 83 | Schema::create('resourcelog', function($table) 84 | { 85 | $table->increments('id')->unsigned(); 86 | $table->integer('resourcenode_id')->unsigned(); 87 | $table->string('title'); 88 | $table->text('content'); 89 | $table->timestamps(); 90 | $table->foreign('resourcenode_id')->references('id')->on('resourcenode'); 91 | }); 92 | } 93 | 94 | /** 95 | * Reverse the migrations. 96 | * 97 | * @return void 98 | */ 99 | public function down() 100 | { 101 | Schema::table('nodes', function(Blueprint $table) { 102 | $table->dropForeign('nodes_flow_id_foreign'); 103 | }); 104 | Schema::table('node_role', function(Blueprint $table) { 105 | $table->dropForeign('node_role_node_id_foreign'); 106 | $table->dropForeign('node_role_role_id_foreign'); 107 | }); 108 | Schema::table('node_user', function(Blueprint $table) { 109 | $table->dropForeign('node_user_node_id_foreign'); 110 | $table->dropForeign('node_user_user_id_foreign'); 111 | }); 112 | Schema::table('resourceflow', function(Blueprint $table) { 113 | $table->dropForeign('resourceflow_flow_id_foreign'); 114 | }); 115 | Schema::table('resourcenode', function(Blueprint $table) { 116 | $table->dropForeign('resourcenode_resourceflow_id_foreign'); 117 | $table->dropForeign('resourcenode_user_id_foreign'); 118 | }); 119 | Schema::table('resourcelog', function(Blueprint $table) { 120 | $table->dropForeign('resourcelog_resourcenode_id_foreign'); 121 | }); 122 | 123 | Schema::drop('flows'); 124 | Schema::drop('nodes'); 125 | Schema::drop('node_role'); 126 | Schema::drop('node_user'); 127 | Schema::drop('resourceflow'); 128 | Schema::drop('resourcenode'); 129 | Schema::drop('resourcelog'); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/views/generators/routes.blade.php: -------------------------------------------------------------------------------- 1 | {{ "\n\n" }} 2 | Route::model('flow', 'Flow'); 3 | Route::pattern('flow', '[0-9]+'); 4 | Route::model('node', 'Nlow'); 5 | Route::pattern('node', '[0-9]+'); 6 | {{ "\n" }} 7 | Route::group(array('prefix' => 'admin', 'before' => 'auth'), function() 8 | { 9 | Route::post('flows/{{ lcfirst(substr($name,0,-10)) }}/createnode', 'AdminFlowController@postCreateNode'); 10 | Route::get('flows/{{ lcfirst(substr($name,0,-10)) }}/edit', 'AdminFlowController@getEdit'); 11 | Route::post('flows/{{ lcfirst(substr($name,0,-10)) }}/edit', 'AdminFlowController@postEdit'); 12 | Route::controller('/flows', 'AdminFlowController'); 13 | 14 | Route::get('nodes/showlog', 'AdminNodeController@getShowlog'); 15 | Route::get('nodes/{node}/edit', 'AdminNodeController@getEdit'); 16 | Route::post('nodes/{node}/edit', 'AdminNodeController@postEdit'); 17 | Route::delete('nodes/{node}/delete', 'AdminNodeController@postDelete'); 18 | Route::controller('/nodes', 'AdminNodeController'); 19 | }); 20 | {{ "\n" }} -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davin-bao/workflow/8af8b33ef63e455a2a5a1cdf6ac7bc154d590488/tests/.gitkeep -------------------------------------------------------------------------------- /tests/HasFlowForResourceTest.php: -------------------------------------------------------------------------------- 1 | mockApp(); 23 | 24 | $this->testingModel = new TestingModel(); 25 | } 26 | 27 | 28 | public function testBindingFlow() 29 | { 30 | $flow = m::mock('WorkflowFlow'); 31 | $this->testingModel->bindingFlow(1); 32 | $this->assertEquals(1,1); 33 | } 34 | 35 | private function mockApp() 36 | { 37 | // Mocks the application components 38 | $app = array(); 39 | 40 | $app['config'] = m::mock( 'Config' ); 41 | $app['config']->shouldReceive( 'get' ) 42 | ->with( 'auth.table' ) 43 | ->andReturn( 'users' ); 44 | 45 | $app['config']->shouldReceive( 'workflow::resourceflow_table' ) 46 | ->andReturn( 'resourceflow' ); 47 | return $app; 48 | } 49 | 50 | 51 | protected function getPackageProviders() 52 | { 53 | return array('DavinBao\WorkflowServiceProvider'); 54 | } 55 | 56 | protected function getPackageAliases() 57 | { 58 | return array( 59 | 'DavinBao' => 'DavinBao\Facade' 60 | ); 61 | } 62 | } 63 | 64 | class TestingModel 65 | { 66 | use HasFlowForResource; 67 | 68 | public $roles = array(); 69 | public $perms = array(); 70 | 71 | function __construct() 72 | { 73 | 74 | } 75 | } --------------------------------------------------------------------------------