$value) { $product->set_info($field, $value); } foreach($tags as $tag) { $product->add_tag($tag); } commit_trans(); return $product; } catch(Exception $e) { revert_trans(); throw $e; } } public static function compare($prod1, $prod2) { return strcmp(strtolower($prod1->get_name()), strtolower($prod2->get_name())); } public function __construct($clue, $type = 'id') { parent::__construct(); $search = null; switch($type) { case 'id': $search = prepare('select `id` from `product` where `id`=?'); bind($search, 'i', $clue); break; case 'serial': $search = prepare('select `id` from `product` where `serial`=?'); bind($search, 's', $clue); break; default: throw new Exception('Invalid type.'); } execute($search); $result = result_single($search); if($result === null) { throw new Exception('Product does not exist.'); } $this->id = $result['id']; $this->update_fields(); $this->update_info(); $this->update_tags(); # Global variables are bad, but passing these email properties # around everywhere would be worse global $sender, $notify_discard, $email_subject_prefix; $this->discard_email_address = $notify_discard; $this->email_sender = $sender; $this->email_subject_prefix = $email_subject_prefix; } private function update_fields() { $get = prepare('select * from `product` where `id`=?'); bind($get, 'i', $this->id); execute($get); $product = result_single($get); $this->brand = $product['brand']; $this->name = $product['name']; $this->invoice = $product['invoice']; $this->serial = $product['serial']; $this->createtime = $product['createtime']; $this->discardtime = $product['discardtime']; return true; } private function update_info() { $get = prepare('select * from `product_info` where `product`=? order by `field`'); bind($get, 'i', $this->id); execute($get); foreach(result_list($get) as $row) { $field = $row['field']; $data = $row['data']; $this->info[$field] = $data; } return true; } private function update_tags() { $get = prepare('select * from `product_tag` where `product`=? order by `tag`'); bind($get, 'i', $this->id); execute($get); $newtags = array(); foreach(result_list($get) as $row) { $newtags[] = $row['tag']; } $this->tags = $newtags; return true; } /* Return a list of field-value mappings containing all matching search terms. */ public function matches($terms, $ldap) { $matches = array(); // Create a list mapping all basic fields to getters $fields = array('brand' => 'get_brand', 'name' => 'get_name', 'invoice' => 'get_invoice', 'serial' => 'get_serial', 'status' => 'get_status'); foreach($terms as $term) { $key = $term->get_key(); $matched = false; switch($key) { case 'brand': case 'name': case 'invoice': case 'serial': case 'status': // If $key is a standard field, check against its value $getter = $fields[$key]; $value = $this->$getter(); if(match_term($term, $value)) { //Record a successful match $matches[$key] = $value; $matched = true; } break; case 'tag': // If $key is tag, iterate over the tags $matched_tags = $this->match_tags($term); if($matched_tags) { // Record a successful match $matched = true; if(!isset($matches['tags'])) { // This is the first list of matching tags $matches['tags'] = $matched_tags; } else { // Merge these results with existing results $matches['tags'] = array_unique( array_merge($matches['tags'], $matched_tags)); } } break; case 'fritext': // if $key is fritext: // First check basic fields foreach($fields as $field => $getter) { $value = $this->$getter(); if(match_term($term, $value)) { $matches[$field] = $value; $matched = true; } } // Then tags $matched_tags = $this->match_tags($term); if($matched_tags) { $matched = true; if(!isset($matches['tags'])) { $matches['tags'] = $matched_tags; } else { $matches['tags'] = array_unique( array_merge($matches['tags'], $matched_tags)); } } // Then custom fields foreach($this->get_info() as $field => $value) { if(match_term($term, $value)) { //Record a successful match $matches[$field] = $value; $matched = true; } } break; default: // Handle custom fields $info = $this->get_info(); if(isset($info[$key])) { // If $key is a valid custom field on this product $value = $info[$key]; if(match_term($term, $value)) { //Record a successful match $matches[$key] = $value; $matched = true; } } break; } // If a mandatory match failed, the entire search has failed // and we return an empty result. if($term->is_mandatory() && !$matched) { return array(); } // If a negative match succeeded, the entire search has failed // and we return an empty result. if($term->is_negative() && $matched) { return array(); } } return $matches; } private function match_tags($term) { $tags = $this->get_tags(); $matches = array(); foreach($tags as $tag) { if(match_term($term, $tag)) { $matches[] = $tag; } } return $matches; } public function get_label($name) { switch($name) { case 'brand': return 'Tillverkare'; break; case 'name': return 'Namn'; break; case 'invoice': return 'Fakturanummer'; break; case 'serial': return 'Serienummer'; break; case 'tags': return 'Taggar'; break; default: return ucfirst($name); break; } } public function get_id() { return $this->id; } public function get_createtime() { return $this->createtime; } public function get_discardtime() { return $this->discardtime; } public function discard() { if($this->get_status() != 'available') { return false; } $now = time(); $update = prepare('update `product` set `discardtime`=? where `id`=?'); bind($update, 'ii', $now, $this->id); execute($update); $this->discardtime = $now; if($this->discard_email_address) { $this->send_discard_email(); } return true; } private function send_discard_email() { $product_data = array('Märke' => $this->get_brand(), 'Namn' => $this->get_name(), 'Serienummer' => $this->get_serial(), 'Fakturanummer' => $this->get_invoice(), ); $createtime = format_date($this->get_createtime()); $discardtime = format_date($this->get_discardtime()); $subject = $this->email_subject_prefix; $subject .= $this->get_brand().' '.$this->get_name().' skrotad'; $message = << $value) { $message .= "\n$key: $value"; } foreach($this->get_info() as $key => $value) { $uckey = ucfirst($key); $message .= "\n$uckey: $value"; } $message .= "\nTaggar: ".join(', ', $this->get_tags()); $message .= "\n\nHistorik:"; $message .= "\nSkrotad $discardtime"; foreach($this->get_history() as $item) { $starttime = format_date($item->get_starttime()); $endtime = format_date($item->get_returntime()); $event = "Service"; if($item instanceof Loan) { $user = $item->get_user(); $event = "Utlånad till ".$user->get_name(); } $message .= "\n$event $starttime - $endtime"; } $message .= "\nRegistrerad $createtime"; try { mb_send_mail($this->discard_email_address, $subject, $message, 'From: '.$this->email_sender); } catch(Exception $e) { error_log($e->getMessage()); mb_send_mail($this->error, "Kunde inte skicka mail", "Mail kunde inte skickas till " . $this->discard_email_address); } } public function toggle_service() { $status = $this->get_status(); $now = time(); $update = ''; if($status == 'service') { return $this->get_active_service()->end(); } else if($status == 'available') { Service::create_service($this); return true; } $id = $this->get_id(); throw new Exception("The state ($status) of this product (id $id) " ."does not allow servicing."); } public function get_active_service() { $find = prepare("select `id` from `event` where `type`='service' and `returntime` is null and product=?"); bind($find, 'i', $this->id); execute($find); $result = result_single($find); if($result === null) { return null; } return new Service($result['id']); } public function get_brand() { return $this->brand; } public function set_brand($newbrand) { $update = prepare('update `product` set `brand`=? where `id`=?'); bind($update, 'si', $newbrand, $this->id); execute($update); $this->brand = $newbrand; return true; } public function get_name() { return $this->name; } public function set_name($newname) { $update = prepare('update `product` set `name`=? where `id`=?'); bind($update, 'si', $newname, $this->id); execute($update); $this->name = $newname; return true; } public function get_invoice() { return $this->invoice; } public function set_invoice($newinvoice) { $update = prepare('update `product` set `invoice`=? where `id`=?'); bind($update, 'si', $newinvoice, $this->id); execute($update); $this->invoice = $newinvoice; return true; } public function get_serial() { return $this->serial; } public function set_serial($newserial) { $update = prepare('update `product` set `serial`=? where `id`=?'); bind($update, 'si', $newserial, $this->id); execute($update); $this->serial = $newserial; return true; } public function get_info() { return $this->info; } public function set_info($field, $value) { if(!$value) { return true; } $find = prepare('select * from `product_info` where `product`=? and `field`=?'); bind($find, 'is', $this->id, $field); execute($find); if(result_single($find) === null) { $update = prepare('insert into `product_info`(`data`, `product`, `field`) values (?, ?, ?)'); } else { $update = prepare('update `product_info` set `data`=? where `product`=? and `field`=?'); } bind($update, 'sis', $value, $this->id, $field); execute($update); $this->update_info(); return true; } public function remove_info($field) { $find = prepare('select * from `product_info` where `product`=? and `field`=?'); bind($find, 'is', $this->id, $field); execute($find); if(result_single($find) === null) { return true; } $update = prepare('delete from `product_info` where `field`=? and `product`=?'); bind($update, 'si', $field, $this->id); execute($update); $this->update_info(); return true; } public function get_tags() { return $this->tags; } public function add_tag($tag) { if(!$tag) { return true; } $find = prepare('select * from `product_tag` where `product`=? and `tag`=?'); bind($find, 'is', $this->id, $tag); execute($find); if(result_single($find) === null) { $update = prepare('insert into `product_tag`(`tag`, `product`) values (?, ?)'); bind($update, 'si', $tag, $this->id); execute($update); $this->update_tags(); } return true; } public function remove_tag($tag) { $find = prepare('select * from `product_tag` where `product`=? and `tag`=?'); bind($find, 'is', $this->id, $tag); execute($find); if(result_single($find) === null) { return true; } $update = prepare('delete from `product_tag` where `tag`=? and `product`=?'); bind($update, 'si', $tag, $this->id); execute($update); $this->update_tags(); return true; } public function get_status() { if($this->get_discardtime()) { return 'discarded'; } if($this->get_active_service()) { return 'service'; } $loan = $this->get_active_loan(); if(!$loan) { return 'available'; } if($loan->is_overdue()) { return 'overdue'; } return 'on_loan'; } public function get_historic_event($time) { $search = prepare("select `id`,`type` from `event` where `product` = ? and `starttime` < ? and ( `returntime` > ? or `returntime` is null )"); bind($search, 'iii', $this->id, $time, $time); execute($search); $result = result_single($search); if(!$result) { return null; } $id = $result['id']; $type = $result['type']; switch($type) { case 'service': return new Service($id); break; case 'loan': return new Loan($id); break; default: throw new Exception("Invalid type '$type'"); } } public function get_active_loan() { $find = prepare("select `id` from `event` where `type`='loan' and `returntime` is null and product=?"); bind($find, 'i', $this->id); execute($find); $result = result_single($find); if($result === null) { return null; } return new Loan($result['id']); } public function get_history() { $out = array(); $find = prepare('select `id`,`type` from `event` ' .'where `product`=? order by `starttime` desc'); bind($find, 'i', $this->id); execute($find); $items = result_list($find); foreach($items as $item) { $id = $item['id']; switch($item['type']) { case 'service': $out[] = new Service($id); break; case 'loan': $out[] = new Loan($id); break; default: $type = $item['type']; throw new Exception("Invalid type '$type'"); } } return $out; } public function get_attachments() { $out = array(); $find = prepare('select `id` from `attachment` where `product`=? and `deletetime` is NULL order by `uploadtime` asc'); bind($find, 'i', $this->id); execute($find); $items = result_list($find); foreach($items as $item) { $out[] = new Attachment($item['id']); } return $out; } } ?>