File Coverage

blib/lib/WWW/Google/Places.pm
Criterion Covered Total %
statement 32 92 34.7
branch 0 14 0.0
condition n/a
subroutine 11 20 55.0
pod 7 7 100.0
total 50 133 37.5


line stmt bran cond sub pod time code
1             package WWW::Google::Places;
2              
3             $WWW::Google::Places::VERSION = '0.37';
4             $WWW::Google::Places::AUTHORITY = 'cpan:MANWAR';
5              
6             =head1 NAME
7              
8             WWW::Google::Places - Interface to Google Places API.
9              
10             =head1 VERSION
11              
12             Version 0.37
13              
14             =cut
15              
16 8     8   246214 use 5.006;
  8         89  
17 8     8   5199 use JSON;
  8         101498  
  8         89  
18 8     8   5384 use Data::Dumper;
  8         51529  
  8         557  
19              
20 8     8   3625 use WWW::Google::UserAgent;
  8         896058  
  8         331  
21 8     8   4571 use WWW::Google::UserAgent::DataTypes qw(:all);
  8         1294833  
  8         118  
22 8     8   152776 use WWW::Google::Places::Params qw(get_validator);
  8         27  
  8         648  
23 8     8   3809 use WWW::Google::Places::SearchResult;
  8         31  
  8         289  
24 8     8   4087 use WWW::Google::Places::DetailResult;
  8         30  
  8         423  
25              
26 8     8   70 use Moo;
  8         17  
  8         41  
27 8     8   4652 use namespace::clean;
  8         35  
  8         43  
28             extends 'WWW::Google::UserAgent';
29              
30             our $BASE_URL = 'https://maps.googleapis.com/maps/api/place';
31              
32             has 'sensor' => (is => 'ro', isa => TrueFalse, default => sub { 'false' });
33             has 'output' => (is => 'ro', isa => FileType, default => sub { 'json' });
34             has 'language' => (is => 'ro', isa => Language, default => sub { 'en' });
35             has 'validator' => (is => 'ro', default => \&get_validator);
36              
37             before [qw/search paged_search add/] => sub {
38             my ($self, $param) = @_;
39              
40             my $method = (caller(1))[3];
41             $method =~ /(.*)\:\:(.*)$/;
42             $self->validator->validate($2, $param);
43             };
44              
45             =head1 DESCRIPTION
46              
47             The Google Places API is a service that returns information about Places, defined
48             within this API as establishments, geographic location or prominent points of
49             interest using HTTP request.Place requests specify location as latitude/longitude
50             coordinates. Users with an API key are allowed 1,000 requests per 24 hour period.
51             Currently it supports version v3.
52              
53             The official Google API document can be found L.
54              
55             =head1 SYNOPSIS
56              
57             use strict; use warnings;
58             use WWW::Google::Places;
59              
60             my $api_key = 'YOUR_API_KEY';
61             my $place = WWW::Google::Places->new({ api_key => $api_key });
62              
63             # Google search place
64             my $results = $place->search({ location => '-33.8670522,151.1957362', radius => 500 });
65             print join("\n----------------------------------------\n", @$results), "\n";
66              
67             # Google search place details
68             my $place_id = 'ChIJ1ZL9NkGuEmsRUEkzFmh9AQU';
69             print "\n----------------------------------------\n";
70             print $place->details($place_id), "\n";
71              
72             =head1 PLACE TYPES
73              
74             Supported types for Place adds/searches.
75              
76             +---------------------------------+
77             | accounting |
78             | airport |
79             | amusement_park |
80             | aquarium |
81             | art_gallery |
82             | atm |
83             | bakery |
84             | bank |
85             | bar |
86             | beauty_salon |
87             | bicycle_store |
88             | book_store |
89             | bowling_alley |
90             | bus_station |
91             | cafe |
92             | campground |
93             | car_dealer |
94             | car_rental |
95             | car_repair |
96             | car_wash |
97             | casino |
98             | cemetery |
99             | church |
100             | city_hall |
101             | clothing_store |
102             | convenience_store |
103             | courthouse |
104             | dentist |
105             | department_store |
106             | doctor |
107             | electrician |
108             | electronics_store |
109             | embassy |
110             | establishment |
111             | finance |
112             | fire_station |
113             | florist |
114             | food |
115             | funeral_home |
116             | furniture_store |
117             | gas_station |
118             | general_contractor |
119             | geocode |
120             | grocery_or_supermarket |
121             | gym |
122             | hair_care |
123             | hardware_store |
124             | health |
125             | hindu_temple |
126             | home_goods_store |
127             | hospital |
128             | insurance_agency |
129             | jewelry_store |
130             | laundry |
131             | lawyer |
132             | library |
133             | liquor_store |
134             | local_government_office |
135             | locksmith |
136             | lodging |
137             | meal_delivery |
138             | meal_takeaway |
139             | mosque |
140             | movie_rental |
141             | movie_theater |
142             | moving_company |
143             | museum |
144             | night_club |
145             | painter |
146             | park |
147             | parking |
148             | pet_store |
149             | pharmacy |
150             | physiotherapist |
151             | place_of_worship |
152             | plumber |
153             | police |
154             | post_office |
155             | real_estate_agency |
156             | restaurant |
157             | roofing_contractor |
158             | rv_park |
159             | school |
160             | shoe_store |
161             | shopping_mall |
162             | spa |
163             | stadium |
164             | storage |
165             | store |
166             | subway_station |
167             | synagogue |
168             | taxi_stand |
169             | train_station |
170             | travel_agency |
171             | university |
172             | veterinary_care |
173             | zoo |
174             +---------------------------------+
175              
176             Additional types listed below can be used in Place Searches, but not when adding a Place.
177              
178             +---------------------------------+
179             | administrative_area_level_1 |
180             | administrative_area_level_2 |
181             | administrative_area_level_3 |
182             | colloquial_area |
183             | country |
184             | floor |
185             | intersection |
186             | locality |
187             | natural_feature |
188             | neighborhood |
189             | political |
190             | point_of_interest |
191             | post_box |
192             | postal_code |
193             | postal_code_prefix |
194             | postal_town |
195             | premise |
196             | room |
197             | route |
198             | street_address |
199             | street_number |
200             | sublocality |
201             | sublocality_level_4 |
202             | sublocality_level_5 |
203             | sublocality_level_3 |
204             | sublocality_level_2 |
205             | sublocality_level_1 |
206             | subpremise |
207             | transit_station |
208             +---------------------------------+
209              
210             =head1 LANGUAGES
211              
212             +-------+-------------------------+
213             | Code | Name |
214             +-------+-------------------------+
215             | ar | ARABIC |
216             | eu | BASQUE |
217             | bg | BULGARIAN |
218             | bn | BENGALI |
219             | ca | CATALAN |
220             | cs | CZECH |
221             | da | DANISH |
222             | de | GERMAN |
223             | el | GREEK |
224             | en | ENGLISH |
225             | en-AU | ENGLISH (AUSTRALIAN) |
226             | en-GB | ENGLISH (GREAT BRITAIN) |
227             | es | SPANISH |
228             | eu | BASQUE |
229             | fa | FARSI |
230             | fi | FINNISH |
231             | fil | FILIPINO |
232             | fr | FRENCH |
233             | gl | GALICIAN |
234             | gu | GUJARATI |
235             | hi | HINDI |
236             | hr | CROATIAN |
237             | hu | HUNGARIAN |
238             | id | INDONESIAN |
239             | it | ITALIAN |
240             | iw | HEBREW |
241             | ja | JAPANESE |
242             | kn | KANNADA |
243             | ko | KOREAN |
244             | lt | LITHUANIAN |
245             | lv | LATVIAN |
246             | ml | MALAYALAM |
247             | mr | MARATHI |
248             | nl | DUTCH |
249             | no | NORWEGIAN |
250             | pl | POLISH |
251             | pt | PORTUGUESE |
252             | pt-BR | PORTUGUESE (BRAZIL) |
253             | pt-PT | PORTUGUESE (PORTUGAL) |
254             | ro | ROMANIAN |
255             | ru | RUSSIAN |
256             | sk | SLOVAK |
257             | sl | SLOVENIAN |
258             | sr | SERBIAN |
259             | sv | SWEDISH |
260             | tl | TAGALOG |
261             | ta | TAMIL |
262             | te | TELUGU |
263             | th | THAI |
264             | tr | TURKISH |
265             | uk | UKRAINIAN |
266             | vi | VIETNAMESE |
267             | zh-CN | CHINESE (SIMPLIFIED) |
268             | zh-TW | CHINESE (TRADITIONAL) |
269             +-------+-------------------------+
270              
271             =head1 CONSTRUCTOR
272              
273             The constructor expects the following keys. Only the 'api_key' is mandatory and
274             others are optionals.
275              
276             +-----------+---------------------------------------------------------------+
277             | Parameter | Description |
278             +-----------+---------------------------------------------------------------+
279             | api_key | Your application API key. You should supply a valid API key |
280             | | with all requests. Get a key from the Google APIs console. |
281             | | This must be provided. |
282             | sensor | Indicates whether or not the Place request came from a device |
283             | | using a location sensor (e.g. a GPS) to determine the location|
284             | | sent in this request. This value must be either true or false.|
285             | | Default is false. |
286             | language | The language code, indicating in which language the results |
287             | | should be returned. The default is en. |
288             +-----------+---------------------------------------------------------------+
289              
290             use strict; use warnings;
291             use WWW::Google::Places;
292              
293             my $api_key = 'Your_API_Key';
294             my $place = WWW::Google::Places->new({ api_key => $api_key });
295              
296             =head1 METHODS
297              
298             =head2 search(\%params)
299              
300             It expects a ref to hash as the only parameter containing the following keys. It
301             returns list of objects of type L in a LIST
302             context and ref to the same list in a SCALAR context.
303              
304             +----------+----------------------------------------------------------------+
305             | Key | Description |
306             +----------+----------------------------------------------------------------+
307             | location | The latitude/longitude around which to retrieve Place |
308             | | information. This must be provided as a google.maps.LatLng |
309             | | object. This must be provided. |
310             | radius | The distance (in meters) within which to return Place results. |
311             | | The recommended best practice is to set radius based on the |
312             | | accuracy of the location signal as given by the location |
313             | | sensor. Note that setting a radius biases result to the |
314             | | indicated area, but may not fully restrict results to the |
315             | | specified area. This must be provided. |
316             | types | Restricts the results to Places matching at least one of the |
317             | | specified types. Types should be separated with a pipe symbol. |
318             | name | A term to be matched against the names of Places. |
319             +----------+----------------------------------------------------------------+
320              
321             use strict; use warnings;
322             use WWW::Google::Places;
323              
324             my $api_key = 'Your_API_Key';
325             my $place = WWW::Google::Places->new({ api_key => $api_key });
326             my $results = $place->search({ location=>'-33.8670522,151.1957362', radius=>500 });
327              
328             =cut
329              
330             sub search {
331             my ($self, $values) = @_;
332              
333             my $url = $self->_url('search');
334             $url .= $self->validator->query_param('search', $values);
335             my $response = $self->get($url);
336             my $contents = from_json($response->{content});
337              
338             my @results = map { WWW::Google::Places::SearchResult->new($_) } @{$contents->{results}};
339             return wantarray ? @results : \@results;
340             }
341              
342             =head2 paged_search(\%params)
343              
344             Accepts the same values as C but handles queries that have
345             multiple pages worth of data. Using paged_search the max number of results is 60
346             (or 3 pages worth) L
347              
348             It returns list of objects of type L in a LIST
349             context and ref to a list in a SCALAR context.
350              
351             NOTE:Due to the way that Google handles the paging of results there is a required
352             sleep of 2 seconds between each requests so that the Google pageTokens can become
353             active.
354              
355             use strict; use warnings;
356             use WWW::Google::Places;
357              
358             my $api_key = 'Your_API_Key';
359             my $place = WWW::Google::Places->new({ api_key => $api_key });
360             my $results = $place->paged_search(
361             { location => '34.0522222,-118.2427778',
362             radius => 500,
363             types => 'bar|restaurant',
364             });
365              
366             =cut
367              
368             sub paged_search {
369             my ($self, $values) = @_;
370              
371             my ($pagetoken, $contents, $search_results);
372             do {
373             if (defined $pagetoken) {
374             $values->{pagetoken} = $pagetoken;
375             # pagetokens take a few seconds to become active
376             sleep(2);
377             }
378              
379             my $url = $self->_url('search');
380             $url .= $self->validator->query_param('paged_search', $values);
381             my $response = $self->get($url);
382             $contents = from_json( $response->{content} );
383              
384             push @$search_results,
385             map { WWW::Google::Places::SearchResult->new($_) } @{$contents->{results}};
386             } while $pagetoken = $contents->{next_page_token};
387              
388             return wantarray ? @$search_results : $search_results;
389             }
390              
391             =head2 details($place_id)
392              
393             Expects place id, a textual identifier that uniquely identifies a place, returned
394             from a Place Search. It then returns an object of type L.
395              
396             use strict; use warnings;
397             use WWW::Google::Places;
398              
399             my $api_key = 'Your_API_Key';
400             my $placeid = 'Place_ID';
401             my $place = WWW::Google::Places->new({ api_key => $api_key });
402             my $details = $place->details($placeid);
403              
404             =cut
405              
406             sub details {
407 1     1 1 9 my ($self, $placeid) = @_;
408              
409 1         3 my $values = { placeid => $placeid };
410 1         10 $self->validator->validate('details', $values);
411 0           my $url = $self->_url('details');
412 0           $url .= $self->validator->query_param('details', $values);
413              
414 0           my $response = $self->get($url);
415 0           my $contents = from_json($response->{content});
416              
417 0           return WWW::Google::Places::DetailResult->new($contents->{result});
418             }
419              
420             =head2 add(\%params)
421              
422             Expects a ref to hash as the only parameter containing the following keys.It then
423             returns place id.
424              
425             +----------+----------------------------------------------------------------+
426             | Key | Description |
427             +----------+----------------------------------------------------------------+
428             | location | The latitude/longitude around which to retrieve Place |
429             | | information. This must be provided as a google.maps.LatLng |
430             | | object. |
431             | accuracy | The accuracy of the location signal on which this request is |
432             | | based, expressed in meters. This must be provided. |
433             | name | The full text name of the Place. |
434             | types | Restricts the results to Places matching at least one of the |
435             | | specified types. Types should be separated with a pipe symbol. |
436             +----------+----------------------------------------------------------------+
437              
438             use strict; use warnings;
439             use WWW::Google::Places;
440              
441             my $api_key = 'Your_API_Key';
442             my $place = WWW::Google::Places->new({ api_key => $api_key });
443             my $status = $place->add({ 'location'=>'-33.8669710,151.1958750', accuracy=>40, name=>'Google Shoes!' });
444              
445             =cut
446              
447             sub add {
448             my ($self, $values) = @_;
449              
450             my $params = $self->validator->get_method('add')->fields;
451             my $url = $self->_url('add');
452             my $content = $self->_content($params, $values);
453             my $headers = { 'Host' => 'maps.googleapis.com' };
454             my $response = $self->post($url, $headers, $content);
455             my $contents = from_json($response->{content});
456              
457             return $contents->{place_id};
458             }
459              
460             =head2 delete($place_id)
461              
462             Expects place id, a textual identifier that uniquely identifies a place, returned
463             from a Place Search.
464              
465             Delete a place as given reference. Place can be deleted by the same application
466             that has added it in the first place.Once moderated and added into the full Place
467             Search results, a Place can no longer be deleted. Places that are not accepted
468             by the moderation process will continue to be visible to the application that
469             submitted them.
470              
471             use strict; use warnings;
472             use WWW::Google::Places;
473              
474             my $api_key = 'Your_API_Key';
475             my $place_id = 'Place_ID';
476             my $place = WWW::Google::Places->new({ api_key => $api_key });
477             my $status = $place->delete($place_id);
478              
479             =cut
480              
481             sub delete {
482 0     0 1   my ($self, $place_id) = @_;
483              
484 0           my $values = { place_id => $place_id };
485 0           $self->validator->validate('delete', $values);
486 0           my $params = $self->validator->get_method('delete')->fields;
487 0           my $url = $self->_url('delete');
488 0           my $content = $self->_content($params, $values);
489 0           my $headers = { 'Host' => 'maps.googleapis.com' };
490 0           my $response = $self->post($url, $headers, $content);
491              
492 0           return from_json($response->{content});
493             }
494              
495             =head2 search_place(%params) *** DEPRECATED ***
496              
497             Instead call method search().
498              
499             Returns a list of objects of type L.
500              
501             =cut
502              
503             sub search_place {
504 0     0 1   my ($self, %values) = @_;
505              
506 0           warn "DEPRECATED method, please use search()";
507 0           $self->search(\%values);
508             }
509              
510             =head2 place_detail($reference) *** DEPRECATED ***
511              
512             Instead call method details().
513              
514             Returns an object of type L.
515              
516             =cut
517              
518             sub place_detail {
519 0     0 1   my ($self, $reference) = @_;
520              
521 0           warn "DEPRECATED method, please use details(). Also key 'reference' is deprecated, use placeid";
522              
523 0           my $values = { reference => $reference };
524 0           $self->validator->validate('place_detail', $values);
525 0           my $params = $self->validator->get_method('place_detail')->fields;
526 0           my $url = $self->_url('details');
527 0           $url .= $self->validator->query_param('place_detail', $values);
528 0           my $response = $self->get($url);
529 0           my $contents = from_json($response->{content});
530              
531 0           return WWW::Google::Places::DetailResult->new($contents->{result});
532             }
533              
534             =head2 add_place(%params) *** DEPRECATED ***
535              
536             Instead call method add().
537              
538             Returns an object of type L.
539              
540             =cut
541              
542             sub add_place {
543 0     0 1   my ($self, %values) = @_;
544              
545 0           warn "DEPRECATED method, please use add()";
546 0           $self->add(\%values);
547             }
548              
549             =head2 delete_place($reference) *** DEPRECATED ***
550              
551             Instead call method delete().
552              
553             =cut
554              
555             sub delete_place {
556 0     0 1   my ($self, $reference) = @_;
557              
558 0           warn "DEPRECATED method, please use delete(). Also key 'reference' is deprecated, use place_id";
559 0           my $values = { reference => $reference };
560 0           $self->validator->validate('delete_place', $values);
561 0           my $params = $self->validator->get_method('delete_place')->fields;
562 0           my $url = $self->_url('delete');
563 0           my $content = $self->_content($params, $values);
564 0           my $headers = { 'Host' => 'maps.googleapis.com' };
565 0           my $response = $self->post($url, $headers, $content);
566              
567 0           return from_json($response->{content});
568             }
569              
570             =head2 place_checkins() *** UNSUPPORTED ***
571              
572             =cut
573              
574             sub place_checkins {
575 0     0 1   warn "Google API no longer supports the feature."
576             }
577              
578             #
579             #
580             # PRIVATE METHODS
581              
582             sub _url {
583 0     0     my ($self, $type) = @_;
584              
585 0           return sprintf("%s/%s/%s?key=%s&sensor=%s&language=%s",
586             $BASE_URL, $type, $self->output, $self->api_key,
587             $self->sensor, $self->language);
588             }
589              
590             sub _content {
591 0     0     my ($self, $params, $values) = @_;
592              
593 0           my $data = {};
594 0           foreach my $key (keys %$params) {
595 0 0         if ($key eq 'language') {
596 0 0         if (defined $values->{$key}) {
597 0           $data->{$key} = $values->{$key};
598             }
599             else {
600 0           $data->{$key} = $self->language;
601             }
602             }
603              
604 0 0         next unless defined $values->{$key};
605              
606 0 0         if ($key eq 'location') {
    0          
    0          
607 0           my ($lat, $lng) = split /\,/, $values->{$key};
608 0           $data->{$key} = {'lat' => _handle_number($lat), 'lng' => _handle_number($lng)};
609             }
610             elsif ($key eq 'types') {
611 0           $data->{$key} = [ $values->{$key} ];
612             }
613             elsif ($self->validator->get_field($key)->format eq 'd') {
614 0           $data->{$key} = _handle_number($values->{$key});
615             }
616             else {
617 0           $data->{$key} = $values->{$key};
618             }
619             };
620              
621 0           return to_json($data);
622             }
623              
624             sub _handle_number {
625 0     0     my ($number) = @_;
626              
627 0 0         return ($number =~ m/^\-?[\d]+(\.[\d]+)?$/)?($number*1):$number;
628             }
629              
630             =head1 AUTHOR
631              
632             Mohammad S Anwar, C<< >>
633              
634             =head1 REPOSITORY
635              
636             L
637              
638             =head1 CONTRIBUTORS
639              
640             =over 4
641              
642             =item * Hunter McMillen (mcmillhj)
643              
644             =back
645              
646             =head1 BUGS
647              
648             Please report any bugs or feature requests to C,
649             or through the web interface at L.
650             I will be notified, and then you'll automatically be notified of progress on your
651             bug as I make changes.
652              
653             =head1 SUPPORT
654              
655             You can find documentation for this module with the perldoc command.
656              
657             perldoc WWW::Google::Places
658              
659             You can also look for information at:
660              
661             =over 4
662              
663             =item * RT: CPAN's request tracker (report bugs here)
664              
665             L
666              
667             =item * AnnoCPAN: Annotated CPAN documentation
668              
669             L
670              
671             =item * CPAN Ratings
672              
673             L
674              
675             =item * Search CPAN
676              
677             L
678              
679             =back
680              
681             =head1 LICENSE AND COPYRIGHT
682              
683             Copyright (C) 2011 - 2016 Mohammad S Anwar.
684              
685             This program is free software; you can redistribute it and/or modify it under
686             the terms of the the Artistic License (2.0). You may obtain a copy of the full
687             license at:
688              
689             L
690              
691             Any use, modification, and distribution of the Standard or Modified Versions is
692             governed by this Artistic License.By using, modifying or distributing the Package,
693             you accept this license. Do not use, modify, or distribute the Package, if you do
694             not accept this license.
695              
696             If your Modified Version has been derived from a Modified Version made by someone
697             other than you,you are nevertheless required to ensure that your Modified Version
698             complies with the requirements of this license.
699              
700             This license does not grant you the right to use any trademark, service mark,
701             tradename, or logo of the Copyright Holder.
702              
703             This license includes the non-exclusive, worldwide, free-of-charge patent license
704             to make, have made, use, offer to sell, sell, import and otherwise transfer the
705             Package with respect to any patent claims licensable by the Copyright Holder that
706             are necessarily infringed by the Package. If you institute patent litigation
707             (including a cross-claim or counterclaim) against any party alleging that the
708             Package constitutes direct or contributory patent infringement,then this Artistic
709             License to you shall terminate on the date that such litigation is filed.
710              
711             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND
712             CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
713             WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
714             NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS
715             REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT,
716             INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE
717             OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
718              
719             =cut
720              
721             1; # End of WWW::Google::Places