We had fun and learned a lot!
More info: https://fonsvandamme.be/blog/local-drupal-development-acquia-dev-desktop
drupal generate:entity:content
/**
* @ContentEntityType(
* id = "pokemon_marker",
* label = @Translation("Pokemon marker"),
* ...
* entity_keys = {
* "id" = "id",
* "label" = "name",
* "uuid" = "uuid",
* "uid" = "user_id",
* "langcode" = "langcode",
* "status" = "status",
* },
* links = {
* "canonical" = "/admin/structure/pokemon/marker/{pokemon_marker}",
* "add-form" = "/admin/structure/pokemon/marker/add",
* "edit-form" = "/admin/structure/pokemon/marker/{pokemon_marker}/edit",
* "delete-form" = "/admin/structure/pokemon/marker/{pokemon_marker}/delete",
* "collection" = "/admin/structure/pokemon/marker",
* },
* )
*/
$fields['type'] = BaseFieldDefinition::create('list_string')
->setLabel(t('Type'))
->setTranslatable(FALSE)
->setRequired(TRUE)
->setDefaultValue('gym')
->setSettings(array(
'allowed_values' => array(
'gym' => 'Gym',
'pokestop' => 'Pokestop',
'lure' => 'Lure',
),
))
->setRevisionable(FALSE)
->setDisplayOptions('form', array(
'type' => 'list_string',
'weight' => 5,
'settings' => array(
'display_label' => TRUE,
),
));
Edits after module install: drush entity-updates
public static function getAllMarkerTypes() {
return array(
'gym' => new MarkerGym(),
'pokestop' => new MarkerPokestop(),
'lure' => new MarkerLure(),
'gym-new' => new MarkerGymNew(),
'pokestop-new' => new MarkerPokestopNew(),
'lure-new' => new MarkerLureNew()
);
}
Inject http client into class by defining this in pokemon.services.yml
pokemon.manager.import
class: Drupal\pokemon\Manager\MarkerImportManager
arguments: ['@http_client']
MarkerImportManager constructor
public function __construct(Client $client) {
$this->httpClient = $client;
}
Execute request
$response = $this->httpClient->get('uri', [
'headers'=> [
'Content-Type'=> 'application/json',
'additional-header'=> 'value'
],
'auth'=> ['username', 'password'],
]);
Process response
$status_code = $reponse->getStatusCode();
if ($status_code == 200) {
$response_contents = $reponse->getBody()->getContents();
// Do something with response.
...
}
=> Semi-decoupled application
pokemon.leaflet:
version: 1.x
css:
theme:
... leaflet dependent css
js:
... leaflet library and plugins
pokemon.angular:
... angular libray files and custom directives
pokemon.angular.app:
...
dependencies:
- pokemon/pokemon.angular
pokemon.angular.leaflet:
...
dependencies:
- pokemon/pokemon.leaflet
- core/underscore
- core/drupal.debounce
- pokemon/pokemon.angular.app
Readable and compact bacause of
return array(
'#theme' => 'pokemon_page',
'#content' => $content,
'#sidebar' => $sidebar,
'#attached' => array(
'library' => array(
'pokemon/pokemon.angular.leaflet',
),
)
);
HTML:
Javascript:
if(checkStuff()){
$scope.mapFactory.hasToZoomIn = false;
$scope.buttonText = "You can click it now";
}
HTML:
Pokéstop
Javascript:
// Adds pokestop marker to map.
$scope.addPokestop = function () {
// Do fancy things.
};
HTML:
{{ 'Reset location' | t }}
HTML:
Javascript:
angular.extend($scope, {
defaults: {
maxZoom: 18, minZoom: 8
},
center: {
lat: 51.038, lng: 3.721
},
layers: {
...
},
markers {
...
}
});
Used an angular directive to integrate Leaflet.js and AngularJS
// Init leaflet map.
angular.extend($scope, {
defaults: {
maxZoom: 18,
minZoom: 8
},
center: {
lat: 51.038,
lng: 3.721,
zoom: 17,
autoDiscover: true
},
events: {
marker: {
enable: ['dragend'],
logic: 'emit'
},
map: {
enable: ['zoomend', 'move'],
logic: 'emit'
}
},
...
});
// Init leaflet map.
angular.extend($scope, {
...
layers: {
baselayers: {
googleRoadmap: {
name: 'Google Map',
layerType: 'ROADMAP',
type: 'google'
}
},
...
}
});
// Init leaflet map.
angular.extend($scope, {
layers: {
...
overlays: {
ourAwesomeMarkers: {
name: "Markers",
type: "markercluster",
visible: true,
layerOptions: {
disableClusteringAtZoom: 18
}
}
}
}
});
// On zoom end, load markers
$scope.$on('leafletDirectiveMap.pokemon-map.zoomend', _.debounce(function (event, args) {
$scope.loadMarkers();
}, 500));
// On move load markers
$scope.$on('leafletDirectiveMap.pokemon-map.move', _.debounce(function (event, args) {
$scope.loadMarkers();
}, 500));
Let leaflet do all th heavy lifting
Possible to create a resource with Drupal Console
/**
* @RestResource(
* id = "pokemon_marker",
* label = @Translation("Pokemon marker"),
* uri_paths = {
* "canonical" = "/api/marker/{z}/{x}/{y}"
* }
* )
*/
class PokemonMarker extends ResourceBase {
...
}
/**
* Responds to GET requests.
*/
public function get($z, $x, $y) {
if ($something = $this->somethingWrong()) {
// Return 403.
throw new AccessDeniedHttpException($something);
}
// Fetch all markers within tile.
$markers = $this->manager->getMarkers($z, $x, $y);
return new ResourceResponse($markers);
}
Caching problems for anonymous users: used "KillSwitch" to disable cache.
Based on Classy
pokepoke.info.yml
name: pokepoke
type: theme
description: 'Subtheme for Poke Poke!'
core: 8.x
package: custom
base theme: classy
libraries:
- pokepoke/base
pokepoke.libraries.yml
base:
version: 1.0
css:
theme:
css/fontawesome/font-awesome.css: {}
css/pokemon.css: {}
js:
js/bootstrap.js: {}
js/jquery.touchSwipe.min.js: {}
js/pokepoke.js: {}
dependencies:
- core/jquery
- core/jquery.once
- core/drupal
- core/drupalSettings
config.rb
require 'susy'
require 'breakpoint'
require 'sass-globbing'
http_path = "/"
css_dir = "css"
sass_dir = "scss"
images_dir = "img"
javascripts_dir = "js"
output_style = :expanded
relative_assets = true
line_comments = true
Gemlock file
source 'https://rubygems.org'
gem 'compass'
gem "breakpoint", "~>2.4.0"
gem 'sass-rails', '~> 5.0.0'
gem 'susy'
gem 'compass-rails', '~> 2.0.0'
gem 'font-awesome-sass'
gem 'sass-globbing'
There are probably better ways to set this all up with Grunt or Gulp?!
The mobile friendly result after hours of headbanging and using the mighty Google
# Force SSL
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www.my-website\.be*
RewriteRule ^(.*)$ https://my-website.be/$1 [L,R=301]
More info: https://fonsvandamme.be/blog/using-ssl-drupal-website
Thank you for your attention, are there any questions?