diff --git a/app/Console/Commands/CreateAdmin.php b/app/Console/Commands/CreateAdmin.php index 89b564091e..7a2c9a1feb 100644 --- a/app/Console/Commands/CreateAdmin.php +++ b/app/Console/Commands/CreateAdmin.php @@ -76,10 +76,4 @@ class CreateAdmin extends Command } - // protected function getArguments() - // { - // return array( - // array('username', InputArgument::REQUIRED, 'Username'), - // ); - // } } diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 3713624422..fed6c0398c 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -49,6 +49,12 @@ class Kernel extends ConsoleKernel $schedule->command('backup:clean')->daily(); } + /** + * This method is required by Laravel to handle any console routes + * that are defined in routes/console.php + * + * @return void + */ protected function commands() { require base_path('routes/console.php'); diff --git a/app/Http/Controllers/Api/CategoriesController.php b/app/Http/Controllers/Api/CategoriesController.php index 399a2d78fb..3a208c64ae 100644 --- a/app/Http/Controllers/Api/CategoriesController.php +++ b/app/Http/Controllers/Api/CategoriesController.php @@ -114,15 +114,15 @@ class CategoriesController extends Controller public function destroy($id) { $this->authorize('delete', Category::class); - $category = Category::findOrFail($id); + $category = Category::withCount('models as models_count', 'accessories as accessories_count','consumables as consumables_count','components as components_count')->findOrFail($id); - if ($category->has_models() > 0) { + if ($category->models_count > 0) { return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'model']))); - } elseif ($category->accessories()->count() > 0) { + } elseif ($category->accessories_count > 0) { return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'accessory']))); - } elseif ($category->consumables()->count() > 0) { + } elseif ($category->consumables_count > 0) { return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'consumable']))); - } elseif ($category->components()->count() > 0) { + } elseif ($category->components_count > 0) { return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/categories/message.assoc_items', ['asset_type'=>'component']))); } $category->delete(); diff --git a/app/Http/Controllers/Api/DepreciationsController.php b/app/Http/Controllers/Api/DepreciationsController.php index 970e82e313..e3f6edf2e8 100644 --- a/app/Http/Controllers/Api/DepreciationsController.php +++ b/app/Http/Controllers/Api/DepreciationsController.php @@ -110,10 +110,10 @@ class DepreciationsController extends Controller public function destroy($id) { $this->authorize('delete', Depreciation::class); - $depreciation = Depreciation::findOrFail($id); + $depreciation = Depreciation::withCount('models as models_count')->findOrFail($id); $this->authorize('delete', $depreciation); - if ($depreciation->has_models() > 0) { + if ($depreciation->models_count > 0) { return response()->json(Helper::formatStandardApiResponse('error', trans('admin/depreciations/message.assoc_users'))); } diff --git a/app/Http/Controllers/CategoriesController.php b/app/Http/Controllers/CategoriesController.php index 4745fc747f..2de5fd9a50 100755 --- a/app/Http/Controllers/CategoriesController.php +++ b/app/Http/Controllers/CategoriesController.php @@ -168,20 +168,21 @@ class CategoriesController extends Controller { $this->authorize('delete', Category::class); // Check if the category exists - if (is_null($category = Category::find($categoryId))) { + if (is_null($category = Category::withCount('models as models_count', 'accessories as accessories_count','consumables as consumables_count','components as components_count')->findOrFail($categoryId))) { return redirect()->route('categories.index')->with('error', trans('admin/categories/message.not_found')); } - if ($category->has_models() > 0) { + if ($category->models_count > 0) { return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'model'])); - } elseif ($category->accessories()->count() > 0) { - return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'accessory'])); - } elseif ($category->consumables()->count() > 0) { - return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'consumable'])); - } elseif ($category->components()->count() > 0) { - return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'component'])); + } elseif ($category->accessories_count > 0) { + return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'accessory'])); + } elseif ($category->consumables_count > 0) { + return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'consumable'])); + } elseif ($category->components_count > 0) { + return redirect()->route('categories.index')->with('error', trans('admin/categories/message.assoc_items', ['asset_type'=>'component'])); } + $category->delete(); // Redirect to the locations management page return redirect()->route('categories.index')->with('success', trans('admin/categories/message.delete.success')); diff --git a/app/Http/Controllers/DepreciationsController.php b/app/Http/Controllers/DepreciationsController.php index 91b168aca0..86b9e895e6 100755 --- a/app/Http/Controllers/DepreciationsController.php +++ b/app/Http/Controllers/DepreciationsController.php @@ -150,13 +150,13 @@ class DepreciationsController extends Controller public function destroy($depreciationId) { // Check if the depreciation exists - if (is_null($depreciation = Depreciation::find($depreciationId))) { + if (is_null($depreciation = Depreciation::withCount('models as models_count')->find($depreciationId))) { return redirect()->route('depreciations.index')->with('error', trans('admin/depreciations/message.not_found')); } $this->authorize('delete', $depreciation); - if ($depreciation->has_models() > 0) { + if ($depreciation->models_count > 0) { // Redirect to the asset management page return redirect()->route('depreciations.index')->with('error', trans('admin/depreciations/message.assoc_users')); } diff --git a/app/Http/Controllers/ManufacturersController.php b/app/Http/Controllers/ManufacturersController.php index d28a1411f1..1bbd4466d4 100755 --- a/app/Http/Controllers/ManufacturersController.php +++ b/app/Http/Controllers/ManufacturersController.php @@ -152,14 +152,11 @@ class ManufacturersController extends Controller public function destroy($manufacturerId) { $this->authorize('delete', Manufacturer::class); - // Check if the manufacturer exists - if (is_null($manufacturer = Manufacturer::find($manufacturerId))) { - // Redirect to the manufacturers page + if (is_null($manufacturer = Manufacturer::withCount('models as models_count')->find($manufacturerId))) { return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.not_found')); } - if ($manufacturer->has_models() > 0) { - // Redirect to the asset management page + if ($manufacturer->models_count > 0) { return redirect()->route('manufacturers.index')->with('error', trans('admin/manufacturers/message.assoc_users')); } @@ -167,7 +164,7 @@ class ManufacturersController extends Controller try { unlink(public_path().'/uploads/manufacturers/'.$manufacturer->image); } catch (\Exception $e) { - \Log::error($e); + } } diff --git a/app/Importer/Importer.php b/app/Importer/Importer.php index 0d864f175b..88b3888022 100644 --- a/app/Importer/Importer.php +++ b/app/Importer/Importer.php @@ -113,6 +113,13 @@ abstract class Importer // Cached Values for import lookups protected $customFields; + /** + * Sets up the database transaction and logging for the importer + * + * @return void + * @author Daniel Meltzer + * @since 5.0 + */ public function import() { $headerRow = $this->csv->fetchOne(); diff --git a/app/Models/Accessory.php b/app/Models/Accessory.php index 772099418d..8fa27515e9 100755 --- a/app/Models/Accessory.php +++ b/app/Models/Accessory.php @@ -101,13 +101,26 @@ class Accessory extends SnipeModel - + /** + * Establishes the accessory -> supplier relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function supplier() { return $this->belongsTo('\App\Models\Supplier', 'supplier_id'); } - + + /** + * Sets the requestable attribute on the accessory + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return void + */ public function setRequestableAttribute($value) { if ($value == '') { @@ -117,24 +130,49 @@ class Accessory extends SnipeModel return; } + /** + * Establishes the accessory -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** + * Establishes the accessory -> location relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); } + /** + * Establishes the accessory -> category relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id')->where('category_type', '=', 'accessory'); } /** - * Get action logs for this accessory - */ + * Returns the action logs associated with the accessory + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id')->where('item_type', Accessory::class)->orderBy('created_at', 'desc')->withTrashed(); @@ -173,6 +211,16 @@ class Accessory extends SnipeModel } + /** + * Sets the full image url + * + * @todo this should probably be moved out of the model and into a + * presenter or service provider + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string + */ public function getImageUrl() { if ($this->image) { return url('/').'/uploads/accessories/'.$this->image; @@ -181,31 +229,77 @@ class Accessory extends SnipeModel } + /** + * Establishes the accessory -> users relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function users() { return $this->belongsToMany('\App\Models\User', 'accessories_users', 'accessory_id', 'assigned_to')->withPivot('id')->withTrashed(); } + /** + * Checks whether or not the accessory has users + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return int + */ public function hasUsers() { return $this->belongsToMany('\App\Models\User', 'accessories_users', 'accessory_id', 'assigned_to')->count(); } + /** + * Establishes the accessory -> manufacturer relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manufacturer() { return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id'); } + /** + * Determins whether or not an email should be sent for checkin/checkout of this + * accessory based on the category it belongs to. + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return boolean + */ public function checkin_email() { return $this->category->checkin_email; } + /** + * Determines whether or not the accessory should require the user to + * accept it via email. + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return boolean + */ public function requireAcceptance() { return $this->category->require_acceptance; } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string + */ public function getEula() { @@ -219,6 +313,13 @@ class Accessory extends SnipeModel return null; } + /** + * Check how many items of an accessory remain + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return int + */ public function numRemaining() { $checkedout = $this->users->count(); diff --git a/app/Models/Actionlog.php b/app/Models/Actionlog.php index b2945b8d13..f28ab36895 100755 --- a/app/Models/Actionlog.php +++ b/app/Models/Actionlog.php @@ -41,9 +41,15 @@ class Actionlog extends SnipeModel */ protected $searchableRelations = [ 'company' => ['name'] - ]; + ]; - // Overridden from Builder to automatically add the company + /** + * Override from Builder to automatically add the company + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public static function boot() { parent::boot(); @@ -60,17 +66,39 @@ class Actionlog extends SnipeModel } }); } - // Eloquent Relationships below + + + /** + * Establishes the actionlog -> item relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function item() { return $this->morphTo('item')->withTrashed(); } + /** + * Establishes the actionlog -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->hasMany('\App\Models\Company', 'id', 'company_id'); } + /** + * Establishes the actionlog -> item type relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function itemType() { @@ -80,6 +108,13 @@ class Actionlog extends SnipeModel return camel_case(class_basename($this->item_type)); } + /** + * Establishes the actionlog -> target type relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function targetType() { if ($this->target_type == User::class) { @@ -88,28 +123,14 @@ class Actionlog extends SnipeModel return camel_case(class_basename($this->target_type)); } - public function parseItemRoute() - { - if ($this->itemType() == "asset") { - $itemroute = 'assets'; - } elseif ($this->itemType() == "accessory") { - $itemroute = 'accessories'; - } elseif ($this->itemType()=="consumable") { - $itemroute = 'consumables'; - } elseif ($this->itemType()=="license") { - $itemroute = 'licenses'; - } elseif ($this->itemType()=="component") { - $itemroute = 'components'; - } else { - $itemroute = ''; - } - - return $itemroute; - } - - - + /** + * Establishes the actionlog -> uploads relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function uploads() { return $this->morphTo('item') @@ -117,39 +138,62 @@ class Actionlog extends SnipeModel ->withTrashed(); } + /** + * Establishes the actionlog -> userlog relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function userlog() { return $this->target(); } + /** + * Establishes the actionlog -> user relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function user() { return $this->belongsTo(User::class, 'user_id') ->withTrashed(); } + /** + * Establishes the actionlog -> target relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function target() { return $this->morphTo('target')->withTrashed(); } - public function childlogs() - { - return $this->hasMany('\App\Models\ActionLog', 'thread_id'); - } - - public function parentlog() - { - return $this->belongsTo('\App\Models\ActionLog', 'thread_id'); - } - + /** + * Establishes the actionlog -> location relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id' )->withTrashed(); } + /** - * Check if the file exists, and if it does, force a download - **/ + * Check if the file exists, and if it does, force a download + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string | false + */ public function get_src($type = 'assets', $fieldname = 'filename') { if ($this->filename!='') { @@ -162,8 +206,12 @@ class Actionlog extends SnipeModel /** - * Get the parent category name - */ + * Saves the log record with the action type + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return boolean + */ public function logaction($actiontype) { @@ -176,6 +224,13 @@ class Actionlog extends SnipeModel } } + /** + * Calculate the number of days until the next audit + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return int + */ public function daysUntilNextAudit($monthInterval = 12, $asset = null) { $now = Carbon::now(); @@ -192,6 +247,13 @@ class Actionlog extends SnipeModel return $next_audit_days; } + /** + * Calculate the date of the next audit + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Datetime + */ public function calcNextAuditDate($monthInterval = 12, $asset = null) { $last_audit_date = Carbon::parse($this->created_at); @@ -204,12 +266,12 @@ class Actionlog extends SnipeModel } /** - * getListingOfActionLogsChronologicalOrder - * - * @return mixed - * @author Vincent Sposato - * @version v1.0 - */ + * Gets action logs in chronological order, excluding uploads + * + * @author Vincent Sposato + * @since v1.0 + * @return \Illuminate\Database\Eloquent\Collection + */ public function getListingOfActionLogsChronologicalOrder() { diff --git a/app/Models/Asset.php b/app/Models/Asset.php index d02513aa8d..4805602f34 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -174,12 +174,26 @@ class Asset extends Depreciable return null; } + + /** + * Establishes the asset -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } - + /** + * Determines if an asset is available for checkout + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return boolean + */ public function availableForCheckout() { if ( @@ -192,8 +206,13 @@ class Asset extends Depreciable return false; } + /** - * Checkout asset + * Checks the asset out to the target + * + * @todo The admin parameter is never used. Can probably be removed. + * + * @author [A. Gianotto] [] * @param User $user * @param User $admin * @param Carbon $checkout_at @@ -201,8 +220,9 @@ class Asset extends Depreciable * @param string $note * @param null $name * @return bool + * @since [v3.0] + * @return boolean */ - //FIXME: The admin parameter is never used. Can probably be removed. public function checkOut($target, $admin = null, $checkout_at = null, $expected_checkin = null, $note = null, $name = null, $location = null) { if (!$target) { @@ -253,6 +273,13 @@ class Asset extends Depreciable return false; } + /** + * Sets the detailedNameAttribute + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string + */ public function getDetailedNameAttribute() { if ($this->assignedto) { @@ -263,31 +290,54 @@ class Asset extends Depreciable return $this->asset_tag . ' - ' . $this->name . ' (' . $user_name . ') ' . ($this->model) ? $this->model->name: ''; } - public function validationRules($id = '0') + /** + * Pulls in the validation rules + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return array + */ + public function validationRules() { return $this->rules; } /** - * Set depreciation relationship - */ + * Establishes the asset -> depreciation relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function depreciation() { return $this->model->belongsTo('\App\Models\Depreciation', 'depreciation_id'); } + /** * Get components assigned to this asset + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function components() { return $this->belongsToMany('\App\Models\Component', 'components_assets', 'asset_id', 'component_id')->withPivot('id', 'assigned_qty')->withTrashed(); } - /** - * Get depreciation attribute from associated asset model - */ + + /** + * Get depreciation attribute from associated asset model + * + * @todo Is this still needed? + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function get_depreciation() { if (($this->model) && ($this->model->depreciation)) { @@ -295,9 +345,14 @@ class Asset extends Depreciable } } - /** - * Get uploads for this asset - */ + + /** + * Get uploads for this asset + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function uploads() { return $this->hasMany('\App\Models\Actionlog', 'item_id') @@ -307,29 +362,58 @@ class Asset extends Depreciable ->orderBy('created_at', 'desc'); } + /** + * Determines whether the asset is checked out to a user + * * Even though we allow allow for checkout to things beyond users * this method is an easy way of seeing if we are checked out to a user. - * @return mixed + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean */ public function checkedOutToUser() { return $this->assignedType() === self::USER; } + /** + * Get the target this asset is checked out to + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assignedTo() { return $this->morphTo('assigned', 'assigned_type', 'assigned_to'); } + /** + * Gets assets assigned to this asset + * + * Sigh. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assignedAssets() { return $this->morphMany('App\Models\Asset', 'assigned', 'assigned_type', 'assigned_to')->withTrashed(); } - /** - * Get the asset's location based on the assigned user - **/ + + /** + * Get the asset's location based on the assigned user + * + * @todo Refactor this if possible. It's awful. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \ArrayObject + */ public function assetLoc($iterations = 1,$first_asset = null) { if (!empty($this->assignedType())) { @@ -364,19 +448,40 @@ class Asset extends Depreciable return $this->defaultLoc; } + /** + * Gets the lowercased name of the type of target the asset is assigned to + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string + */ public function assignedType() { return strtolower(class_basename($this->assigned_type)); } - /** - * Get the asset's location based on default RTD location - **/ + + /** + * Get the asset's location based on default RTD location + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function defaultLoc() { return $this->belongsTo('\App\Models\Location', 'rtd_location_id'); } - + /** + * Get the image URL of the asset. + * + * Check first to see if there is a specific image uploaded to the asset, + * and if not, check for an image uploaded to the asset model. + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return string | false + */ public function getImageUrl() { if ($this->image && !empty($this->image)) { @@ -388,9 +493,13 @@ class Asset extends Depreciable } - /** - * Get action logs for this asset - */ + /** + * Get the asset's logs + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id') @@ -400,7 +509,11 @@ class Asset extends Depreciable } /** - * Get checkouts + * Get the list of checkouts for this asset + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function checkouts() { @@ -410,7 +523,11 @@ class Asset extends Depreciable } /** - * Get checkins + * Get the list of checkins for this asset + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function checkins() { @@ -421,7 +538,11 @@ class Asset extends Depreciable } /** - * Get user requests + * Get the asset's user requests + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function userRequests() { @@ -432,71 +553,65 @@ class Asset extends Depreciable } - /** - * assetmaintenances - * Get improvements for this asset - * - * @return mixed - * @author Vincent Sposato - * @version v1.0 - */ + /** + * Get maintenances for this asset + * + * @author Vincent Sposato + * @since 1.0 + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetmaintenances() { return $this->hasMany('\App\Models\AssetMaintenance', 'asset_id') ->orderBy('created_at', 'desc'); } - /** - * Get action logs for this asset - */ + /** + * Get action logs history for this asset + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function adminuser() { return $this->belongsTo('\App\Models\User', 'user_id'); } - /** - * Get total assets - */ - public static function assetcount() - { - return Company::scopeCompanyables(Asset::where('physical', '=', '1')) - ->whereNull('deleted_at', 'and') - ->count(); - } - /** - * Get total assets not checked out - */ - public static function availassetcount() - { - return Asset::RTD() - ->whereNull('deleted_at') - ->count(); - } - /** - * Get requestable assets - */ - public static function getRequestable() - { - return Asset::Requestable() - ->whereNull('deleted_at') - ->count(); - } - - /** - * Get asset status - */ + /** + * Establishes the asset -> status relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetstatus() { return $this->belongsTo('\App\Models\Statuslabel', 'status_id'); } + /** + * Establishes the asset -> model relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function model() { return $this->belongsTo('\App\Models\AssetModel', 'model_id')->withTrashed(); } + /** + * Return the assets with a warranty expiring within x days + * + * @param $days + * @author [A. Gianotto] [] + * @since [v2.0] + * @return mixed + */ public static function getExpiringWarrantee($days = 30) { return Asset::where('archived', '=', '0') @@ -510,25 +625,50 @@ class Asset extends Depreciable ->get(); } - /** - * Get the license seat information - **/ + + /** + * Establishes the asset -> assigned licenses relationship + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenses() { return $this->belongsToMany('\App\Models\License', 'license_seats', 'asset_id', 'license_id'); } + /** + * Establishes the asset -> status relationship + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenseseats() { return $this->hasMany('\App\Models\LicenseSeat', 'asset_id'); } + /** + * Establishes the asset -> aupplier relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function supplier() { return $this->belongsTo('\App\Models\Supplier', 'supplier_id'); } - + /** + * Establishes the asset -> location relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); @@ -536,9 +676,13 @@ class Asset extends Depreciable - /** - * Get auto-increment - */ + /** + * Get the next autoincremented asset tag + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string | false + */ public static function autoincrement_asset() { $settings = \App\Models\Setting::getSettings(); @@ -561,10 +705,15 @@ class Asset extends Depreciable } } - /* - * Get the next base number for the auto-incrementer. We'll add the zerofill and - * prefixes on the fly as we generate the number + + /** + * Get the next base number for the auto-incrementer. * + * We'll add the zerofill and prefixes on the fly as we generate the number. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return int */ public static function nextAutoIncrement($assets) { @@ -590,23 +739,53 @@ class Asset extends Depreciable - + /** + * Add zerofilling based on Settings + * + * We'll add the zerofill and prefixes on the fly as we generate the number. + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string + */ public static function zerofill($num, $zerofill = 3) { return str_pad($num, $zerofill, '0', STR_PAD_LEFT); } - + /** + * Determine whether to send a checkin/checkout email based on + * asset model category + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean + */ public function checkin_email() { return $this->model->category->checkin_email; } + /** + * Determine whether this asset requires acceptance by the assigned user + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean + */ public function requireAcceptance() { return $this->model->category->require_acceptance; } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string | false + */ public function getEula() { $Parsedown = new \Parsedown(); @@ -620,91 +799,92 @@ class Asset extends Depreciable } } + + /** + * ----------------------------------------------- + * BEGIN QUERY SCOPES + * ----------------------------------------------- + **/ + /** * Run additional, advanced searches. - * - * @param Illuminate\Database\Eloquent\Builder $query + * + * @param \Illuminate\Database\Eloquent\Builder $query * @param array $terms The search terms - * @return Illuminate\Database\Eloquent\Builder + * @return \Illuminate\Database\Eloquent\Builder */ public function advancedTextSearch(Builder $query, array $terms) { - - /** - * Assigned user - */ - $query = $query->leftJoin('users as assets_users',function ($leftJoin) { + /** + * Assigned user + */ + $query = $query->leftJoin('users as assets_users',function ($leftJoin) { $leftJoin->on("assets_users.id", "=", "assets.assigned_to") ->where("assets.assigned_type", "=", User::class); - }); + }); - foreach($terms as $term) { + foreach($terms as $term) { - $query = $query - ->orWhere('assets_users.first_name', 'LIKE', '%'.$term.'%') - ->orWhere('assets_users.last_name', 'LIKE', '%'.$term.'%') - ->orWhere('assets_users.username', 'LIKE', '%'.$term.'%') - ->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$term%", "%$term%"]); + $query = $query + ->orWhere('assets_users.first_name', 'LIKE', '%'.$term.'%') + ->orWhere('assets_users.last_name', 'LIKE', '%'.$term.'%') + ->orWhere('assets_users.username', 'LIKE', '%'.$term.'%') + ->orWhereRaw('CONCAT('.DB::getTablePrefix().'assets_users.first_name," ",'.DB::getTablePrefix().'assets_users.last_name) LIKE ?', ["%$term%", "%$term%"]); - } + } - /** - * Assigned location - */ - $query = $query->leftJoin('locations as assets_locations',function ($leftJoin) { - $leftJoin->on("assets_locations.id","=","assets.assigned_to") - ->where("assets.assigned_type","=",Location::class); - }); + /** + * Assigned location + */ + $query = $query->leftJoin('locations as assets_locations',function ($leftJoin) { + $leftJoin->on("assets_locations.id","=","assets.assigned_to") + ->where("assets.assigned_type","=",Location::class); + }); - foreach($terms as $term) { + foreach($terms as $term) { - $query = $query->orWhere('assets_locations.name', 'LIKE', '%'.$term.'%'); + $query = $query->orWhere('assets_locations.name', 'LIKE', '%'.$term.'%'); - } + } - /** - * Assigned assets - */ - $query = $query->leftJoin('assets as assigned_assets',function ($leftJoin) { - $leftJoin->on('assigned_assets.id', '=', 'assets.assigned_to') - ->where('assets.assigned_type', '=', Asset::class); - }); + /** + * Assigned assets + */ + $query = $query->leftJoin('assets as assigned_assets',function ($leftJoin) { + $leftJoin->on('assigned_assets.id', '=', 'assets.assigned_to') + ->where('assets.assigned_type', '=', Asset::class); + }); - foreach($terms as $term) { + foreach($terms as $term) { - $query = $query->orWhere('assigned_assets.name', 'LIKE', '%'.$term.'%'); - - } + $query = $query->orWhere('assigned_assets.name', 'LIKE', '%'.$term.'%'); - return $query; + } + + return $query; } - /** - * ----------------------------------------------- - * BEGIN QUERY SCOPES - * ----------------------------------------------- - **/ - /** - * Query builder scope for hardware - * - * @param \Illuminate\Database\Query\Builder $query Query builder instance - * - * @return \Illuminate\Database\Query\Builder Modified query builder - */ + /** + * Query builder scope for hardware + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopeHardware($query) { return $query->where('physical', '=', '1'); } - /** - * Query builder scope for pending assets - * - * @param \Illuminate\Database\Query\Builder $query Query builder instance - * - * @return \Illuminate\Database\Query\Builder Modified query builder - */ + /** + * Query builder scope for pending assets + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopePending($query) { diff --git a/app/Models/AssetMaintenance.php b/app/Models/AssetMaintenance.php index af05774f13..020bf2777c 100644 --- a/app/Models/AssetMaintenance.php +++ b/app/Models/AssetMaintenance.php @@ -22,7 +22,6 @@ class AssetMaintenance extends Model implements ICompanyableChild protected $dates = [ 'deleted_at', 'start_date' , 'completion_date']; protected $table = 'asset_maintenances'; - // Declaring rules for form validation protected $rules = [ 'asset_id' => 'required|integer', 'supplier_id' => 'required|integer', diff --git a/app/Models/AssetModel.php b/app/Models/AssetModel.php index 9c18f522a5..a570cd8c75 100755 --- a/app/Models/AssetModel.php +++ b/app/Models/AssetModel.php @@ -87,44 +87,92 @@ class AssetModel extends SnipeModel 'depreciation' => ['name'], 'category' => ['name'], 'manufacturer' => ['name'], - ]; + ]; + + /** + * Establishes the model -> assets relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assets() { return $this->hasMany('\App\Models\Asset', 'model_id'); } + /** + * Establishes the model -> category relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id'); } + /** + * Establishes the model -> depreciation relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function depreciation() { return $this->belongsTo('\App\Models\Depreciation', 'depreciation_id'); } - public function adminuser() - { - return $this->belongsTo('\App\Models\User', 'user_id'); - } + /** + * Establishes the model -> manufacturer relationship + * + * @author [A. Gianotto] [] + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manufacturer() { return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id'); } + /** + * Establishes the model -> fieldset relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function fieldset() { return $this->belongsTo('\App\Models\CustomFieldset', 'fieldset_id'); } + /** + * Establishes the model -> custom field default values relationship + * + * @author hannah tinkler + * @since [v4.3] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function defaultValues() { return $this->belongsToMany('\App\Models\CustomField', 'models_custom_fields')->withPivot('default_value'); } + /** + * Gets the full url for the image + * + * @todo this should probably be moved + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function getImageUrl() { if ($this->image) { return url('/').'/uploads/models/'.$this->image; @@ -141,8 +189,8 @@ class AssetModel extends SnipeModel /** * Query builder scope for Deleted assets * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @return Illuminate\Database\Query\Builder Modified query builder + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeDeleted($query) diff --git a/app/Models/Category.php b/app/Models/Category.php index 7650cdde76..c88280df0e 100755 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -80,31 +80,62 @@ class Category extends SnipeModel */ protected $searchableRelations = []; - public function has_models() - { - return $this->hasMany('\App\Models\AssetModel', 'category_id')->count(); - } + /** + * Establishes the category -> accessories relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function accessories() { return $this->hasMany('\App\Models\Accessory'); } + /** + * Establishes the category -> licenses relationship + * + * @author [A. Gianotto] [] + * @since [v4.3] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenses() { return $this->hasMany('\App\Models\License'); } + /** + * Establishes the category -> consumables relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function consumables() { return $this->hasMany('\App\Models\Consumable'); } + /** + * Establishes the category -> consumables relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function components() { return $this->hasMany('\App\Models\Component'); } + /** + * Get the number of items in the category + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return int + */ public function itemCount() { switch ($this->category_type) { @@ -120,16 +151,38 @@ class Category extends SnipeModel return '0'; } + /** + * Establishes the category -> assets relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assets() { return $this->hasManyThrough('\App\Models\Asset', '\App\Models\AssetModel', 'category_id', 'model_id'); } + /** + * Establishes the category -> models relationship + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function models() { return $this->hasMany('\App\Models\AssetModel', 'category_id'); } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v2.0] + * @return string | null + */ public function getEula() { @@ -145,15 +198,22 @@ class Category extends SnipeModel } + /** - * scopeRequiresAcceptance + * ----------------------------------------------- + * BEGIN QUERY SCOPES + * ----------------------------------------------- + **/ + + /** + * Query builder scope for whether or not the category requires acceptance * - * @param $query - * - * @return mixed * @author Vincent Sposato - * @version v1.0 + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @return \Illuminate\Database\Query\Builder Modified query builder */ + public function scopeRequiresAcceptance($query) { diff --git a/app/Models/Component.php b/app/Models/Component.php index cc973c6bf5..8ccc3c3070 100644 --- a/app/Models/Component.php +++ b/app/Models/Component.php @@ -86,43 +86,89 @@ class Component extends SnipeModel 'category' => ['name'], 'company' => ['name'], 'location' => ['name'], - ]; + ]; + /** + * Establishes the component -> location relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); } + /** + * Establishes the component -> assets relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assets() { return $this->belongsToMany('\App\Models\Asset', 'components_assets')->withPivot('id', 'assigned_qty', 'created_at', 'user_id'); } + /** + * Establishes the component -> admin user relationship + * + * @todo this is probably not needed - refactor + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function admin() { return $this->belongsTo('\App\Models\User', 'user_id'); } + /** + * Establishes the component -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } - + /** + * Establishes the component -> category relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id'); } /** - * Get action logs for this consumable - */ + * Establishes the component -> action logs relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id')->where('item_type', Component::class)->orderBy('created_at', 'desc')->withTrashed(); } - + /** + * Check how many items within a component are remaining + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return int + */ public function numRemaining() { $checkedout = 0; @@ -140,10 +186,10 @@ class Component extends SnipeModel /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCategory($query, $order) { @@ -153,10 +199,10 @@ class Component extends SnipeModel /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderLocation($query, $order) { @@ -167,10 +213,10 @@ class Component extends SnipeModel /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCompany($query, $order) { diff --git a/app/Models/Consumable.php b/app/Models/Consumable.php index 7f61c895f1..b1d3fe222c 100644 --- a/app/Models/Consumable.php +++ b/app/Models/Consumable.php @@ -88,8 +88,21 @@ class Consumable extends SnipeModel 'company' => ['name'], 'location' => ['name'], 'manufacturer' => ['name'], - ]; + ]; + /** + * Sets the attribute of whether or not the consumable is requestable + * + * This isn't really implemented yet, as you can't currently request a consumable + * however it will be implemented in the future, and we needed to include + * this method here so all of our polymorphic methods don't break. + * + * @todo Update this comment once it's been implemented + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function setRequestableAttribute($value) { if ($value == '') { @@ -99,44 +112,98 @@ class Consumable extends SnipeModel return; } + /** + * Establishes the consumable -> admin user relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function admin() { return $this->belongsTo('\App\Models\User', 'user_id'); } + /** + * Establishes the component -> assignments relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function consumableAssignments() { return $this->hasMany('\App\Models\ConsumableAssignment'); } + /** + * Establishes the component -> company relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** + * Establishes the component -> manufacturer relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manufacturer() { return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id'); } + /** + * Establishes the component -> location relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); } + /** + * Establishes the component -> category relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id'); } + /** - * Get action logs for this consumable - */ + * Establishes the component -> action logs relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id')->where('item_type', Consumable::class)->orderBy('created_at', 'desc')->withTrashed(); } + /** + * Gets the full image url for the consumable + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return string | false + */ public function getImageUrl() { if ($this->image) { return url('/').'/uploads/consumables/'.$this->image; @@ -145,27 +212,52 @@ class Consumable extends SnipeModel } - + /** + * Establishes the component -> users relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function users() { return $this->belongsToMany('\App\Models\User', 'consumables_users', 'consumable_id', 'assigned_to')->withPivot('user_id')->withTrashed()->withTimestamps(); } - public function hasUsers() - { - return $this->belongsToMany('\App\Models\User', 'consumables_users', 'consumable_id', 'assigned_to')->count(); - } + /** + * Determine whether to send a checkin/checkout email based on + * asset model category + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean + */ public function checkin_email() { return $this->category->checkin_email; - } + } + /** + * Determine whether this asset requires acceptance by the assigned user + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return boolean + */ public function requireAcceptance() { return $this->category->require_acceptance; } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string | false + */ public function getEula() { @@ -181,6 +273,13 @@ class Consumable extends SnipeModel } + /** + * Checks the number of available consumables + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return int + */ public function numRemaining() { $checkedout = $this->users->count(); @@ -192,10 +291,10 @@ class Consumable extends SnipeModel /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCategory($query, $order) { @@ -205,10 +304,10 @@ class Consumable extends SnipeModel /** * Query builder scope to order on location * - * @param Illuminate\Database\Query\Builder $query Query builder instance + * @param \Illuminate\Database\Query\Builder $query Query builder instance * @param text $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderLocation($query, $order) { @@ -218,10 +317,10 @@ class Consumable extends SnipeModel /** * Query builder scope to order on manufacturer * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderManufacturer($query, $order) { @@ -232,10 +331,10 @@ class Consumable extends SnipeModel /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCompany($query, $order) { diff --git a/app/Models/CustomField.php b/app/Models/CustomField.php index 4ea44fef90..eef6a55d9a 100644 --- a/app/Models/CustomField.php +++ b/app/Models/CustomField.php @@ -46,10 +46,15 @@ class CustomField extends Model 'show_in_email', ]; - // This is confusing, since it's actually the custom fields table that - // we're usually modifying, but since we alter the assets table, we have to - // say that here, otherwise the new fields get added onto the custom fields - // table instead of the assets table. + /** + * This is confusing, since it's actually the custom fields table that + * we're usually modifying, but since we alter the assets table, we have to + * say that here, otherwise the new fields get added onto the custom fields + * table instead of the assets table. + * + * @author [Brady Wetherington] [] + * @since [v3.0] + */ public static $table_name = "assets"; @@ -138,16 +143,37 @@ class CustomField extends Model }); } + /** + * Establishes the customfield -> fieldset relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function fieldset() { return $this->belongsToMany('\App\Models\CustomFieldset'); } + /** + * Establishes the customfield -> admin user relationship + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function user() { return $this->belongsTo('\App\Models\User'); } + /** + * Establishes the customfield -> default values relationship + * + * @author Hannah Tinkler + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function defaultValues() { return $this->belongsToMany('\App\Models\AssetModel', 'models_custom_fields')->withPivot('default_value'); @@ -169,11 +195,28 @@ class CustomField extends Model })->first(); } + /** + * Checks the format of the attribute + * + * @author [A. Gianotto] [] + * @param $value string + * @since [v3.0] + * @return boolean + */ public function check_format($value) { return preg_match('/^'.$this->attributes['format'].'$/', $value)===1; } + /** + * Gets the DB column name. + * + * @todo figure out if this is still needed? I don't know WTF it's for. + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function db_column_name() { return $this->db_column; @@ -188,7 +231,7 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Array + * @return string */ public function getFormatAttribute($value) { @@ -205,7 +248,7 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Array + * @return array */ public function setFormatAttribute($value) { @@ -221,7 +264,7 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Array + * @return array */ public function formatFieldValuesAsArray() { @@ -249,7 +292,7 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Boolean + * @return boolean */ public function isFieldDecryptable($string) { @@ -266,7 +309,7 @@ class CustomField extends Model * * @author [A. Gianotto] [] * @since [v3.4] - * @return Boolean + * @return boolean */ public function convertUnicodeDbSlug($original = null) { @@ -287,7 +330,7 @@ class CustomField extends Model * @author [V. Cordes] [] * @param int $id * @since [v4.1.10] - * @return Array + * @return array */ public function validationRules() { diff --git a/app/Models/CustomFieldset.php b/app/Models/CustomFieldset.php index d0aa33aa23..e25248f2c7 100644 --- a/app/Models/CustomFieldset.php +++ b/app/Models/CustomFieldset.php @@ -22,23 +22,52 @@ class CustomFieldset extends Model */ protected $injectUniqueIdentifier = true; use ValidatingTrait; - + + /** + * Establishes the fieldset -> field relationship + * + * @author [Brady Wetherington] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function fields() { return $this->belongsToMany('\App\Models\CustomField')->withPivot(["required","order"])->orderBy("pivot_order"); } + /** + * Establishes the fieldset -> models relationship + * + * @author [Brady Wetherington] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function models() { return $this->hasMany('\App\Models\AssetModel', "fieldset_id"); } + /** + * Establishes the fieldset -> admin user relationship + * + * @author [Brady Wetherington] [] + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function user() { return $this->belongsTo('\App\Models\User'); //WARNING - not all CustomFieldsets have a User!! } + /** + * Determine the validation rules we should apply based on the + * custom field format + * + * @author [A. Gianotto] [] + * @since [v3.0] + * @return array + */ public function validation_rules() { $rules=[]; diff --git a/app/Models/Department.php b/app/Models/Department.php index d9cab7a738..28f71935e8 100644 --- a/app/Models/Department.php +++ b/app/Models/Department.php @@ -60,18 +60,27 @@ class Department extends SnipeModel * * @var array */ - protected $searchableRelations = []; - + protected $searchableRelations = []; + /** + * Establishes the department -> company relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** - * Even though we allow allow for checkout to things beyond users - * this method is an easy way of seeing if we are checked out to a user. - * @return mixed + * Establishes the department -> users relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function users() { @@ -80,15 +89,24 @@ class Department extends SnipeModel /** - * Return the manager in charge of the dept - * @return mixed - */ + * Establishes the department -> manager relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manager() { return $this->belongsTo('\App\Models\User', 'manager_id'); } - + /** + * Establishes the department -> location relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id'); diff --git a/app/Models/Depreciation.php b/app/Models/Depreciation.php index e67d4d7fa4..c706f2f1e7 100755 --- a/app/Models/Depreciation.php +++ b/app/Models/Depreciation.php @@ -48,14 +48,28 @@ class Depreciation extends SnipeModel */ protected $searchableRelations = []; - - public function has_models() + /** + * Establishes the depreciation -> models relationship + * + * @author A. Gianotto + * @since [v5.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function models() { - return $this->hasMany('\App\Models\AssetModel', 'depreciation_id')->count(); + return $this->hasMany('\App\Models\AssetModel', 'depreciation_id'); } - public function has_licenses() + + /** + * Establishes the depreciation -> licenses relationship + * + * @author A. Gianotto + * @since [v5.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function licenses() { - return $this->hasMany('\App\Models\License', 'depreciation_id')->count(); + return $this->hasMany('\App\Models\License', 'depreciation_id'); } } diff --git a/app/Models/Group.php b/app/Models/Group.php index 1003e0d03f..ea04f035f5 100755 --- a/app/Models/Group.php +++ b/app/Models/Group.php @@ -37,17 +37,27 @@ class Group extends SnipeModel * * @var array */ - protected $searchableRelations = []; + protected $searchableRelations = []; /** - * Get user groups - */ + * Establishes the groups -> users relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function users() { return $this->belongsToMany('\App\Models\User', 'users_groups'); } - + /** + * Decode JSON permissions into array + * + * @author A. Gianotto + * @since [v1.0] + * @return array + */ public function decodePermissions() { return json_decode($this->permissions, true); diff --git a/app/Models/License.php b/app/Models/License.php index 9685b4b8f6..a3ac4c5985 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -110,8 +110,14 @@ class License extends Depreciable protected $searchableRelations = [ 'manufacturer' => ['name'], 'company' => ['name'], - ]; + ]; + /** + * Update seat counts when the license is updated + * + * @author A. Gianotto + * @since [v3.0] + */ public static function boot() { parent::boot(); @@ -128,6 +134,13 @@ class License extends Depreciable }); } + /** + * Balance seat counts + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public static function adjustSeatCount($license, $oldSeats, $newSeats) { // If the seats haven't changed, continue on happily. @@ -181,15 +194,37 @@ class License extends Depreciable return true; } + /** + * Sets the attribute for whether or not the license is maintained + * + * @author A. Gianotto + * @since [v1.0] + * @return mixed + */ public function setMaintainedAttribute($value) { $this->attributes['maintained'] = filter_var($value, FILTER_VALIDATE_BOOLEAN); } + + /** + * Sets the reassignable attribute + * + * @author A. Gianotto + * @since [v1.0] + * @return mixed + */ public function setReassignableAttribute($value) { $this->attributes['reassignable'] = filter_var($value, FILTER_VALIDATE_BOOLEAN); } + /** + * Sets expiration date attribute + * + * @author A. Gianotto + * @since [v1.0] + * @return mixed + */ public function setExpirationDateAttribute($value) { @@ -201,6 +236,13 @@ class License extends Depreciable $this->attributes['expiration_date'] = $value; } + /** + * Sets termination date attribute + * + * @author A. Gianotto + * @since [v2.0] + * @return mixed + */ public function setTerminationDateAttribute($value) { if ($value == '' || $value == '0000-00-00') { @@ -211,31 +253,74 @@ class License extends Depreciable $this->attributes['termination_date'] = $value; } + /** + * Establishes the license -> company relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** + * Establishes the license -> category relationship + * + * @author A. Gianotto + * @since [v4.4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function category() { return $this->belongsTo('\App\Models\Category', 'category_id'); } + /** + * Establishes the license -> manufacturer relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manufacturer() { return $this->belongsTo('\App\Models\Manufacturer', 'manufacturer_id'); } + /** + * Determine whether the user should be emailed on checkin/checkout + * + * @author A. Gianotto + * @since [v2.0] + * @return boolean + */ public function checkin_email() { return $this->category->checkin_email; } + /** + * Determine whether the user should be required to accept the license + * + * @author A. Gianotto + * @since [v4.0] + * @return boolean + */ public function requireAcceptance() { return $this->category->require_acceptance; } + /** + * Checks for a category-specific EULA, and if that doesn't exist, + * checks for a settings level EULA + * + * @author [A. Gianotto] [] + * @since [v4.0] + * @return string | false + */ public function getEula() { $Parsedown = new \Parsedown(); @@ -250,7 +335,11 @@ class License extends Depreciable } /** - * Get the assigned user + * Establishes the license -> assigned user relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assignedusers() { @@ -258,8 +347,12 @@ class License extends Depreciable } /** - * Get asset logs for this asset - */ + * Establishes the license -> action logs relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Actionlog', 'item_id') @@ -268,8 +361,12 @@ class License extends Depreciable } /** - * Get uploads for this asset - */ + * Establishes the license -> action logs -> uploads relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function uploads() { return $this->hasMany('\App\Models\Actionlog', 'item_id') @@ -281,16 +378,26 @@ class License extends Depreciable /** - * Get admin user for this asset - */ + * Establishes the license -> admin user relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function adminuser() { return $this->belongsTo('\App\Models\User', 'user_id'); } /** - * Get total licenses - */ + * Returns the total number of all license seats + * + * @todo this can probably be refactored at some point. We don't need counting methods. + * + * @author A. Gianotto + * @since [v2.0] + * @return int + */ public static function assetcount() { return LicenseSeat::whereNull('deleted_at') @@ -299,8 +406,14 @@ class License extends Depreciable /** - * Get total licenses - */ + * Return the number of seats for this asset + * + * @todo this can also probably be refactored at some point. + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function totalSeatsByLicenseID() { return LicenseSeat::where('license_id', '=', $this->id) @@ -308,12 +421,28 @@ class License extends Depreciable ->count(); } - // We do this to eager load the "count" of seats from the controller. Otherwise calling "count()" on each model results in n+1 + /** + * Establishes the license -> seat relationship + * + * We do this to eager load the "count" of seats from the controller. + * Otherwise calling "count()" on each model results in n+1 sadness. + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenseSeatsRelation() { return $this->hasMany(LicenseSeat::class)->whereNull('deleted_at')->selectRaw('license_id, count(*) as count')->groupBy('license_id'); } + /** + * Sets the license seat count attribute + * + * @author A. Gianotto + * @since [v2.0] + * @return int + */ public function getLicenseSeatsCountAttribute() { if ($this->licenseSeatsRelation->first()) { @@ -324,8 +453,12 @@ class License extends Depreciable } /** - * Get total licenses not checked out - */ + * Returns the number of total available seats across all licenses + * + * @author A. Gianotto + * @since [v2.0] + * @return int + */ public static function availassetcount() { return LicenseSeat::whereNull('assigned_to') @@ -335,7 +468,11 @@ class License extends Depreciable } /** - * Get the number of available seats + * Returns the number of total available seats for this license + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function availCount() { @@ -345,6 +482,13 @@ class License extends Depreciable ->whereNull('deleted_at'); } + /** + * Sets the available seats attribute + * + * @author A. Gianotto + * @since [v3.0] + * @return mixed + */ public function getAvailSeatsCountAttribute() { if ($this->availCount->first()) { @@ -355,8 +499,11 @@ class License extends Depreciable } /** - * Get the number of assigned seats + * Retuns the number of assigned seats for this asset * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assignedCount() { @@ -366,9 +513,15 @@ class License extends Depreciable }); } + /** + * Sets the assigned seats attribute + * + * @author A. Gianotto + * @since [v1.0] + * @return int + */ public function getAssignedSeatsCountAttribute() { - // dd($this->licenseSeatsRelation->first()); if ($this->assignedCount->first()) { return $this->assignedCount->first()->count; } @@ -376,6 +529,13 @@ class License extends Depreciable return 0; } + /** + * Calculates the number of remaining seats + * + * @author A. Gianotto + * @since [v1.0] + * @return int + */ public function remaincount() { $total = $this->licenseSeatsCount; @@ -385,7 +545,11 @@ class License extends Depreciable } /** - * Get the total number of seats + * Returns the total number of seats for this license + * + * @author A. Gianotto + * @since [v1.0] + * @return int */ public function totalcount() { @@ -396,21 +560,37 @@ class License extends Depreciable } /** - * Get license seat data + * Establishes the license -> seats relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function licenseseats() { return $this->hasMany('\App\Models\LicenseSeat'); } + /** + * Establishes the license -> supplier relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function supplier() { return $this->belongsTo('\App\Models\Supplier', 'supplier_id'); } - /* - * Get the next available free seat - used by + + /** + * Gets the next available free seat - used by * the API to populate next_seat + * + * @author A. Gianotto + * @since [v3.0] + * @return mixed */ public function freeSeat() { @@ -424,15 +604,28 @@ class License extends Depreciable ->first(); } - /* - * Get the next available free seat - used by - * the API to populate next_seat - */ + + /** + * Establishes the license -> free seats relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function freeSeats() { return $this->hasMany('\App\Models\LicenseSeat')->whereNull('assigned_to')->whereNull('deleted_at')->whereNull('asset_id'); } + /** + * Returns expiring licenses + * + * @todo should refactor. I don't like get() in model methods + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public static function getExpiringLicenses($days = 60) { @@ -448,10 +641,10 @@ class License extends Depreciable /** * Query builder scope to order on manufacturer * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderManufacturer($query, $order) { @@ -463,7 +656,7 @@ class License extends Depreciable * Query builder scope to order on supplier * * @param \Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param string $order Order * * @return \Illuminate\Database\Query\Builder Modified query builder */ @@ -476,10 +669,10 @@ class License extends Depreciable /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance + * @param \Illuminate\Database\Query\Builder $query Query builder instance * @param text $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderCompany($query, $order) { diff --git a/app/Models/LicenseSeat.php b/app/Models/LicenseSeat.php index 22f159b806..500391041d 100755 --- a/app/Models/LicenseSeat.php +++ b/app/Models/LicenseSeat.php @@ -28,21 +28,50 @@ class LicenseSeat extends Model implements ICompanyableChild return ['asset', 'license']; } + /** + * Establishes the seat -> license relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function license() { return $this->belongsTo('\App\Models\License', 'license_id'); } + /** + * Establishes the seat -> assignee relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function user() { return $this->belongsTo('\App\Models\User', 'assigned_to')->withTrashed(); } + /** + * Establishes the seat -> asset relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function asset() { return $this->belongsTo('\App\Models\Asset', 'asset_id')->withTrashed(); } + /** + * Determines the assigned seat's location based on user + * or asset its assigned to + * + * @author A. Gianotto + * @since [v4.0] + * @return string + */ public function location() { if (($this->user) && ($this->user->location)) { diff --git a/app/Models/Location.php b/app/Models/Location.php index 1e676854c3..a6e2007cd3 100755 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -79,11 +79,25 @@ class Location extends SnipeModel 'parent' => ['name'] ]; + /** + * Establishes the location -> users relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function users() { return $this->hasMany('\App\Models\User', 'location_id'); } + /** + * Establishes the location -> assets relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assets() { return $this->hasMany('\App\Models\Asset', 'location_id') @@ -94,52 +108,103 @@ class Location extends SnipeModel }); } + /** + * Establishes the location -> asset's RTD relationship + * + * This used to have an ...->orHas() clause that referred to + * assignedAssets, and that was probably incorrect, as well as + * definitely was setting fire to the query-planner. So don't do that. + * + * It is arguable that we should have a '...->whereNull('assigned_to') + * bit in there, but that isn't always correct either (in the case + * where a user has no location, for example). + * + * In all likelihood, we need to denorm an "effective_location" column + * into Assets to make this slightly less miserable. + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function rtd_assets() { - /* This used to have an ...->orHas() clause that referred to - assignedAssets, and that was probably incorrect, as well as - definitely was setting fire to the query-planner. So don't do that. - - It is arguable that we should have a '...->whereNull('assigned_to') - bit in there, but that isn't always correct either (in the case - where a user has no location, for example). - - In all likelyhood, we need to denorm an "effective_location" column - into Assets to make this slightly less miserable. + /* */ return $this->hasMany('\App\Models\Asset', 'rtd_location_id'); } + /** + * Establishes the location -> parent location relationship + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function parent() { return $this->belongsTo('\App\Models\Location', 'parent_id','id'); } + /** + * Establishes the location -> manager relationship + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manager() { return $this->belongsTo('\App\Models\User', 'manager_id'); } + /** + * Establishes the location -> child locations relationship + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function childLocations() { return $this->hasMany('\App\Models\Location', 'parent_id'); } - // I don't think we need this anymore since we de-normed location_id in assets? + /** + * Establishes the location -> assigned assets relationship + * + * I don't think we need this anymore since we de-normed location_id in assets? + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assignedAssets() { return $this->morphMany('App\Models\Asset', 'assigned', 'assigned_type', 'assigned_to')->withTrashed(); } + /** + * Sets the location-specific OU attribute + * + * @author A. Gianotto + * @since [v3.0] + * @return mixed + */ public function setLdapOuAttribute($ldap_ou) { return $this->attributes['ldap_ou'] = empty($ldap_ou) ? null : $ldap_ou; } + /** + * Recursion to determine location hierarchy + * + * @author A. Gianotto + * @since [v3.0] + * @return mixed + */ public static function getLocationHierarchy($locations, $parent_id = null) { - $op = array(); foreach ($locations as $location) { @@ -163,7 +228,15 @@ class Location extends SnipeModel return $op; } - + /** + * Flattens the location array for display on the front-end + * + * @todo maybe move to presenters? + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public static function flattenLocationsArray($location_options_array = null) { $location_options = array(); @@ -193,14 +266,15 @@ class Location extends SnipeModel /** * Query builder scope to order on parent * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * We have to use a Left join here, or it will only return results with parents * - * @return Illuminate\Database\Query\Builder Modified query builder + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order + * + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderParent($query, $order) { - // Left join here, or it will only return results with parents return $query->leftJoin('locations as parent_loc', 'locations.parent_id', '=', 'parent_loc.id')->orderBy('parent_loc.name', $order); } @@ -208,7 +282,7 @@ class Location extends SnipeModel * Query builder scope to order on manager name * * @param \Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param string $order Order * * @return \Illuminate\Database\Query\Builder Modified query builder */ diff --git a/app/Models/Manufacturer.php b/app/Models/Manufacturer.php index 81dbfdac8b..c684c068d1 100755 --- a/app/Models/Manufacturer.php +++ b/app/Models/Manufacturer.php @@ -66,11 +66,6 @@ class Manufacturer extends SnipeModel - public function has_models() - { - return $this->hasMany('\App\Models\AssetModel', 'manufacturer_id')->count(); - } - public function assets() { return $this->hasManyThrough('\App\Models\Asset', '\App\Models\AssetModel', 'manufacturer_id', 'model_id'); diff --git a/app/Models/Statuslabel.php b/app/Models/Statuslabel.php index fa6f6df1ba..c97b6c9c70 100755 --- a/app/Models/Statuslabel.php +++ b/app/Models/Statuslabel.php @@ -50,19 +50,28 @@ class Statuslabel extends SnipeModel * * @var array */ - protected $searchableRelations = []; + protected $searchableRelations = []; /** - * Get assets with associated status label + * Establishes the status label -> assets relationship * - * @return \Illuminate\Support\Collection + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assets() { return $this->hasMany('\App\Models\Asset', 'status_id'); } + /** + * Gets the status label type + * + * @author A. Gianotto + * @since [v1.0] + * @return string + */ public function getStatuslabelType() { @@ -78,6 +87,11 @@ class Statuslabel extends SnipeModel } + /** + * Query builder scope to for pending status types + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopePending() { return $this->where('pending', '=', 1) @@ -85,6 +99,11 @@ class Statuslabel extends SnipeModel ->where('deployable', '=', 0); } + /** + * Query builder scope for archived status types + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopeArchived() { return $this->where('pending', '=', 0) @@ -92,6 +111,11 @@ class Statuslabel extends SnipeModel ->where('deployable', '=', 0); } + /** + * Query builder scope for deployable status types + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ public function scopeDeployable() { return $this->where('pending', '=', 0) @@ -99,7 +123,13 @@ class Statuslabel extends SnipeModel ->where('deployable', '=', 1); } - + /** + * Helper function to determine type attributes + * + * @author A. Gianotto + * @since [v1.0] + * @return string + */ public static function getStatuslabelTypesForDB($type) { diff --git a/app/Models/Supplier.php b/app/Models/Supplier.php index 82c3a0770c..2313e998a9 100755 --- a/app/Models/Supplier.php +++ b/app/Models/Supplier.php @@ -66,13 +66,30 @@ class Supplier extends SnipeModel protected $fillable = ['name','address','address2','city','state','country','zip','phone','fax','email','contact','url','notes']; - // Eager load counts. - // We do this to eager load the "count" of seats from the controller. Otherwise calling "count()" on each model results in n+1 + /** + * Eager load counts + * + * We do this to eager load the "count" of seats from the controller. + * Otherwise calling "count()" on each model results in n+1. + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetsRelation() { return $this->hasMany(Asset::class)->whereNull('deleted_at')->selectRaw('supplier_id, count(*) as count')->groupBy('supplier_id'); } + /** + * Sets the license seat count attribute + * + * @todo I don't see the licenseSeatsRelation here? + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function getLicenseSeatsCountAttribute() { if ($this->licenseSeatsRelation->first()) { @@ -81,21 +98,50 @@ class Supplier extends SnipeModel return 0; } + + /** + * Establishes the supplier -> assets relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assets() { return $this->hasMany('\App\Models\Asset', 'supplier_id'); } + /** + * Establishes the supplier -> accessories relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function accessories() { return $this->hasMany('\App\Models\Accessory', 'supplier_id'); } + /** + * Establishes the supplier -> asset maintenances relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function asset_maintenances() { return $this->hasMany('\App\Models\AssetMaintenance', 'supplier_id'); } + /** + * Return the number of assets by supplier + * + * @author A. Gianotto + * @since [v1.0] + * @return int + */ public function num_assets() { if ($this->assetsRelation->first()) { @@ -105,16 +151,39 @@ class Supplier extends SnipeModel return 0; } + /** + * Establishes the supplier -> license relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function licenses() { return $this->hasMany('\App\Models\License', 'supplier_id'); } + /** + * Return the number of licenses by supplier + * + * @author A. Gianotto + * @since [v1.0] + * @return int + */ public function num_licenses() { return $this->licenses()->count(); } + /** + * Add http to the url in suppliers if the user didn't give one + * + * @todo this should be handled via validation, no? + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function addhttp($url) { if (!preg_match("~^(?:f|ht)tps?://~i", $url)) { diff --git a/app/Models/Throttle.php b/app/Models/Throttle.php deleted file mode 100644 index 85e447378e..0000000000 --- a/app/Models/Throttle.php +++ /dev/null @@ -1,14 +0,0 @@ -belongsTo('User', 'user_id'); - } -} diff --git a/app/Models/User.php b/app/Models/User.php index 1a3eea8cc9..71fa797dcb 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -100,8 +100,18 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo 'department' => ['name'], 'groups' => ['name'], 'manager' => ['first_name', 'last_name', 'username'] - ]; + ]; + /** + * Check user permissions + * + * Parses the user and group permission masks to see if the user + * is authorized to do the thing + * + * @author A. Gianotto + * @since [v1.0] + * @return boolean + */ public function hasAccess($section) { if ($this->isSuperUser()) { @@ -136,6 +146,13 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo return false; } + /** + * Checks if the user is a SuperUser + * + * @author A. Gianotto + * @since [v1.0] + * @return boolean + */ public function isSuperUser() { if (!$user_permissions = json_decode($this->permissions, true)) { @@ -158,26 +175,63 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo } + /** + * Establishes the user -> company relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function company() { return $this->belongsTo('\App\Models\Company', 'company_id'); } + /** + * Establishes the user -> department relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function department() { return $this->belongsTo('\App\Models\Department', 'department_id'); } + /** + * Checks activated status + * + * @author A. Gianotto + * @since [v1.0] + * @return boolean + */ public function isActivated() { return $this->activated ==1; } + /** + * Returns the full name attribute + * + * @author A. Gianotto + * @since [v2.0] + * @return string + */ public function getFullNameAttribute() { return $this->first_name . " " . $this->last_name; } + /** + * Returns the complete name attribute with username + * + * @todo refactor this so it's less repetitive and dumb + * + * @author A. Gianotto + * @since [v2.0] + * @return string + */ public function getCompleteNameAttribute() { return $this->last_name . ", " . $this->first_name . " (" . $this->username . ")"; @@ -198,7 +252,11 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo /** - * Get assets assigned to this user + * Establishes the user -> assets relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assets() { @@ -206,7 +264,14 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo } /** - * Get assets assigned to this user + * Establishes the user -> maintenances relationship + * + * This would only be used to return maintenances that this user + * created. + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function assetmaintenances() { @@ -214,7 +279,11 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo } /** - * Get accessories assigned to this user + * Establishes the user -> accessories relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function accessories() { @@ -222,7 +291,11 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo } /** - * Get consumables assigned to this user + * Establishes the user -> consumables relationship + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function consumables() { @@ -230,7 +303,11 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo } /** - * Get licenses assigned to this user + * Establishes the user -> license seats relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function licenses() { @@ -238,78 +315,105 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo } /** - * Get action logs for this user + * Establishes the user -> actionlogs relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function userlog() { return $this->hasMany('\App\Models\Actionlog', 'target_id')->orderBy('created_at', 'DESC')->withTrashed(); } + /** + * Establishes the user -> location relationship + * * Get the asset's location based on the assigned user - * @todo - this should be removed once we're sure we've switched it - * to location() - **/ + * + * @todo - this should be removed once we're sure we've switched it to location() + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ + public function userloc() { return $this->belongsTo('\App\Models\Location', 'location_id')->withTrashed(); } + /** - * Get the asset's location based on the assigned user - **/ + * Establishes the user -> location relationship + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function location() { return $this->belongsTo('\App\Models\Location', 'location_id')->withTrashed(); } + /** - * Get the user's manager based on the assigned user - **/ + * Establishes the user -> manager relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function manager() { return $this->belongsTo('\App\Models\User', 'manager_id')->withTrashed(); } /** - * Get any locations the user manages. - **/ + * Establishes the user -> managed locations relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function managedLocations() { return $this->hasMany('\App\Models\Location', 'manager_id')->withTrashed(); } /** - * Get user groups + * Establishes the user -> groups relationship + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function groups() { return $this->belongsToMany('\App\Models\Group', 'users_groups'); } - - public function accountStatus() - { - if ($this->throttle) { - if ($this->throttle->suspended==1) { - return 'suspended'; - } elseif ($this->throttle->banned==1) { - return 'banned'; - } else { - return false; - } - } else { - return false; - } - } - + /** + * Establishes the user -> assets relationship + * + * @author A. Gianotto + * @since [v4.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + */ public function assetlog() { return $this->hasMany('\App\Models\Asset', 'id')->withTrashed(); } /** - * Get uploads for this asset + * Establishes the user -> uploads relationship + * + * @todo I don't think we use this? + * + * @author A. Gianotto + * @since [v3.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function uploads() { @@ -321,28 +425,54 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo } /** - * Fetch Items User has requested + * Establishes the user -> requested assets relationship + * + * @author A. Gianotto + * @since [v2.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation */ public function checkoutRequests() { return $this->belongsToMany(Asset::class, 'checkout_requests', 'user_id', 'requestable_id')->whereNull('canceled_at'); } - public function throttle() - { - return $this->hasOne('\App\Models\Throttle'); - } - + /** + * Query builder scope to return deleted users + * @author A. Gianotto + * @since [v2.0] + * + * @param string $query + * @return \Illuminate\Database\Query\Builder + */ public function scopeGetDeleted($query) { return $query->withTrashed()->whereNotNull('deleted_at'); } + /** + * Query builder scope to return NOT-deleted users + * @author A. Gianotto + * @since [v2.0] + * + * @param string $query + * @return \Illuminate\Database\Query\Builder + */ public function scopeGetNotDeleted($query) { return $query->whereNull('deleted_at'); } + /** + * Query builder scope to return users by email or username + * + * @author A. Gianotto + * @since [v2.0] + * + * @param string $query + * @param string $user_username + * @param string $user_email + * @return \Illuminate\Database\Query\Builder + */ public function scopeMatchEmailOrUsername($query, $user_username, $user_email) { return $query->where('email', '=', $user_email) @@ -350,6 +480,15 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo ->orWhere('username', '=', $user_email); } + /** + * Generate email from full name + * + * @author A. Gianotto + * @since [v2.0] + * + * @param string $query + * @return string + */ public static function generateEmailFromFullName($name) { $username = User::generateFormattedNameFromFullName($name, Setting::getSettings()->email_format); @@ -422,9 +561,9 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo /** * Run additional, advanced searches. * - * @param Illuminate\Database\Eloquent\Builder $query - * @param array $term The search terms - * @return Illuminate\Database\Eloquent\Builder + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param array $terms The search terms + * @return \Illuminate\Database\Eloquent\Builder */ public function advancedTextSearch(Builder $query, array $terms) { @@ -435,7 +574,13 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo return $query; } - + /** + * Query builder scope to return users by group + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param int $id + * @return \Illuminate\Database\Query\Builder + */ public function scopeByGroup($query, $id) { return $query->whereHas('groups', function ($query) use ($id) { $query->where('groups.id', '=', $id); @@ -445,9 +590,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo /** * Query builder scope for Deleted users * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * - * @return Illuminate\Database\Query\Builder Modified query builder + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeDeleted($query) @@ -459,10 +603,10 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo /** * Query builder scope to order on manager * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderManager($query, $order) { @@ -473,10 +617,10 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo /** * Query builder scope to order on company * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderLocation($query, $order) { @@ -487,10 +631,10 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo /** * Query builder scope to order on department * - * @param Illuminate\Database\Query\Builder $query Query builder instance - * @param text $order Order + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param string $order Order * - * @return Illuminate\Database\Query\Builder Modified query builder + * @return \Illuminate\Database\Query\Builder Modified query builder */ public function scopeOrderDepartment($query, $order) { diff --git a/tests/unit/CategoryTest.php b/tests/unit/CategoryTest.php index 3fa114bb52..6d0d4e2fe4 100644 --- a/tests/unit/CategoryTest.php +++ b/tests/unit/CategoryTest.php @@ -34,7 +34,7 @@ class CategoryTest extends BaseTest $category = $this->createValidCategory('asset-desktop-category'); $models = factory(App\Models\AssetModel::class, 5)->states('mbp-13-model')->create(['category_id' => $category->id]); - $this->assertEquals(5, $category->has_models()); + $this->assertEquals(5, $category->models->count()); $this->assertCount(5, $category->models); $models->each(function($model) { diff --git a/tests/unit/DepreciationTest.php b/tests/unit/DepreciationTest.php index b1c5416e15..bb31de772c 100644 --- a/tests/unit/DepreciationTest.php +++ b/tests/unit/DepreciationTest.php @@ -32,7 +32,7 @@ class DepreciationTest extends BaseTest $this->createValidAssetModel(); $depreciation = $this->createValidDepreciation('computer', ['name' => 'New Depreciation']); $models = factory(App\Models\AssetModel::class, 5)->states('mbp-13-model')->create(['depreciation_id'=>$depreciation->id]); - $this->assertEquals(5,$depreciation->has_models()); + $this->assertEquals(5,$depreciation->models->count()); } public function testADepreciationHasLicenses()