Factory hierarchy for creating GoogleMap and its elements











up vote
0
down vote

favorite












The purpose of this code is to create a GoogleMap using PHP, add markers to it according to Place objects from database, add infoWindows for these markers. While reading about Factory pattern I came up with the following solution. What are the parts that can be improved. Thank you.



Factory for creating markers:



class MarkerFactory
{
public function create(Coordinate $position, array $options = )
{
$marker = new Marker($position);
$marker->setOptions($options);

return $marker;
}
}


Factory for creating infoWindows. Isn't it violating any principles because of injected dependency?



class InfoWindowFactory
{
private $twig;

public function __construct(Twig_Environment $twig)
{
$this->twig = $twig;
}

public function create(Place $place, $editable = false)
{
return new InfoWindow($this->renderWindowContent($place, $editable));
}

protected function renderWindowContent(Place $place, $editable)
{
if ($editable) {
$template = 'editable_infowindow.html.twig';
} else {
$template = 'static_infowindow.html.twig';
}

return $this->twig->render($template, ['place' => $place]);
}
}


MapFactory that uses MarkerFactory and InfoWindowFactory:



class MapFactory
{
private $markerFactory;

private $infoWindowFactory;

public function __construct(MarkerFactory $markerFactory, InfoWindowFactory $infoWindowFactory)
{
$this->markerFactory = $markerFactory;
$this->infoWindowFactory = $infoWindowFactory;
}

public function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
{
$map = new Map();

$map->setCenter($mapCenter);
$map->setMapOptions($mapOptions);

$markers = ;

foreach ($places as $place) {
$position = new Coordinate($place->getLatitude(), $place->getLongitude());

$marker = $this->markerFactory->create($position);
$infoWindow = $this->infoWindowFactory->create($place, $isEditableMap);

$marker->setInfoWindow($infoWindow);

$markers = $marker;
}

$map->getOverlayManager()->setMarkers($markers);

return $map;
}
}


And the code example of usage:



$markerFactory = new MarkerFactory();
$infoWindowFactory = new InfoWindowFactory($this->get('twig'));
$mapFactory = new MapFactory($markerFactory, $infoWindowFactory);

$center = new Coordinate(55.117100, 23.940332);
$options = ['zoom' => 7];
$map = $mapFactory->create($center, $places, $options);









share|improve this question




























    up vote
    0
    down vote

    favorite












    The purpose of this code is to create a GoogleMap using PHP, add markers to it according to Place objects from database, add infoWindows for these markers. While reading about Factory pattern I came up with the following solution. What are the parts that can be improved. Thank you.



    Factory for creating markers:



    class MarkerFactory
    {
    public function create(Coordinate $position, array $options = )
    {
    $marker = new Marker($position);
    $marker->setOptions($options);

    return $marker;
    }
    }


    Factory for creating infoWindows. Isn't it violating any principles because of injected dependency?



    class InfoWindowFactory
    {
    private $twig;

    public function __construct(Twig_Environment $twig)
    {
    $this->twig = $twig;
    }

    public function create(Place $place, $editable = false)
    {
    return new InfoWindow($this->renderWindowContent($place, $editable));
    }

    protected function renderWindowContent(Place $place, $editable)
    {
    if ($editable) {
    $template = 'editable_infowindow.html.twig';
    } else {
    $template = 'static_infowindow.html.twig';
    }

    return $this->twig->render($template, ['place' => $place]);
    }
    }


    MapFactory that uses MarkerFactory and InfoWindowFactory:



    class MapFactory
    {
    private $markerFactory;

    private $infoWindowFactory;

    public function __construct(MarkerFactory $markerFactory, InfoWindowFactory $infoWindowFactory)
    {
    $this->markerFactory = $markerFactory;
    $this->infoWindowFactory = $infoWindowFactory;
    }

    public function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
    {
    $map = new Map();

    $map->setCenter($mapCenter);
    $map->setMapOptions($mapOptions);

    $markers = ;

    foreach ($places as $place) {
    $position = new Coordinate($place->getLatitude(), $place->getLongitude());

    $marker = $this->markerFactory->create($position);
    $infoWindow = $this->infoWindowFactory->create($place, $isEditableMap);

    $marker->setInfoWindow($infoWindow);

    $markers = $marker;
    }

    $map->getOverlayManager()->setMarkers($markers);

    return $map;
    }
    }


    And the code example of usage:



    $markerFactory = new MarkerFactory();
    $infoWindowFactory = new InfoWindowFactory($this->get('twig'));
    $mapFactory = new MapFactory($markerFactory, $infoWindowFactory);

    $center = new Coordinate(55.117100, 23.940332);
    $options = ['zoom' => 7];
    $map = $mapFactory->create($center, $places, $options);









    share|improve this question


























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      The purpose of this code is to create a GoogleMap using PHP, add markers to it according to Place objects from database, add infoWindows for these markers. While reading about Factory pattern I came up with the following solution. What are the parts that can be improved. Thank you.



      Factory for creating markers:



      class MarkerFactory
      {
      public function create(Coordinate $position, array $options = )
      {
      $marker = new Marker($position);
      $marker->setOptions($options);

      return $marker;
      }
      }


      Factory for creating infoWindows. Isn't it violating any principles because of injected dependency?



      class InfoWindowFactory
      {
      private $twig;

      public function __construct(Twig_Environment $twig)
      {
      $this->twig = $twig;
      }

      public function create(Place $place, $editable = false)
      {
      return new InfoWindow($this->renderWindowContent($place, $editable));
      }

      protected function renderWindowContent(Place $place, $editable)
      {
      if ($editable) {
      $template = 'editable_infowindow.html.twig';
      } else {
      $template = 'static_infowindow.html.twig';
      }

      return $this->twig->render($template, ['place' => $place]);
      }
      }


      MapFactory that uses MarkerFactory and InfoWindowFactory:



      class MapFactory
      {
      private $markerFactory;

      private $infoWindowFactory;

      public function __construct(MarkerFactory $markerFactory, InfoWindowFactory $infoWindowFactory)
      {
      $this->markerFactory = $markerFactory;
      $this->infoWindowFactory = $infoWindowFactory;
      }

      public function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
      {
      $map = new Map();

      $map->setCenter($mapCenter);
      $map->setMapOptions($mapOptions);

      $markers = ;

      foreach ($places as $place) {
      $position = new Coordinate($place->getLatitude(), $place->getLongitude());

      $marker = $this->markerFactory->create($position);
      $infoWindow = $this->infoWindowFactory->create($place, $isEditableMap);

      $marker->setInfoWindow($infoWindow);

      $markers = $marker;
      }

      $map->getOverlayManager()->setMarkers($markers);

      return $map;
      }
      }


      And the code example of usage:



      $markerFactory = new MarkerFactory();
      $infoWindowFactory = new InfoWindowFactory($this->get('twig'));
      $mapFactory = new MapFactory($markerFactory, $infoWindowFactory);

      $center = new Coordinate(55.117100, 23.940332);
      $options = ['zoom' => 7];
      $map = $mapFactory->create($center, $places, $options);









      share|improve this question















      The purpose of this code is to create a GoogleMap using PHP, add markers to it according to Place objects from database, add infoWindows for these markers. While reading about Factory pattern I came up with the following solution. What are the parts that can be improved. Thank you.



      Factory for creating markers:



      class MarkerFactory
      {
      public function create(Coordinate $position, array $options = )
      {
      $marker = new Marker($position);
      $marker->setOptions($options);

      return $marker;
      }
      }


      Factory for creating infoWindows. Isn't it violating any principles because of injected dependency?



      class InfoWindowFactory
      {
      private $twig;

      public function __construct(Twig_Environment $twig)
      {
      $this->twig = $twig;
      }

      public function create(Place $place, $editable = false)
      {
      return new InfoWindow($this->renderWindowContent($place, $editable));
      }

      protected function renderWindowContent(Place $place, $editable)
      {
      if ($editable) {
      $template = 'editable_infowindow.html.twig';
      } else {
      $template = 'static_infowindow.html.twig';
      }

      return $this->twig->render($template, ['place' => $place]);
      }
      }


      MapFactory that uses MarkerFactory and InfoWindowFactory:



      class MapFactory
      {
      private $markerFactory;

      private $infoWindowFactory;

      public function __construct(MarkerFactory $markerFactory, InfoWindowFactory $infoWindowFactory)
      {
      $this->markerFactory = $markerFactory;
      $this->infoWindowFactory = $infoWindowFactory;
      }

      public function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
      {
      $map = new Map();

      $map->setCenter($mapCenter);
      $map->setMapOptions($mapOptions);

      $markers = ;

      foreach ($places as $place) {
      $position = new Coordinate($place->getLatitude(), $place->getLongitude());

      $marker = $this->markerFactory->create($position);
      $infoWindow = $this->infoWindowFactory->create($place, $isEditableMap);

      $marker->setInfoWindow($infoWindow);

      $markers = $marker;
      }

      $map->getOverlayManager()->setMarkers($markers);

      return $map;
      }
      }


      And the code example of usage:



      $markerFactory = new MarkerFactory();
      $infoWindowFactory = new InfoWindowFactory($this->get('twig'));
      $mapFactory = new MapFactory($markerFactory, $infoWindowFactory);

      $center = new Coordinate(55.117100, 23.940332);
      $options = ['zoom' => 7];
      $map = $mapFactory->create($center, $places, $options);






      php factory-method google-maps






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Feb 28 at 0:11









      200_success

      127k15148412




      127k15148412










      asked Nov 4 '16 at 9:25









      nn4n4s

      1162




      1162






















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          0
          down vote













          I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.



          Your MarkerFactory class is close, just needing to have create() method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.



          But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory probably should not have a method such as renderWindowContent() on it. That would seem to be a method that should perhaps exist on the InfoWindow itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).



          I would like to see InfoWindowFactory be something like:



          namespace YourNamespace;

          abstract class InfoWindowFactory
          {
          public static final function create(
          Place $place,
          Twig_Environment $twig,
          $template
          ) {
          return new InfoWindow($place, $twig, $template);
          }
          }


          Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.



          My comments on MapFactory would be similar to those for the InfoWindowFactory. Namely, I would rather see a class like structured like this:



          namespace YourNamespace;

          use MarkerFactory;
          use InfowindowFactory;

          abstract class MapFactory
          {

          public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
          {
          $map = new Map();

          $map->setCenter($mapCenter);
          $map->setMapOptions($mapOptions);

          $markers = ;

          foreach ($places as $place) {
          $position = new Coordinate($place->getLatitude(), $place->getLongitude());

          $marker = MarkerFactory::create($position);
          $infoWindow = InfoWindowFactory::create($place, $isEditableMap);

          $marker->setInfoWindow($infoWindow);

          $markers = $marker;
          }

          $map->getOverlayManager()->setMarkers($markers);

          return $map;
          }
          }


          A comment about validation...



          You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection or similar, you could be ensured that everything in that collection is a valid Place object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).



          Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map, InfoWindow, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.






          share|improve this answer























          • Map, Marker, InfoWindow are from 3rd party livb
            – nn4n4s
            Nov 4 '16 at 18:48










          • @nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push the renderWindowContent() logic down into InfoWindow
            – Mike Brant
            Nov 4 '16 at 21:18










          • Are there some other principles that would make this code more testable than static methods?
            – nn4n4s
            Nov 5 '16 at 4:25










          • @nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
            – Mike Brant
            Nov 7 '16 at 2:53











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f146104%2ffactory-hierarchy-for-creating-googlemap-and-its-elements%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          0
          down vote













          I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.



          Your MarkerFactory class is close, just needing to have create() method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.



          But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory probably should not have a method such as renderWindowContent() on it. That would seem to be a method that should perhaps exist on the InfoWindow itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).



          I would like to see InfoWindowFactory be something like:



          namespace YourNamespace;

          abstract class InfoWindowFactory
          {
          public static final function create(
          Place $place,
          Twig_Environment $twig,
          $template
          ) {
          return new InfoWindow($place, $twig, $template);
          }
          }


          Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.



          My comments on MapFactory would be similar to those for the InfoWindowFactory. Namely, I would rather see a class like structured like this:



          namespace YourNamespace;

          use MarkerFactory;
          use InfowindowFactory;

          abstract class MapFactory
          {

          public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
          {
          $map = new Map();

          $map->setCenter($mapCenter);
          $map->setMapOptions($mapOptions);

          $markers = ;

          foreach ($places as $place) {
          $position = new Coordinate($place->getLatitude(), $place->getLongitude());

          $marker = MarkerFactory::create($position);
          $infoWindow = InfoWindowFactory::create($place, $isEditableMap);

          $marker->setInfoWindow($infoWindow);

          $markers = $marker;
          }

          $map->getOverlayManager()->setMarkers($markers);

          return $map;
          }
          }


          A comment about validation...



          You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection or similar, you could be ensured that everything in that collection is a valid Place object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).



          Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map, InfoWindow, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.






          share|improve this answer























          • Map, Marker, InfoWindow are from 3rd party livb
            – nn4n4s
            Nov 4 '16 at 18:48










          • @nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push the renderWindowContent() logic down into InfoWindow
            – Mike Brant
            Nov 4 '16 at 21:18










          • Are there some other principles that would make this code more testable than static methods?
            – nn4n4s
            Nov 5 '16 at 4:25










          • @nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
            – Mike Brant
            Nov 7 '16 at 2:53















          up vote
          0
          down vote













          I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.



          Your MarkerFactory class is close, just needing to have create() method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.



          But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory probably should not have a method such as renderWindowContent() on it. That would seem to be a method that should perhaps exist on the InfoWindow itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).



          I would like to see InfoWindowFactory be something like:



          namespace YourNamespace;

          abstract class InfoWindowFactory
          {
          public static final function create(
          Place $place,
          Twig_Environment $twig,
          $template
          ) {
          return new InfoWindow($place, $twig, $template);
          }
          }


          Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.



          My comments on MapFactory would be similar to those for the InfoWindowFactory. Namely, I would rather see a class like structured like this:



          namespace YourNamespace;

          use MarkerFactory;
          use InfowindowFactory;

          abstract class MapFactory
          {

          public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
          {
          $map = new Map();

          $map->setCenter($mapCenter);
          $map->setMapOptions($mapOptions);

          $markers = ;

          foreach ($places as $place) {
          $position = new Coordinate($place->getLatitude(), $place->getLongitude());

          $marker = MarkerFactory::create($position);
          $infoWindow = InfoWindowFactory::create($place, $isEditableMap);

          $marker->setInfoWindow($infoWindow);

          $markers = $marker;
          }

          $map->getOverlayManager()->setMarkers($markers);

          return $map;
          }
          }


          A comment about validation...



          You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection or similar, you could be ensured that everything in that collection is a valid Place object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).



          Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map, InfoWindow, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.






          share|improve this answer























          • Map, Marker, InfoWindow are from 3rd party livb
            – nn4n4s
            Nov 4 '16 at 18:48










          • @nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push the renderWindowContent() logic down into InfoWindow
            – Mike Brant
            Nov 4 '16 at 21:18










          • Are there some other principles that would make this code more testable than static methods?
            – nn4n4s
            Nov 5 '16 at 4:25










          • @nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
            – Mike Brant
            Nov 7 '16 at 2:53













          up vote
          0
          down vote










          up vote
          0
          down vote









          I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.



          Your MarkerFactory class is close, just needing to have create() method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.



          But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory probably should not have a method such as renderWindowContent() on it. That would seem to be a method that should perhaps exist on the InfoWindow itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).



          I would like to see InfoWindowFactory be something like:



          namespace YourNamespace;

          abstract class InfoWindowFactory
          {
          public static final function create(
          Place $place,
          Twig_Environment $twig,
          $template
          ) {
          return new InfoWindow($place, $twig, $template);
          }
          }


          Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.



          My comments on MapFactory would be similar to those for the InfoWindowFactory. Namely, I would rather see a class like structured like this:



          namespace YourNamespace;

          use MarkerFactory;
          use InfowindowFactory;

          abstract class MapFactory
          {

          public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
          {
          $map = new Map();

          $map->setCenter($mapCenter);
          $map->setMapOptions($mapOptions);

          $markers = ;

          foreach ($places as $place) {
          $position = new Coordinate($place->getLatitude(), $place->getLongitude());

          $marker = MarkerFactory::create($position);
          $infoWindow = InfoWindowFactory::create($place, $isEditableMap);

          $marker->setInfoWindow($infoWindow);

          $markers = $marker;
          }

          $map->getOverlayManager()->setMarkers($markers);

          return $map;
          }
          }


          A comment about validation...



          You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection or similar, you could be ensured that everything in that collection is a valid Place object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).



          Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map, InfoWindow, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.






          share|improve this answer














          I think your conception of the factory pattern is a little off. Throughout your classes, you seem to want to deal with concrete factory objects, which doesn't seem to make sense. Typically, a factory would be invoked statically and would not store local references (i.e. in properties) to the dependencies it is acting upon.



          Your MarkerFactory class is close, just needing to have create() method defined as static and possibly defining the class itself as abstract since there would not seem to be any reason to ever instantiate it.



          But getting into your other classes, there seem to be issues with where logic lies. The InfoWindowFactory probably should not have a method such as renderWindowContent() on it. That would seem to be a method that should perhaps exist on the InfoWindow itself. Now, if the factory needs to call that method on a concrete window object to get it set up properly before returning it, that might be OK (though I might suggest the InfoWindow constructor is changed to trigger this action).



          I would like to see InfoWindowFactory be something like:



          namespace YourNamespace;

          abstract class InfoWindowFactory
          {
          public static final function create(
          Place $place,
          Twig_Environment $twig,
          $template
          ) {
          return new InfoWindow($place, $twig, $template);
          }
          }


          Note that we are pushing the render operation down into the InfoWindow object where it probably belongs. Also note that we have removed the hard-coded template names from this class. Maybe they truly belong here, in which case maybe they should be class constants rather than buried in a method. But, depending on how you are using these InfoWindows, perhaps this should be passed through as configuration.



          My comments on MapFactory would be similar to those for the InfoWindowFactory. Namely, I would rather see a class like structured like this:



          namespace YourNamespace;

          use MarkerFactory;
          use InfowindowFactory;

          abstract class MapFactory
          {

          public static final function create(Coordinate $mapCenter, array $places = , array $mapOptions = , $isEditableMap = false)
          {
          $map = new Map();

          $map->setCenter($mapCenter);
          $map->setMapOptions($mapOptions);

          $markers = ;

          foreach ($places as $place) {
          $position = new Coordinate($place->getLatitude(), $place->getLongitude());

          $marker = MarkerFactory::create($position);
          $infoWindow = InfoWindowFactory::create($place, $isEditableMap);

          $marker->setInfoWindow($infoWindow);

          $markers = $marker;
          }

          $map->getOverlayManager()->setMarkers($markers);

          return $map;
          }
          }


          A comment about validation...



          You are doing a good job of trying to enforce typehints on your methods, however I do wonder if it might make sense for you to have classes defined which deal with say a collection of Place objects. These seem to be critical dependencies that can only be enforced to be an array via type-hinting, meaning that if you truly wanted to be able to validate that you have valid place objects in your array, you might have to go into undesirable approach of inspecting each array item to validate it. If instead of passing simple array, you passed PlaceCollection or similar, you could be ensured that everything in that collection is a valid Place object. Certainly, this adds yet another bit of code to the overall system, so really only you can determine if it is worthwhile to do this depending on how you are planning to use this code. But it is something to consider when these are key items you are working with (vs. say optional configurations or similar).



          Do you need any error or exception handling here? Typically one of the things a factory would do is raise an exception if the dependencies that are passed are not valid (typehinting can do a lot of this for you) or to handle any underyling exceptions that might happen within method execution (i.e. can instantiation of a Map, InfoWindow, etc. object throw an exception?). I don't really see any consideration here in your code for error or edge conditions. It seems as if this is considering happy path only.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 4 '16 at 15:22

























          answered Nov 4 '16 at 15:05









          Mike Brant

          8,723619




          8,723619












          • Map, Marker, InfoWindow are from 3rd party livb
            – nn4n4s
            Nov 4 '16 at 18:48










          • @nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push the renderWindowContent() logic down into InfoWindow
            – Mike Brant
            Nov 4 '16 at 21:18










          • Are there some other principles that would make this code more testable than static methods?
            – nn4n4s
            Nov 5 '16 at 4:25










          • @nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
            – Mike Brant
            Nov 7 '16 at 2:53


















          • Map, Marker, InfoWindow are from 3rd party livb
            – nn4n4s
            Nov 4 '16 at 18:48










          • @nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push the renderWindowContent() logic down into InfoWindow
            – Mike Brant
            Nov 4 '16 at 21:18










          • Are there some other principles that would make this code more testable than static methods?
            – nn4n4s
            Nov 5 '16 at 4:25










          • @nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
            – Mike Brant
            Nov 7 '16 at 2:53
















          Map, Marker, InfoWindow are from 3rd party livb
          – nn4n4s
          Nov 4 '16 at 18:48




          Map, Marker, InfoWindow are from 3rd party livb
          – nn4n4s
          Nov 4 '16 at 18:48












          @nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push the renderWindowContent() logic down into InfoWindow
          – Mike Brant
          Nov 4 '16 at 21:18




          @nn4n4s That still does not change my thoughts around mivng towards a more staticmethod approach. It would obviously not enable you to push the renderWindowContent() logic down into InfoWindow
          – Mike Brant
          Nov 4 '16 at 21:18












          Are there some other principles that would make this code more testable than static methods?
          – nn4n4s
          Nov 5 '16 at 4:25




          Are there some other principles that would make this code more testable than static methods?
          – nn4n4s
          Nov 5 '16 at 4:25












          @nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
          – Mike Brant
          Nov 7 '16 at 2:53




          @nn4n4s static methods are traditionally hard to unit test in PHP. The are some libraries like AspectMock that provide some unique tooling geared at allowing to better text static methods
          – Mike Brant
          Nov 7 '16 at 2:53


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f146104%2ffactory-hierarchy-for-creating-googlemap-and-its-elements%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Список кардиналов, возведённых папой римским Каликстом III

          Deduzione

          Mysql.sock missing - “Can't connect to local MySQL server through socket”