2 namespace App\Model\Table;
6 use Cake\ORM\RulesChecker;
8 use Cake\Validation\Validator;
13 * @method \App\Model\Entity\Location get($primaryKey, $options = [])
14 * @method \App\Model\Entity\Location newEntity($data = null, array $options = [])
15 * @method \App\Model\Entity\Location[] newEntities(array $data, array $options = [])
16 * @method \App\Model\Entity\Location|bool save(\Cake\Datasource\EntityInterface $entity, $options = [])
17 * @method \App\Model\Entity\Location patchEntity(\Cake\Datasource\EntityInterface $entity, array $data, array $options = [])
18 * @method \App\Model\Entity\Location[] patchEntities($entities, array $data, array $options = [])
19 * @method \App\Model\Entity\Location findOrCreate($search, callable $callback = null, $options = [])
21 * @mixin \Cake\ORM\Behavior\TimestampBehavior
23 class LocationsTable extends Table
29 * @param array $config The configuration for the Table.
32 public function initialize(array $config)
34 parent::initialize($config);
36 $this->setTable('locations');
37 $this->setDisplayField('name');
38 $this->setPrimaryKey('id');
40 $this->addBehavior('Timestamp');
42 $this->belongsToMany('Categories',
44 'targetForeignKey' => 'category_id',
45 'foreignKey' => 'location_id',
46 'joinTable' => 'categories_locations',
47 'through' => 'CategoriesLocations',
54 * Default validation rules.
56 * @param \Cake\Validation\Validator $validator Validator instance.
57 * @return \Cake\Validation\Validator
59 public function validationDefault(Validator $validator)
63 ->allowEmpty('id', 'create');
66 ->requirePresence('name', 'create')
68 ->add('name', 'unique', ['rule' => 'validateUnique', 'provider' => 'table']);
70 $validator->requirePresence ( 'location', 'create' )->notEmpty ( 'location' );
81 * Returns a rules checker object that will be used for validating
82 * application integrity.
84 * @param \Cake\ORM\RulesChecker $rules The rules object to be modified.
85 * @return \Cake\ORM\RulesChecker
87 public function buildRules(RulesChecker $rules)
89 $rules->add($rules->isUnique(['name']));
96 * returns a query that will find the category records associated with a location 'id'
99 public function getSelectedCategories($id)
101 // find the categories that are chosen for this item, if any.
102 $selectedCategories = $this->CategoriesLocations->find ( 'list', [
103 'keyField' => 'category_id',
104 'valueField' => 'location_id',
112 return $selectedCategories;
116 * returns a query that will find all of the locations within the bounding box.
118 public function getLocationsInBox($sw_lat, $sw_long, $ne_lat, $ne_long, $start = null, $end = null) {
119 $locationsInRange = $this->find ( 'all', [
120 'contain' => ['Categories'],
123 Log::Debug ( 'bounds=' . $sw_lat . ', ' . $sw_long . ' to ' . $ne_lat . ', ' . $ne_long );
133 Log::Debug ( "failed to calculate the bounding box!" );
135 Log::Debug ( "bounding box: " . var_export ( $bounds, true ) );
138 // use the boundaries to restrict the lookup so we aren't crushed.
139 // order: min_lat, min_long, max_lat, max_long.
140 $locationsInRange = $locationsInRange->where ( function ($exp) use ($bounds) {
141 return $exp->gte ( 'lat', $bounds [0] )->gte ( 'lng', $bounds [1] )->lte ( 'lat', $bounds [2] )->lte ( 'lng', $bounds [3] );
144 if (($start !== null) && ($end !== null)) {
145 Log::debug('start of range = ' . $start . ' and end = ' . $end);
146 $locationsInRange = $locationsInRange->order(['lat desc', 'lng desc']);
147 $chunk = $end - $start + 1;
148 $locationsInRange = $locationsInRange->limit($chunk);
149 $page = 1 + (int)($start / $chunk);
150 $locationsInRange = $locationsInRange->page($page);
151 Log::debug('page = ' . $page . ' and chunk = ' . $chunk);
154 return $locationsInRange;
158 * retrieves all of the locations within the bounding box as a list of partial location data.
160 public function getChewedLocationsInBox($sw_lat, $sw_long, $ne_lat, $ne_long, $start = null, $end = null) {
161 $locationsInRange = $this->getLocationsInBox($sw_lat, $sw_long, $ne_lat, $ne_long, $start, $end);
163 // track locations we've already added and do not add ones at exactly the same lat/long.
164 // if we did add these, google maps screws up in representing them.
165 $locationsToSerialize = [ ];
167 foreach ( $locationsInRange as $location ) {
168 $lat_and_long = $location->lat . ',' . $location->lng;
169 if (array_key_exists ( $lat_and_long, $locationsToSerialize )) {
170 continue; // already got it.
173 // Log::debug('dumping location row: ' . var_export($location, true));
175 // we don't include lat and lng below since they are encoded as array key.
176 $locationsToSerialize [$lat_and_long] = [
177 'name' => $location->name,
178 'loc' => $location->location,
179 'id' => $location->id
182 // only try to add the image if the location actually has a category membership (at least one).
183 if ($location->categories) {
184 $locationsToSerialize [$lat_and_long]['icon'] = $location->categories[0]->image;
188 return $locationsToSerialize;