protected function beforeSave() { //set the created date to allow auto deleting //http://docs.mongodb.org/manual/tutorial/expire-data/ $this->createdAt = new \MongoDate(); parent::beforeSave(); }
protected function fetchConditions() { parent::fetchConditions(); $filter_keyword = $this->getState('filter.keyword'); if ($filter_keyword && is_string($filter_keyword)) { $key = new \MongoRegex('/' . $filter_keyword . '/i'); $where = array(); $regex = '/^[0-9a-z]{24}$/'; if (preg_match($regex, (string) $filter_keyword)) { $where[] = array('_id' => new \MongoId((string) $filter_keyword)); } $where[] = array('title' => $key); $where[] = array('type' => $key); $this->setCondition('$or', $where); } $filter_priority = $this->getState('filter.priority'); if (strlen($filter_priority)) { $this->setCondition('priority', $filter_priority); } $filter_type = $this->getState('filter.type'); if (strlen($filter_type)) { $this->setCondition('type', $filter_type); } return $this; }
public function validate() { if (empty($this->title)) { $this->setError('Title is required'); } return parent::validate(); }
protected function fetchConditions() { parent::fetchConditions(); $filter_user = $this->getState('filter.user'); if (strlen($filter_user)) { if (static::isValidId($filter_user)) { $this->setCondition('user_id', new \MongoId((string) $filter_user)); } } $filter_site = $this->getState('filter.site'); if (strlen($filter_site)) { $this->setCondition('site_id', $filter_site); } $filter_session = $this->getState('filter.session'); if (strlen($filter_session)) { $this->setCondition('session_id', $filter_session); } $filter_active_after = $this->getState('filter.active_after'); if (strlen($filter_active_after)) { $this->setCondition('$and', array('timestamp' => array('$gt' => $filter_active_after)), 'append'); } $filter_active_before = $this->getState('filter.active_before'); if (strlen($filter_active_before)) { $this->setCondition('$and', array('timestamp' => array('$lt' => $filter_active_before)), 'append'); } $filter_is_user = $this->getState('filter.is_user'); if (is_bool($filter_is_user) && !empty($filter_is_user)) { $this->setCondition('user_id', array('$exists' => true, '$nin' => array('', null))); } else { if (is_bool($filter_is_user) && empty($filter_is_user)) { $this->setCondition('user_id', array('$in' => array('', null))); } } return $this; }
protected function beforeValidate() { if (empty($this->slug)) { $this->slug = \Web::instance()->slug($this->namespace); } $this->enabled = (bool) $this->enabled; return parent::beforeValidate(); }
protected function beforeSave() { if (empty($this->created)) { $this->created = \Dsc\Mongo\Metastamp::getDate('now'); } if (empty($this->{'created.microtime'})) { $this->set('created.microtime', microtime(true)); } return parent::beforeSave(); }
/** * */ protected function beforeValidate() { if (empty($this->type)) { $this->type = $this->__type; } if (!$this->get('metadata.created')) { $this->set('metadata.created', \Dsc\Mongo\Metastamp::getDate('now')); } $this->set('metadata.last_modified', \Dsc\Mongo\Metastamp::getDate('now')); return parent::beforeValidate(); }
protected function fetchConditions() { parent::fetchConditions(); $filter_keyword = $this->getState('filter.keyword'); if ($filter_keyword && is_string($filter_keyword)) { $key = new \MongoRegex('/' . $filter_keyword . '/i'); $where = array(); $regex = '/^[0-9a-z]{24}$/'; if (preg_match($regex, (string) $filter_keyword)) { $where[] = array('_id' => new \MongoId((string) $filter_keyword)); $where[] = array('resource_id' => new \MongoId((string) $filter_keyword)); $where[] = array('actor_id' => new \MongoId((string) $filter_keyword)); } $where[] = array('message' => $key); $where[] = array('priority' => $key); $where[] = array('category' => $key); $where[] = array('resource_type' => $key); $where[] = array('action' => $key); $where[] = array('diff' => $key); $where[] = array('actor_type' => $key); $where[] = array('actor_name' => $key); $this->setCondition('$or', $where); } $filter_resource_type = $this->getState('filter.resource_type'); if (strlen($filter_resource_type)) { $this->setCondition('resource_type', $filter_resource_type); } $filter_resource_id = $this->getState('filter.resource_id'); if (strlen($filter_resource_id)) { $this->setCondition('resource_id', $filter_resource_id); } $filter_action = $this->getState('filter.action'); if (strlen($filter_action)) { $this->setCondition('action', $filter_action); } $filter_actor_type = $this->getState('filter.actor_type'); if (strlen($filter_actor_type)) { $this->setCondition('actor_type', $filter_actor_type); } $filter_actor_id = $this->getState('filter.actor_id'); if (strlen($filter_actor_id)) { $this->setCondition('actor_id', $filter_actor_id); } return $this; }
protected function fetchConditions() { parent::fetchConditions(); $filter_keyword = $this->getState('filter.keyword'); if ($filter_keyword && is_string($filter_keyword)) { $key = new \MongoRegex('/' . $filter_keyword . '/i'); $where = array(); $where[] = array('name' => $key); $where[] = array('country_isocode_2' => $key); $where[] = array('code' => $key); $this->setCondition('$or', $where); } $filter_country_isocode_2 = $this->getState('filter.country.isocode_2'); if (strlen($filter_country_isocode_2)) { $this->setCondition('country_isocode_2', $filter_country_isocode_2); } $filter_code = $this->getState('filter.code'); if (strlen($filter_code)) { $this->setCondition('code', $filter_code); } return $this; }
public function validatePayment() { $cart = $this->model->cart(); $checkout = $this->model->checkout(); $paymentData = $this->model->paymentData(); $user = $this->auth->getIdentity(); $order = $this->model->order(); $gateway = $this->gateway(); /* * Success response looks like: * Array ( [utf8] => [req_bill_to_address_country] => US [auth_avs_code] => X [req_bill_to_phone] => 800-123-4567 [req_card_number] => xxxxxxxxxxxx1111 [req_card_expiry_date] => 01-2017 [decision] => ACCEPT [req_bill_to_address_state] => NY [signed_field_names] => transaction_id,decision,req_access_key,req_profile_id,req_transaction_uuid,req_transaction_type,req_reference_number,req_amount,req_currency,req_locale,req_payment_method,req_bill_to_forename,req_bill_to_surname,req_bill_to_email,req_bill_to_phone,req_bill_to_address_line1,req_bill_to_address_city,req_bill_to_address_state,req_bill_to_address_country,req_bill_to_address_postal_code,req_card_number,req_card_type,req_card_expiry_date,message,reason_code,auth_avs_code,auth_avs_code_raw,auth_response,auth_amount,auth_code,auth_trans_ref_no,auth_time,payment_token,signed_field_names,signed_date_time [req_payment_method] => card [req_transaction_type] => authorization,create_payment_token [auth_code] => 888888 [signature] => Tjvr0UPJdcXp10Ouo1IoS8O5+e1C1IKHD0qIMKcGrmQ= [req_locale] => en-us [reason_code] => 100 [req_bill_to_address_postal_code] => 10033 [req_bill_to_address_line1] => 1 Main Street #6 [req_card_type] => 001 [auth_amount] => 32.63 [req_bill_to_address_city] => New York [signed_date_time] => 2014-07-31T04:46:04Z [req_currency] => USD [req_reference_number] => 53d8fa97f02e25c641d3783f [auth_avs_code_raw] => I1 [transaction_id] => 4067819643530176195662 [req_amount] => 32.63 [auth_time] => 2014-07-31T044604Z [message] => Request was processed successfully. [auth_response] => 100 [req_profile_id] => bangles [req_transaction_uuid] => 53d8fa97f02e25c641d3783f.1406781952 [payment_token] => 4067819643530176195662 [auth_trans_ref_no] => 81884333NY88NKVM [req_bill_to_surname] => Tushman [req_bill_to_forename] => Rafael [req_bill_to_email] => email@dioscouri.com [req_access_key] => 4571ed37561d32419cab3fa6ad0ff7cb [actor_id] => 53bd8b8af02e25fa0af22e6d [affiliate_id] => ) */ $response = $gateway->completeAuthorize($paymentData)->send(); if (!$response->isSuccessful()) { // OK, so lets figure out why payment was not successful switch ($response->getReasonCode()) { case "102": // One or more fields in the request contain invalid data. // Check invalid_fields, a CSV of the invalid fields. foreach ($response->getInvalidFields() as $invalid_field) { switch ($invalid_field) { case "card_number": $message = 'Invalid card number. Please confirm the information submitted and try again.'; throw new \Exception($message); break; case "card_expiry_date": $message = 'Invalid expiration date. Please confirm the information submitted and try again.'; throw new \Exception($message); break; case "card_cvn": $message = 'Invalid card security code. Please confirm the information submitted and try again.'; throw new \Exception($message); break; case "card_type": $message = 'Invalid card type. Please try again with a different card.'; throw new \Exception($message); break; case "bill_to_phone": case "customer_phone": $message = 'Invalid Billing Phone Number. Please correct and try again.'; throw new \Exception($message); break; } } case "104": // The access_key and transaction_uuid fields for this authorization request matches the access_key and transaction_uuid of another authorization request that you sent within the past 15 minutes. // The access_key and transaction_uuid fields for this authorization request matches the access_key and transaction_uuid of another authorization request that you sent within the past 15 minutes. case "207": // issuing bank unavailable // issuing bank unavailable case "236": // processor failure // processor failure case "240": // wrong card type $message = 'There was an error submitting your order. Please try again.'; throw new \Exception($message); break; case "202": // expired card $message = 'Your card has expired. Please try again with a different card.'; throw new \Exception($message); break; case "203": // general decline // general decline case "205": // lost/stolen card // lost/stolen card case "208": // inactive card // inactive card case "210": // card over limit // card over limit case "221": // customer in negative file // customer in negative file case "222": // account frozen // account frozen case "231": // account number invalid // account number invalid case "232": // card not accepted // card not accepted case "233": // general decline // general decline case "234": // error in cybersource setup // error in cybersource setup case "520": // declined by Decision Manager $message = 'Your card has been declined. Please try again with a different card.'; throw new \Exception($message); break; case "204": $message = 'Your card has been declined due to insufficient funds. Please try again with a different card.'; throw new \Exception($message); break; case "211": // invalid CVN // invalid CVN case "230": // CVN fail in cybersource $message = 'The billing information that you entered does not match your credit card information. Please confirm the Security Code you have provided.'; throw new \Exception($message); break; case "200": // AVS fail in cybersource $message = 'The billing information that you entered does not match your credit card information. Please confirm the Billing Address you have provided.'; throw new \Exception($message); break; case "201": // call bank // call bank default: break; } // check CVN response /* D The transaction was considered to be suspicious by the issuing bank. I The CVN failed the processor's data validation. M The CVN matched. N The CVN did not match. P The CVN was not processed by the processor for an unspecified reason. S The CVN is on the card but was not included in the request. U Card verification is not supported by the issuing bank. X Card verification is not supported by the card association. 1 Card verification is not supported for this processor or card type. 2 An unrecognized result code was returned by the processor for the card verification response. 3 No result code was returned by the processor. */ switch ($response->getCVNCode()) { case "D": case "I": case "N": case "S": $message = 'The billing information that you entered does not match your credit card information. Please confirm the Security Code you have provided.'; throw new \Exception($message); break; case "M": case "P": case "U": case "X": case "1": case "2": case "3": default: // null break; } // check AVS response /* A Partial match Street address matches, but five digit and nine digit postal codes do not match. B Partial match Street address matches, but postal code is not verified. C No match Street address and postal code do not match. D & M Match Street address and postal code match. E Invalid AVS data is invalid or AVS is not allowed for this card type. F Partial match Card member’s name does not match, but billing postal code matches. Returned only for the American Express card type. G Not supported. H Partial match Card member’s name does not match, but street address and postal code match. Returned only for the American Express card type. I No match Address not verified. J Match Card member’s name, billing address, and postal code match. Shipping information verified and chargeback protection guaranteed through the Fraud Protection Program. Returned only if you are signed up to use AAV+ with the American Express Phoenix processor. K Partial match Card member’s name matches, but billing address and billing postal code do not match. Returned only for the American Express card type. L Partial match Card member’s name and billing postal code match, but billing address does not match. Returned only for the American Express card type. M Match Street address and postal code match. N No match One of the following: Street address and postal code do not match. Card member’s name, street address, and postal code do not match. Returned only for the American Express card type. O Partial match Card member’s name and billing address match, but billing postal code does not match. Returned only for the American Express card type. P Partial match Postal code matches, but street address is not verified. Q Match Card member’s name, billing address, and postal code match. Shipping information verified but chargeback protection not guaranteed (Standard program). Returned only if you are registered to use AAV+ with the American Express Phoenix processor. R System unavailable System unavailable. S Not supported U.S.-issuing bank does not support AVS. T Partial match Card member’s name does not match, but street address matches. Returned only for the American Express card type. U System unavailable Address information unavailable for one of these reasons: The U.S. bank does not support non-U.S. AVS. The AVS in a U.S. bank is not functioning properly. V Match Card member’s name, billing address, and billing postal code match. Returned only for the American Express card type. W Partial match Street address does not match, but nine digit postal code matches. X Match Street address and nine digit postal code match. Y Match Street address and five digit postal code match. Z Partial match Street address does not match, but 5-digit postal code matches. 1 Not supported AVS is not supported for this processor or card type. 2 Unrecognized The processor returned an unrecognized value for the AVS response. 3 Match Address is confirmed. Returned only for PayPal Express Checkout. 4 No match Address is not confirmed. Returned only for PayPal Express Checkout. */ switch ($response->getAVSCode()) { case "C": case "E": case "I": case "N": case "4": $message = 'The billing information that you entered does not match your credit card information. Please confirm the Billing Address you have provided.'; throw new \Exception($message); break; default: // null break; } // if we reach here, throw a general error //throw new \Exception('Payment was not successful'); $message = 'Your card has been declined. Please try again with a different card.'; throw new \Exception($message); } // Check the signature if (!$response->validateSignature($gateway->getSecretKey())) { throw new \Exception('Payment data could not be verified'); } $cart_id = $response->getMerchantTransactionReference(); // Verify the cart ID if (!\Dsc\Mongo\Collection::isValidId($cart_id)) { throw new \Exception('Payment transaction has an invalid cart ID'); } $cart = (new \Shop\Models\Carts())->setState('filter.id', $cart_id)->getItem(); if (empty($cart->id)) { throw new \Exception('Payment transaction has an unrecognized cart ID'); } $checkout->addCart($cart); $order = $checkout->order(true); $data = $response->getData(); // Is any further validation required on the payment response? $order->financial_status = \Shop\Constants\OrderFinancialStatus::authorized; $order->payment_method_id = $this->identifier; //$order->payment_method_result = array(); $order->payment_method_validation_result = $data; //$order->payment_method_status = null; $order->payment_method_auth_id = !empty($data['auth_trans_ref_no']) ? $data['auth_trans_ref_no'] : null; $order->payment_method_tran_id = $response->getTransactionReference(); return $data; }
protected function afterDelete() { return parent::afterDelete(); }
protected function beforeUpdate() { return parent::beforeUpdate(); }
protected function afterUpdate() { $this->ancestorsAfterUpdate(); return parent::afterUpdate(); }
protected function fetchConditions() { parent::fetchConditions(); $filter_keyword = $this->getState('filter.keyword'); if ($filter_keyword && is_string($filter_keyword)) { $key = new \MongoRegex('/' . $filter_keyword . '/i'); $where = array(); $where[] = array('actor_name' => $key); $where[] = array('action' => $key); // get an array of actor_ids based on this keyword search, then add them as an OR $conditions = (new \Activity\Models\Actors())->setState('filter.keyword', $filter_keyword)->conditions(); if ($actor_ids = \Activity\Models\Actors::collection()->distinct("_id", $conditions)) { $where[] = array('actor_id' => array('$in' => $actor_ids)); } $this->setCondition('$or', $where); } $filter_action = $this->getState('filter.action'); if (strlen($filter_action)) { $this->setCondition('action', $filter_action); } $filter_excluded_actors = $this->getState('filter.excluded_actors'); if (strlen($filter_excluded_actors)) { // get an array of actor_ids, then add them as a filter $conditions = (new \Activity\Models\Actors())->setState('filter.excluded', true)->conditions(); $actor_ids = \Activity\Models\Actors::collection()->distinct("_id", $conditions); if ($filter_excluded_actors == 'included_actors') { $this->setCondition('$and', array('actor_id' => array('$nin' => $actor_ids)), 'append'); } elseif ($filter_excluded_actors == 'excluded_actors') { $this->setCondition('$and', array('actor_id' => array('$in' => $actor_ids)), 'append'); } } $filter_bots = $this->getState('filter.bots'); if (strlen($filter_bots)) { // get an array of actor_ids, then add them as a filter $conditions = (new \Activity\Models\Actors())->setState('filter.bot', true)->conditions(); $actor_ids = \Activity\Models\Actors::collection()->distinct("_id", $conditions); if ($filter_bots == 'exclude_bots') { $this->setCondition('$and', array('actor_id' => array('$nin' => $actor_ids)), 'append'); } elseif ($filter_bots == 'only_bots') { $this->setCondition('$and', array('actor_id' => array('$in' => $actor_ids)), 'append'); } } $filter_created_after = $this->getState('filter.created_after'); if (strlen($filter_created_after)) { $filter_created_after = strtotime($filter_created_after); // add $and conditions to the query stack if (!($and = $this->getCondition('$and'))) { $and = array(); } $and[] = array('$or' => array(array('created' => 0), array('created' => array('$gte' => $filter_created_after)))); $this->setCondition('$and', $and); } $filter_created_before = $this->getState('filter.created_before'); if (strlen($filter_created_before)) { $filter_created_before = strtotime($filter_created_before); // add $and conditions to the query stack if (!($and = $this->getCondition('$and'))) { $and = array(); } $and[] = array('$or' => array(array('created' => 0), array('created' => array('$lte' => $filter_created_before)))); $this->setCondition('$and', $and); } return $this; }
/** * Instantiate class, optionally binding it with an array/object * * @param unknown $source * @param unknown $options */ public function __construct($source = array(), $options = array()) { parent::__construct($source, $options); $this->__select2_fields['id'] = 'code'; }
/** * */ protected function afterSave() { $this->actionCount(); return parent::afterSave(); }
protected function beforeValidate() { $identity = \Dsc\System::instance()->get('auth')->getIdentity(); if (!$this->get('metadata.creator')) { if (!empty($identity->id)) { $this->set('metadata.creator', array('id' => $identity->id, 'name' => $identity->fullName())); } else { $this->set('metadata.creator', array('id' => new \MongoId(), 'name' => 'Unicorn Egg Eater')); } } if (!$this->get('metadata.created')) { $this->set('metadata.created', \Dsc\Mongo\Metastamp::getDate('now')); } $this->set('metadata.last_modified', \Dsc\Mongo\Metastamp::getDate('now')); if (!empty($identity->id)) { $this->set('metadata.last_modified_by', array('id' => $identity->id, 'name' => $identity->fullName())); } else { $this->set('metadata.last_modified_by', array('id' => new \MongoId(), 'name' => 'Unicorn Egg Eater')); } if (empty($this->type)) { $this->type = $this->type(); } return parent::beforeValidate(); }
public function validatePayment() { $cart = $this->model->cart(); $checkout = $this->model->checkout(); $paymentData = $this->model->paymentData(); $user = $this->auth->getIdentity(); /* * Response looks like: * Array ( [encResp] => 8fdcf29e90be82c0d34d099a2a5642ad7a45baaa68386123c356622d24990ded32b4c7bab79468c9e89c32b912396b1078ea76adba7bdd4f1c3adebf9d916957838f58252e4e94cbb77dfd037d2a14d84d19ff01fd4b48beb103106ec3f1e0b1b33056a1bdeb5f2720e4e4cdfd70c9bc0024bc8539fd7e0fd2d32ac1a29acfc0ad9b2dfca64844d7fd55a64a3f6cf2615dd6c7d6dc5475e97d3ab230b224fa1907550fbf108c0c4255e29c6d502ede544e8a642e4aead61105f45ff98c87401202e8fd7bbc3831dc0bcdd53610ff15625bbdf7e711b5069c5b79d9bc61dd561eaff2a493732e399422811fd080f8eafd3e11a5d4433d22b68f245b22f58df34b9f3043a5e569a2f9bf42a9ce093c85e313e49d3cb77cd7502b5a0288c8921feb40b800ef05e5d89c048d660eaf7ec719a8d108b6d65868d115f7b37c0908b8ff269159535b875f80dc8c320fb281fd5a439bdaa1227fbd052e14398e2913fc4d1c0264fc9ab94cf1aa10dd2a5bacdfcf541a2ca2f2bd462b5fd3a7d481fb70be38937ef745c8c44ff7def72c144a9082beb2b690f54a441ca48e0c4886854839a5d12d489a9fd576b90565841c8343e48dca01b5d9d9b2419a866fc20c95cdca47e4452a82eb07b161c9227eb93bdb85afd39b5b01aabc53d70891ffbc0ff1ce703fb7c00557effd910e1ca86056d23013608b7f4457b7cb36cd384ff8b1fc8403748d38197230bff0476cb1ab3d0b44b8209b5b32536249b08bfdf33ccee94f006742a415f96929663ffdd6a8de37d9c3853b6fbbb2702ccf7e3dd0d503ac1162dc3596856d7b52ae1e3d297d5c4d3fac5bb4feb2d328ef3f6328062cebb1db9e7f05243edeabdb19b79f352169e8eef7033a3cab6391ab767768b49d2b77b97f784742cd57c8bf0147d7f327dabbfbc246a5e120ef6bce186716cade37b754cc4197fe34dda0ebd5110ec2ac007118bd9710357838e8544bfb5193e99a36d1 [payment_method] => ccavenue ) * * Decrypted data array looks like this * Array ( [order_id] => 5410bed2f2f66f884f10a640 [tracking_id] => 103000862840 [bank_ref_no] => null [order_status] => Failure [failure_message] => [payment_mode] => Credit Card [card_name] => Amex [status_code] => 2 [status_message] => E5431-09171621: Invalid Field : CardSecurityCode [currency] => INR [amount] => 3010.0 [billing_name] => Rafael Tushman [billing_address] => 850 West 176th Street #6C [billing_city] => New York [billing_state] => New York [billing_zip] => 10033 [billing_country] => United States [billing_tel] => 7186441019 [billing_email] => email@email.com [delivery_name] => [delivery_address] => [delivery_city] => [delivery_state] => [delivery_zip] => [delivery_country] => [delivery_tel] => [merchant_param1] => [merchant_param2] => [merchant_param3] => [merchant_param4] => [merchant_param5] => [vault] => N ) */ $merchant_id = $this->model->{'settings.merchant_id'}; $working_key = $this->model->{'settings.encryption_key'}; $access_code = $this->model->{'settings.access_code'}; $encoded_response = isset($paymentData["encResp"]) ? $paymentData["encResp"] : null; if (empty($encoded_response)) { $message = "Invalid response data from CCAvenue."; throw new \Exception($message); } $decrypted_string = \Shop\PaymentMethods\CCAvenue\Lib\Encrypt::decrypt($encoded_response, $working_key); $decrypted_values = explode('&', $decrypted_string); $payment_details = array(); foreach ($decrypted_values as $value) { $information = explode('=', $value); $key = $information[0]; $value = isset($information[1]) ? $information[1] : null; $payment_details[$key] = $value; } $cart_id = isset($payment_details['order_id']) ? $payment_details['order_id'] : null; // Verify the cart ID if (empty($cart_id) || !\Dsc\Mongo\Collection::isValidId($cart_id)) { throw new \Exception('Payment transaction has an invalid cart ID'); } $cart = (new \Shop\Models\Carts())->setState('filter.id', $cart_id)->getItem(); if (empty($cart->id)) { throw new \Exception('Payment transaction has an unrecognized cart ID'); } $checkout->addCart($cart); $order = $checkout->order(true); $order->payment_method_validation_result = $payment_details; if (empty($payment_details['order_status'])) { throw new \Exception('Missing order status from CCAvenue'); } switch ($payment_details['order_status']) { case "Aborted": case "Failure": // Handle failures and try to give the user a useful message if (!empty($payment_details['status_message'])) { throw new \Exception($payment_details['status_message']); } elseif (!empty($payment_details['failure_message'])) { throw new \Exception($payment_details['failure_message']); } throw new \Exception('Your payment was not accepted by CCAvenue'); break; case "Success": $order->financial_status = \Shop\Constants\OrderFinancialStatus::paid; $order->payment_method_id = $this->identifier; $order->payment_method_validation_result = $payment_details; $order->payment_method_tran_id = !empty($payment_details['tracking_id']) ? $payment_details['tracking_id'] : null; break; default: throw new \Exception('Invalid order status from CCAvenue'); break; } return $payment_details; }
protected function afterSave() { parent::afterSave(); $this->compressOrdering(); }