@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Refactor Calendar Search, and implement Projects on events

Summary: Ref T7950, Refactor Calendar Search, and implement Projects on events

Test Plan: Verify that all queries in Calendar search still work, and that events can now have associated Projects that you can search by in Calendar Search.

Reviewers: epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: epriestley, Korvin

Maniphest Tasks: T7950

Differential Revision: https://secure.phabricator.com/D13393

+266 -201
+3
src/__phutil_library_map__.php
··· 2549 2549 'PhabricatorSearchDAO' => 'applications/search/storage/PhabricatorSearchDAO.php', 2550 2550 'PhabricatorSearchDatasource' => 'applications/search/typeahead/PhabricatorSearchDatasource.php', 2551 2551 'PhabricatorSearchDatasourceField' => 'applications/search/field/PhabricatorSearchDatasourceField.php', 2552 + 'PhabricatorSearchDateControlField' => 'applications/search/field/PhabricatorSearchDateControlField.php', 2552 2553 'PhabricatorSearchDateField' => 'applications/search/field/PhabricatorSearchDateField.php', 2553 2554 'PhabricatorSearchDeleteController' => 'applications/search/controller/PhabricatorSearchDeleteController.php', 2554 2555 'PhabricatorSearchDocument' => 'applications/search/storage/document/PhabricatorSearchDocument.php', ··· 5086 5087 'PhabricatorCalendarEvent' => array( 5087 5088 'PhabricatorCalendarDAO', 5088 5089 'PhabricatorPolicyInterface', 5090 + 'PhabricatorProjectInterface', 5089 5091 'PhabricatorMarkupInterface', 5090 5092 'PhabricatorApplicationTransactionInterface', 5091 5093 'PhabricatorSubscribableInterface', ··· 6286 6288 'PhabricatorSearchDAO' => 'PhabricatorLiskDAO', 6287 6289 'PhabricatorSearchDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 6288 6290 'PhabricatorSearchDatasourceField' => 'PhabricatorSearchTokenizerField', 6291 + 'PhabricatorSearchDateControlField' => 'PhabricatorSearchField', 6289 6292 'PhabricatorSearchDateField' => 'PhabricatorSearchField', 6290 6293 'PhabricatorSearchDeleteController' => 'PhabricatorSearchBaseController', 6291 6294 'PhabricatorSearchDocument' => 'PhabricatorSearchDAO',
+24
src/applications/calendar/controller/PhabricatorCalendarEventEditController.php
··· 140 140 $cancel_uri = '/'.$event->getMonogram(); 141 141 } 142 142 143 + if ($this->isCreate()) { 144 + $projects = array(); 145 + } else { 146 + $projects = PhabricatorEdgeQuery::loadDestinationPHIDs( 147 + $event->getPHID(), 148 + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); 149 + $projects = array_reverse($projects); 150 + } 151 + 143 152 $name = $event->getName(); 144 153 $description = $event->getDescription(); 145 154 $is_all_day = $event->getIsAllDay(); ··· 167 176 $request, 168 177 'recurrenceEndDate'); 169 178 $recurrence_end_date_value->setOptional(true); 179 + $projects = $request->getArr('projects'); 170 180 $description = $request->getStr('description'); 171 181 $subscribers = $request->getArr('subscribers'); 172 182 $edit_policy = $request->getStr('editPolicy'); ··· 262 272 ->setContinueOnNoEffect(true); 263 273 264 274 try { 275 + $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; 276 + $xactions[] = id(new PhabricatorCalendarEventTransaction()) 277 + ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 278 + ->setMetadataValue('edge:type', $proj_edge_type) 279 + ->setNewValue(array('=' => array_fuse($projects))); 280 + 265 281 $xactions = $editor->applyTransactions($event, $xactions); 266 282 $response = id(new AphrontRedirectResponse()); 267 283 switch ($next_workflow) { ··· 437 453 ->setValue($end_disabled); 438 454 } 439 455 456 + $projects = id(new AphrontFormTokenizerControl()) 457 + ->setLabel(pht('Projects')) 458 + ->setName('projects') 459 + ->setValue($projects) 460 + ->setUser($viewer) 461 + ->setDatasource(new PhabricatorProjectDatasource()); 462 + 440 463 $description = id(new PhabricatorRemarkupControl()) 441 464 ->setLabel(pht('Description')) 442 465 ->setName('description') ··· 511 534 ->appendControl($edit_policies) 512 535 ->appendControl($subscribers) 513 536 ->appendControl($invitees) 537 + ->appendChild($projects) 514 538 ->appendChild($description) 515 539 ->appendChild($icon); 516 540
+4
src/applications/calendar/query/PhabricatorCalendarEventQuery.php
··· 15 15 16 16 private $generateGhosts = false; 17 17 18 + public function newResultObject() { 19 + return new PhabricatorCalendarEvent(); 20 + } 21 + 18 22 public function setGenerateGhosts($generate_ghosts) { 19 23 $this->generateGhosts = $generate_ghosts; 20 24 return $this;
+164 -188
src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
··· 15 15 return 'PhabricatorCalendarApplication'; 16 16 } 17 17 18 - public function buildSavedQueryFromRequest(AphrontRequest $request) { 19 - $saved = new PhabricatorSavedQuery(); 18 + public function newQuery() { 19 + return new PhabricatorCalendarEventQuery(); 20 + } 20 21 21 - $saved->setParameter( 22 - 'rangeStart', 23 - $this->readDateFromRequest($request, 'rangeStart')); 22 + protected function shouldShowOrderField() { 23 + return false; 24 + } 24 25 25 - $saved->setParameter( 26 - 'rangeEnd', 27 - $this->readDateFromRequest($request, 'rangeEnd')); 26 + protected function buildCustomSearchFields() { 27 + return array( 28 + id(new PhabricatorSearchDatasourceField()) 29 + ->setLabel(pht('Created By')) 30 + ->setKey('creatorPHIDs') 31 + ->setDatasource(new PhabricatorPeopleUserFunctionDatasource()), 32 + id(new PhabricatorSearchDatasourceField()) 33 + ->setLabel(pht('Invited')) 34 + ->setKey('invitedPHIDs') 35 + ->setDatasource(new PhabricatorPeopleUserFunctionDatasource()), 36 + id(new PhabricatorSearchDateControlField()) 37 + ->setLabel(pht('Occurs After')) 38 + ->setKey('rangeStart'), 39 + id(new PhabricatorSearchDateControlField()) 40 + ->setLabel(pht('Occurs Before')) 41 + ->setKey('rangeEnd') 42 + ->setAliases(array('rangeEnd')), 43 + id(new PhabricatorSearchCheckboxesField()) 44 + ->setKey('upcoming') 45 + ->setOptions(array( 46 + 'upcoming' => pht('Show only upcoming events.'), 47 + )), 48 + id(new PhabricatorSearchSelectField()) 49 + ->setLabel(pht('Cancelled Events')) 50 + ->setKey('isCancelled') 51 + ->setOptions($this->getCancelledOptions()) 52 + ->setDefault('active'), 53 + id(new PhabricatorSearchSelectField()) 54 + ->setLabel(pht('Display Options')) 55 + ->setKey('display') 56 + ->setOptions($this->getViewOptions()) 57 + ->setDefault('month'), 58 + ); 59 + } 28 60 29 - $saved->setParameter( 30 - 'upcoming', 31 - $this->readBoolFromRequest($request, 'upcoming')); 61 + private function getCancelledOptions() { 62 + return array( 63 + 'active' => pht('Active Events Only'), 64 + 'cancelled' => pht('Cancelled Events Only'), 65 + 'both' => pht('Both Cancelled and Active Events'), 66 + ); 67 + } 32 68 33 - $saved->setParameter( 34 - 'invitedPHIDs', 35 - $this->readUsersFromRequest($request, 'invited')); 69 + private function getViewOptions() { 70 + return array( 71 + 'month' => pht('Month View'), 72 + 'day' => pht('Day View'), 73 + 'list' => pht('List View'), 74 + ); 75 + } 36 76 37 - $saved->setParameter( 38 - 'creatorPHIDs', 39 - $this->readUsersFromRequest($request, 'creators')); 77 + protected function buildQueryFromParameters(array $map) { 78 + $query = $this->newQuery(); 79 + $viewer = $this->requireViewer(); 40 80 41 - $saved->setParameter( 42 - 'isCancelled', 43 - $request->getStr('isCancelled')); 81 + if ($map['creatorPHIDs']) { 82 + $query->withCreatorPHIDs($map['creatorPHIDs']); 83 + } 44 84 45 - $saved->setParameter( 46 - 'display', 47 - $request->getStr('display')); 85 + if ($map['invitedPHIDs']) { 86 + $query->withInvitedPHIDs($map['invitedPHIDs']); 87 + } 48 88 49 - return $saved; 89 + $range_start = $map['rangeStart']; 90 + $range_end = $map['rangeEnd']; 91 + $display = $map['display']; 92 + 93 + if ($map['upcoming'] && $map['upcoming'][0] == 'upcoming') { 94 + $upcoming = true; 95 + } else { 96 + $upcoming = false; 97 + } 98 + 99 + list($range_start, $range_end) = $this->getQueryDateRange( 100 + $range_start, 101 + $range_end, 102 + $display, 103 + $upcoming); 104 + 105 + $query->withDateRange($range_start, $range_end); 106 + 107 + switch ($map['isCancelled']) { 108 + case 'active': 109 + $query->withIsCancelled(false); 110 + break; 111 + case 'cancelled': 112 + $query->withIsCancelled(true); 113 + break; 114 + } 115 + 116 + return $query->setGenerateGhosts(true); 50 117 } 51 118 52 - public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { 53 - $query = id(new PhabricatorCalendarEventQuery()) 54 - ->setGenerateGhosts(true); 119 + private function getQueryDateRange( 120 + $start_date_wild, 121 + $end_date_wild, 122 + $display, 123 + $upcoming) { 124 + 125 + $start_date_value = $this->getSafeDate($start_date_wild); 126 + $end_date_value = $this->getSafeDate($end_date_wild); 127 + 55 128 $viewer = $this->requireViewer(); 56 129 $timezone = new DateTimeZone($viewer->getTimezoneIdentifier()); 57 - 58 - $min_range = $this->getDateFrom($saved)->getEpoch(); 59 - $max_range = $this->getDateTo($saved)->getEpoch(); 130 + $min_range = null; 131 + $max_range = null; 60 132 61 - $user_datasource = id(new PhabricatorPeopleUserFunctionDatasource()) 62 - ->setViewer($viewer); 133 + $min_range = $start_date_value->getEpoch(); 134 + $max_range = $end_date_value->getEpoch(); 63 135 64 - if ($this->isMonthView($saved) || 65 - $this->isDayView($saved)) { 136 + if ($display == 'month' || $display == 'day') { 66 137 list($start_year, $start_month, $start_day) = 67 - $this->getDisplayYearAndMonthAndDay($saved); 138 + $this->getDisplayYearAndMonthAndDay($min_range, $max_range, $display); 68 139 69 140 $start_day = new DateTime( 70 141 "{$start_year}-{$start_month}-{$start_day}", 71 142 $timezone); 72 143 $next = clone $start_day; 73 144 74 - if ($this->isMonthView($saved)) { 145 + if ($display == 'month') { 75 146 $next->modify('+1 month'); 76 - } else if ($this->isDayView($saved)) { 77 - $next->modify('+6 day'); 147 + } else if ($display == 'day') { 148 + $next->modify('+7 day'); 78 149 } 79 150 80 151 $display_start = $start_day->format('U'); ··· 92 163 if (!$min_range || ($min_range < $display_start)) { 93 164 $min_range = $display_start; 94 165 95 - if ($this->isMonthView($saved) && 166 + if ($display == 'month' && 96 167 $first_of_month !== $start_of_week) { 97 168 $interim_day_num = ($first_of_month + 7 - $start_of_week) % 7; 98 169 $min_range = id(clone $start_day) ··· 103 174 if (!$max_range || ($max_range > $display_end)) { 104 175 $max_range = $display_end; 105 176 106 - if ($this->isMonthView($saved) && 177 + if ($display == 'month' && 107 178 $last_of_month !== $end_of_week) { 108 179 $interim_day_num = ($end_of_week + 7 - $last_of_month) % 7; 109 180 $max_range = id(clone $next) 110 181 ->modify('+'.$interim_day_num.' days') 111 182 ->format('U'); 112 183 } 113 - 114 184 } 115 185 } 116 186 117 - if ($saved->getParameter('upcoming')) { 187 + if ($upcoming) { 118 188 if ($min_range) { 119 189 $min_range = max(time(), $min_range); 120 190 } else { ··· 122 192 } 123 193 } 124 194 125 - if ($min_range || $max_range) { 126 - $query->withDateRange($min_range, $max_range); 127 - } 128 - 129 - $invited_phids = $saved->getParameter('invitedPHIDs', array()); 130 - $invited_phids = $user_datasource->evaluateTokens($invited_phids); 131 - if ($invited_phids) { 132 - $query->withInvitedPHIDs($invited_phids); 133 - } 134 - 135 - $creator_phids = $saved->getParameter('creatorPHIDs', array()); 136 - $creator_phids = $user_datasource->evaluateTokens($creator_phids); 137 - if ($creator_phids) { 138 - $query->withCreatorPHIDs($creator_phids); 139 - } 140 - 141 - $is_cancelled = $saved->getParameter('isCancelled', 'active'); 142 - 143 - switch ($is_cancelled) { 144 - case 'active': 145 - $query->withIsCancelled(false); 146 - break; 147 - case 'cancelled': 148 - $query->withIsCancelled(true); 149 - break; 150 - } 151 - 152 - return $query; 153 - } 154 - 155 - public function buildSearchForm( 156 - AphrontFormView $form, 157 - PhabricatorSavedQuery $saved) { 158 - 159 - $range_start = $this->getDateFrom($saved); 160 - $e_start = null; 161 - 162 - $range_end = $this->getDateTo($saved); 163 - $e_end = null; 164 - 165 - if (!$range_start->isValid()) { 166 - $this->addError(pht('Start date is not valid.')); 167 - $e_start = pht('Invalid'); 168 - } 169 - 170 - if (!$range_end->isValid()) { 171 - $this->addError(pht('End date is not valid.')); 172 - $e_end = pht('Invalid'); 173 - } 174 - 175 - $start_epoch = $range_start->getEpoch(); 176 - $end_epoch = $range_end->getEpoch(); 177 - 178 - if ($start_epoch && $end_epoch && ($start_epoch > $end_epoch)) { 179 - $this->addError(pht('End date must be after start date.')); 180 - $e_start = pht('Invalid'); 181 - $e_end = pht('Invalid'); 182 - } 183 - 184 - $upcoming = $saved->getParameter('upcoming'); 185 - $is_cancelled = $saved->getParameter('isCancelled', 'active'); 186 - $display = $saved->getParameter('display', 'month'); 187 - 188 - $invited_phids = $saved->getParameter('invitedPHIDs', array()); 189 - $creator_phids = $saved->getParameter('creatorPHIDs', array()); 190 - $resolution_types = array( 191 - 'active' => pht('Active Events Only'), 192 - 'cancelled' => pht('Cancelled Events Only'), 193 - 'both' => pht('Both Cancelled and Active Events'), 194 - ); 195 - $display_options = array( 196 - 'month' => pht('Month View'), 197 - 'day' => pht('Day View (beta)'), 198 - 'list' => pht('List View'), 199 - ); 200 - 201 - $form 202 - ->appendControl( 203 - id(new AphrontFormTokenizerControl()) 204 - ->setDatasource(new PhabricatorPeopleUserFunctionDatasource()) 205 - ->setName('creators') 206 - ->setLabel(pht('Created By')) 207 - ->setValue($creator_phids)) 208 - ->appendControl( 209 - id(new AphrontFormTokenizerControl()) 210 - ->setDatasource(new PhabricatorPeopleUserFunctionDatasource()) 211 - ->setName('invited') 212 - ->setLabel(pht('Invited')) 213 - ->setValue($invited_phids)) 214 - ->appendChild( 215 - id(new AphrontFormDateControl()) 216 - ->setLabel(pht('Occurs After')) 217 - ->setUser($this->requireViewer()) 218 - ->setName('rangeStart') 219 - ->setError($e_start) 220 - ->setValue($range_start)) 221 - ->appendChild( 222 - id(new AphrontFormDateControl()) 223 - ->setLabel(pht('Occurs Before')) 224 - ->setUser($this->requireViewer()) 225 - ->setName('rangeEnd') 226 - ->setError($e_end) 227 - ->setValue($range_end)) 228 - ->appendChild( 229 - id(new AphrontFormCheckboxControl()) 230 - ->addCheckbox( 231 - 'upcoming', 232 - 1, 233 - pht('Show only upcoming events.'), 234 - $upcoming)) 235 - ->appendChild( 236 - id(new AphrontFormSelectControl()) 237 - ->setLabel(pht('Cancelled Events')) 238 - ->setName('isCancelled') 239 - ->setValue($is_cancelled) 240 - ->setOptions($resolution_types)) 241 - ->appendChild( 242 - id(new AphrontFormSelectControl()) 243 - ->setLabel(pht('Display Options')) 244 - ->setName('display') 245 - ->setValue($display) 246 - ->setOptions($display_options)); 195 + return array($min_range, $max_range); 247 196 } 248 197 249 198 protected function getURI($path) { ··· 279 228 case 'day': 280 229 return $query->setParameter('display', 'day'); 281 230 case 'upcoming': 282 - return $query->setParameter('upcoming', true); 231 + return $query->setParameter('upcoming', array( 232 + 0 => 'upcoming', 233 + )); 283 234 case 'all': 284 235 return $query; 285 236 } ··· 311 262 assert_instances_of($events, 'PhabricatorCalendarEvent'); 312 263 $viewer = $this->requireViewer(); 313 264 $list = new PHUIObjectItemListView(); 265 + 314 266 foreach ($events as $event) { 315 267 $from = phabricator_datetime($event->getDateFrom(), $viewer); 316 268 $duration = ''; ··· 349 301 array $statuses, 350 302 PhabricatorSavedQuery $query, 351 303 array $handles) { 304 + 352 305 $viewer = $this->requireViewer(); 353 306 $now = time(); 354 307 355 308 list($start_year, $start_month) = 356 - $this->getDisplayYearAndMonthAndDay($query); 309 + $this->getDisplayYearAndMonthAndDay( 310 + $this->getQueryDateFrom($query)->getEpoch(), 311 + $this->getQueryDateTo($query)->getEpoch(), 312 + $query->getParameter('display')); 357 313 358 314 $now_year = phabricator_format_local_time($now, $viewer, 'Y'); 359 315 $now_month = phabricator_format_local_time($now, $viewer, 'm'); ··· 361 317 362 318 if ($start_month == $now_month && $start_year == $now_year) { 363 319 $month_view = new PHUICalendarMonthView( 364 - $this->getDateFrom($query), 365 - $this->getDateTo($query), 320 + $this->getQueryDateFrom($query), 321 + $this->getQueryDateTo($query), 366 322 $start_month, 367 323 $start_year, 368 324 $now_day); 369 325 } else { 370 326 $month_view = new PHUICalendarMonthView( 371 - $this->getDateFrom($query), 372 - $this->getDateTo($query), 327 + $this->getQueryDateFrom($query), 328 + $this->getQueryDateTo($query), 373 329 $start_month, 374 330 $start_year); 375 331 } ··· 406 362 array $statuses, 407 363 PhabricatorSavedQuery $query, 408 364 array $handles) { 365 + 409 366 $viewer = $this->requireViewer(); 367 + 410 368 list($start_year, $start_month, $start_day) = 411 - $this->getDisplayYearAndMonthAndDay($query); 369 + $this->getDisplayYearAndMonthAndDay( 370 + $this->getQueryDateFrom($query)->getEpoch(), 371 + $this->getQueryDateTo($query)->getEpoch(), 372 + $query->getParameter('display')); 412 373 413 374 $day_view = id(new PHUICalendarDayView( 414 - $this->getDateFrom($query), 415 - $this->getDateTo($query), 375 + $this->getQueryDateFrom($query)->getEpoch(), 376 + $this->getQueryDateTo($query)->getEpoch(), 416 377 $start_year, 417 378 $start_month, 418 379 $start_day)) ··· 454 415 } 455 416 456 417 private function getDisplayYearAndMonthAndDay( 457 - PhabricatorSavedQuery $query) { 418 + $range_start, 419 + $range_end, 420 + $display) { 421 + 458 422 $viewer = $this->requireViewer(); 423 + $epoch = null; 424 + 459 425 if ($this->calendarYear && $this->calendarMonth) { 460 426 $start_year = $this->calendarYear; 461 427 $start_month = $this->calendarMonth; 462 428 $start_day = $this->calendarDay ? $this->calendarDay : 1; 463 429 } else { 464 - $epoch = $this->getDateFrom($query)->getEpoch(); 465 - if (!$epoch) { 466 - $epoch = $this->getDateTo($query)->getEpoch(); 467 - if (!$epoch) { 468 - $epoch = time(); 469 - } 430 + if ($range_start) { 431 + $epoch = $range_start; 432 + } else if ($range_end) { 433 + $epoch = $range_end; 434 + } else { 435 + $epoch = time(); 470 436 } 471 - if ($this->isMonthView($query)) { 437 + if ($display == 'month') { 472 438 $day = 1; 473 439 } else { 474 440 $day = phabricator_format_local_time($epoch, $viewer, 'd'); ··· 488 454 } 489 455 } 490 456 491 - private function getDateFrom(PhabricatorSavedQuery $saved) { 492 - return $this->getDate($saved, 'rangeStart'); 457 + private function getQueryDateFrom(PhabricatorSavedQuery $saved) { 458 + return $this->getQueryDate($saved, 'rangeStart'); 493 459 } 494 460 495 - private function getDateTo(PhabricatorSavedQuery $saved) { 496 - return $this->getDate($saved, 'rangeEnd'); 461 + private function getQueryDateTo(PhabricatorSavedQuery $saved) { 462 + return $this->getQueryDate($saved, 'rangeEnd'); 497 463 } 498 464 499 - private function getDate(PhabricatorSavedQuery $saved, $key) { 465 + private function getQueryDate(PhabricatorSavedQuery $saved, $key) { 500 466 $viewer = $this->requireViewer(); 501 467 502 468 $wild = $saved->getParameter($key); 503 - if ($wild) { 504 - $value = AphrontFormDateControlValue::newFromWild($viewer, $wild); 469 + return $this->getSafeDate($wild); 470 + } 471 + 472 + private function getSafeDate($value) { 473 + $viewer = $this->requireViewer(); 474 + if ($value) { 475 + // ideally this would be consistent and always pass in the same type 476 + if ($value instanceof AphrontFormDateControlValue) { 477 + return $value; 478 + } else { 479 + $value = AphrontFormDateControlValue::newFromWild($viewer, $value); 480 + } 505 481 } else { 506 482 $value = AphrontFormDateControlValue::newFromEpoch( 507 483 $viewer,
+1
src/applications/calendar/storage/PhabricatorCalendarEvent.php
··· 2 2 3 3 final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO 4 4 implements PhabricatorPolicyInterface, 5 + PhabricatorProjectInterface, 5 6 PhabricatorMarkupInterface, 6 7 PhabricatorApplicationTransactionInterface, 7 8 PhabricatorSubscribableInterface,
+5 -1
src/applications/search/engine/PhabricatorApplicationSearchEngine.php
··· 266 266 } 267 267 268 268 $query = $this->newQuery(); 269 - if ($query) { 269 + if ($query && $this->shouldShowOrderField()) { 270 270 $orders = $query->getBuiltinOrders(); 271 271 $orders = ipull($orders, 'name'); 272 272 ··· 291 291 } 292 292 293 293 return $field_map; 294 + } 295 + 296 + protected function shouldShowOrderField() { 297 + return true; 294 298 } 295 299 296 300 private function adjustFieldsForDisplay(array $field_map) {
+39
src/applications/search/field/PhabricatorSearchDateControlField.php
··· 1 + <?php 2 + 3 + final class PhabricatorSearchDateControlField 4 + extends PhabricatorSearchField { 5 + 6 + protected function getValueExistsInRequest(AphrontRequest $request, $key) { 7 + // The control doesn't actually submit a value with the same name as the 8 + // key, so look for the "_d" value instead, which has the date part of the 9 + // control value. 10 + return $request->getExists($key.'_d'); 11 + } 12 + 13 + protected function getValueFromRequest(AphrontRequest $request, $key) { 14 + $value = AphrontFormDateControlValue::newFromRequest($request, $key); 15 + $value->setOptional(true); 16 + return $value->getDictionary(); 17 + } 18 + 19 + protected function newControl() { 20 + return id(new AphrontFormDateControl()) 21 + ->setAllowNull(true); 22 + } 23 + 24 + protected function didReadValueFromSavedQuery($value) { 25 + if (!$value) { 26 + return null; 27 + } 28 + 29 + if ($value instanceof AphrontFormDateControlValue && $value->getEpoch()) { 30 + return $value->setOptional(true); 31 + } 32 + 33 + $value = AphrontFormDateControlValue::newFromWild( 34 + $this->getViewer(), 35 + $value); 36 + return $value->setOptional(true); 37 + } 38 + 39 + }
+13 -6
src/view/phui/calendar/PHUICalendarDayView.php
··· 208 208 private function getQueryRangeWarning() { 209 209 $errors = array(); 210 210 211 - $range_start_epoch = $this->rangeStart->getEpoch(); 212 - $range_end_epoch = $this->rangeEnd->getEpoch(); 211 + $range_start_epoch = null; 212 + $range_end_epoch = null; 213 + 214 + if ($this->rangeStart) { 215 + $range_start_epoch = $this->rangeStart->getEpoch(); 216 + } 217 + if ($this->rangeEnd) { 218 + $range_end_epoch = $this->rangeEnd->getEpoch(); 219 + } 213 220 214 221 $day_start = $this->getDateTime(); 215 222 $day_end = id(clone $day_start)->modify('+1 day'); ··· 226 233 $errors[] = pht('Part of the day is out of range'); 227 234 } 228 235 229 - if (($this->rangeEnd->getEpoch() != null && 230 - $this->rangeEnd->getEpoch() < $day_start) || 231 - ($this->rangeStart->getEpoch() != null && 232 - $this->rangeStart->getEpoch() > $day_end)) { 236 + if (($range_end_epoch != null && 237 + $range_end_epoch < $day_start) || 238 + ($range_start_epoch != null && 239 + $range_start_epoch > $day_end)) { 233 240 $errors[] = pht('Day is out of query range'); 234 241 } 235 242 return $errors;
+13 -6
src/view/phui/calendar/PHUICalendarMonthView.php
··· 434 434 private function getQueryRangeWarning() { 435 435 $errors = array(); 436 436 437 - $range_start_epoch = $this->rangeStart->getEpoch(); 438 - $range_end_epoch = $this->rangeEnd->getEpoch(); 437 + $range_start_epoch = null; 438 + $range_end_epoch = null; 439 + 440 + if ($this->rangeStart) { 441 + $range_start_epoch = $this->rangeStart->getEpoch(); 442 + } 443 + if ($this->rangeEnd) { 444 + $range_end_epoch = $this->rangeEnd->getEpoch(); 445 + } 439 446 440 447 $month_start = $this->getDateTime(); 441 448 $month_end = id(clone $month_start)->modify('+1 month'); ··· 452 459 $errors[] = pht('Part of the month is out of range'); 453 460 } 454 461 455 - if (($this->rangeEnd->getEpoch() != null && 456 - $this->rangeEnd->getEpoch() < $month_start) || 457 - ($this->rangeStart->getEpoch() != null && 458 - $this->rangeStart->getEpoch() > $month_end)) { 462 + if (($range_end_epoch != null && 463 + $range_end_epoch < $month_start) || 464 + ($range_start_epoch != null && 465 + $range_start_epoch > $month_end)) { 459 466 $errors[] = pht('Month is out of query range'); 460 467 } 461 468