Jump to content

ignace

Moderators
  • Posts

    6,457
  • Joined

  • Last visited

  • Days Won

    26

Everything posted by ignace

  1. Sure a few of his examples are a little far-fetched. I have never had the trouble distinguishing between what a Translator is or what a TranslatorInterface does. I think SerializeToJson is a good descriptive name for the interface as would JsonSerializable I imagine. But again this is probably a bad example because an object should not be aware of what JSON is nor how it "serializes" itself to it. It gives you something to think about though the next time you develop a system. Proper naming is always half the battle. Even though I prefer to write an interface without the suffix on small (individual) and private projects, on big projects I tend to stick to "open-source" standards and that means *Interface suffix, *Trait suffix, and Abstract* prefix. This makes it easier to work together, and publish libraries.
  2. Is hardly a technical discussion.
  3. I used to use the *Interface suffix until I read this article: http://verraes.net/2013/09/sensible-interfaces/
  4. It doesn't know that's the entire point. someCodeThatCanDumpThings(VarDumper $dumper) The only thing that this function/method knows is that it can call $dumper with a method dump() which has certain arguments. The implementation details however it is unaware of. If this is to HTML or CLI or SOAP. It doesn't actually care. Through dependency injection you'll define what the implementation is going to be for the VarDumper interface.
  5. You can also pass the IP address as a constructor argument. Decoupling your class from the globals. If you use dependency injection it's even easier to do. Mind that when you are behind a proxy getting the IP address is not as simple as querying REMOTE_ADDR which further warrants the need for injection. class LoginAttemptsLog { /** * @var PDO the connection to the underlying database */ protected $database; /** * @var string */ protected $ipAddress; /** * @param PDO $database the connection to the underlying database * @param string $ipAddress the IP of the user */ public function __construct(PDO $database, $ipAddress) { $this->database = $database; $this->ipAddress = $ipAddress; } // .. }
  6. Kinda, it would be something like: class Quote { private $id; // .. other fields private $price; public function setId($id) { $this->id = $id; } public function getId() { return $this->id; } // get*, set* for the other fields public function setPrice($price) { $this->price = $price; } public function getPrice() { return $this->price; } }Then you would create a query and populate this object: $sql = 'SELECT id, .., price FROM quotes'; $stmt = $this->db->prepare($sql); foreach ($stmt->fetchAll() as $row) { $quotes[] = $quote = new Quote; $quote->setId($row['id']); $quote->setPrice($row['price']); } return $quotes;At this point you can work with this object as: $quote->getId(); $quote->getPrice();Now before you start writing all of this yourself, there are frameworks available online that do this sort of thing for you. A list can be found here:https://github.com/ziadoz/awesome-php#database
  7. What you should do though, is set up an auto-response for the noreply address. So that anyone who does decide to mail that address is informed of their mistake.
  8. ignace

    MVC

    I do not encourage building a full production site from my example code merely use it to understand MVC. Once you do, it is recommended to use a framework to learn the finer points of programming and modern programming techniques since MVC is only a small part of building a web application. Other terms you will cross are Object-Oriented Programming, Dependency Injection, Object-Relational Mapping, Design Patterns (Factory, Repository, ..), .. To come back at your example: class Model { private $pdo; function __construct() { $this->pdo = Database::getInstance(); } function fetchImages() { $st = $this->pdo->prepare("SELECT * FROM GALLERY"); $st->execute(); return $st->fetchAll(); } } You will NEVER have a class called Model. Programming is all about assigning responsibility and proper naming. Naming is actually the hardest part of the job. So the responsibility of your "Model" is to: - return a list of gallery images - add / delete a gallery image So let's settle for now on GalleryManager: interface GalleryManager { public function addImage(GalleryImage $image); public function removeImage(GalleryImage $image); public function getAll(); } At some point we may want to use something different than PDO (Doctrine, Eloquent, ..) to query for our images so we define our manager as an interface. Now for our PDO implementation: class PdoGalleryManager implements GalleryManager { private $pdo; public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function getAll() { // your code here } public function addImage(GalleryImage $image) { // your code here } public function removeImage(GalleryImage $image) { // your code here } } We also pass PDO through the constructor and not use a Singleton to fetch it to make it easier to test.
  9. ignace

    MVC

    Look, in short, this is how it works: MVC is a concept divided in three keywords, but each keyword covers a LOT in code. Your Model does all the work. Now the Model is not ONE thing, it's everything that is associated with your business logic. Queries, DAO's, Services, Repositories, Factories, Entities, ... Your View only handles presentation. The View is ALSO not ONE thing, it's everything that handles presentation. By presentation I mean in the case of a web application is HTML. Your Controller has actually no real task, but is required to handle a request, since neither the Model nor View are able (nor should they) to do this. Your header and footer are part of the View and this should be handled in the View. A popular approach is the '2-step View' to this problem: http://martinfowler.com/eaaCatalog/twoStepView.html You can of course use a simpler method if needed, for example: views/gallery/index.php <?php require APP_VIEW_DIR . '/header.php'; ?> <!-- Your content here --> <?php require APP_VIEW_DIR . 'footer.php'; ?> When people first encounter MVC they imagine something very complicated while it's actually really simple: models/gallery/getAll.php <?php $db = require APP_MODEL_DIR . '/db.php'; $stmt = $db->prepare('SELECT * FROM gallery'); return $stmt->fetchAll(); controllers/gallery/index.php <?php $images = require APP_MODEL_DIR . '/gallery/getAll.php'; require APP_VIEW_DIR . '/gallery/index.php'; To make this work you need a "Front Controller", what this means is a Controller that is called first. In Java this is the project class with the main() method. For web applications this is whatever file you tell nginx/apache to load as default, usually index.php <?php define('APP_CONTROLLER_DIR', __DIR__ . '/controllers'); define('APP_MODEL_DIR', __DIR__ . '/models'); define('APP_VIEW_DIR', __DIR__ . '/views'); define('APP_CONFIG_DIR', __DIR__ . '/config'); require APP_MODEL_DIR . '/functions/request.php'; $page = get('page', 'home'); switch ($page) { case 'gallery': require APP_CONTROLLER_DIR . '/gallery/index.php'; break; default: case 'home': require APP_CONTROLLER_DIR . '/home/index.php'; break; } Try to wrap your head around this. You'll see my model is only concerned with model stuff, the view only with view stuff, and the controller just puts the pieces together. This is also true in every framework though it may seem a lot more complicated there.
  10. ignace

    MVC

    It's kinda correct. Your main controller actually should call the gallery controller, not some view. Inside the controller you would load the view. Something like: <?php $page = !empty($_GET['page']) ? $_GET['page'] : null; switch ($page) { case 'gallery': $controller = new GalleryController(); break; default: $controller = new HomeController(); break; } // do something with $controller
  11. @kicken I tried Laravel recently 5.3 and the same things that bugged you, still bug people. PHPStorm does not understand Laravel with all their facades. They claim they love beautiful code but then go on to do something like: https://laravel.com/docs/5.3/session#registering-the-driver Create an entire new class to simply call a static method on another? Is this something we want to promote? Their expressive interfaces are nice though. And it comes with a lot of functionality out of the box. Where you would need quite a few bundles in Symfony to have the same functionality.
  12. I assume the TFTP server is the CentOS6 server on which you will also host the PHP code? You can write files with: file_put_contents You can read the file with: file use explode to separate Button6 and BLF, and Button6value and 103. At this point you have the data from the file in an array and you can generate an interface for the user to change the function of each button.
  13. No, your response classes should not throw exceptions. My previous post was the answer to why you would want to use multiple response classes for your error responses, nothing more. The doHandle401() etc.. was an example to show the difference between bad designed code and good code using exceptions as an example.
  14. Why would you want to have custom exception classes while you can perfectly use Exception everywhere? try { somethingHere(); } catch (Exception $e) { switch ($e->getCode()) { case 400: doHandle400(); break; case 401: doHandle401(); break; case 405: doHandle405(); break; } } // versus try { somethingHere(); } catch (GenericErrorException $e) { doHandle400(); } catch (UnsupportedMethodErrorException $e) { doHandle405(); } // .. It all boils down to good design. Sure you can do this: return $response->withJson(\MyApp\ErrorResponse::missingKey(), 401);But it does not reflect what you want to do, from a design point-of-view. It may also lead to inconsistencies using 401 here and 400 there. If at some point you want to add custom headers to your errors, you will have to hunt down all uses of ErrorResponse and edit the $response accordingly. Using a class and inheritance avoids duplication and a single point to be edited in case your requirements change.
  15. I have never used Slim before, I have however dabbled with StackPHP. But from reading the documentation I was able to concoct the above example. Regarding ErrorResponse::missingKey() and new MissingKeyErrorResponse() I was of course referring to a parent object containing the error structure which MissingKeyErrorResponse expands upon. class MissingKeyErrorResponse extends AbstractErrorResponse { public function __construct() { parent::__construct(3, 'Missing Key.'); } }Then for the rest of your code, which can be drastically improved: $container['accounts'] = function ($c) { return new \MyApp\Accounts($c['db']); // <-- instead of passing it to EVERY method }; namespace MyApp; class Accounts { private $db; public function __construct($db) { $this->db = $db; } // <-- construction injection FTW public function findOneByKey($key) // <-- proper naming { $stmt=$db->prepare('SELECT id,name FROM accounts WHERE main_key=?'); $stmt->execute([$key]); return $stmt->fetch(\PDO::FETCH_OBJ); } } $app->add(function(Request $request, Response $response, $next) use ($container) { $key = $request->getHeaderLine('X-MyApp-Key'); if (empty($key)) { return new MissingKeyErrorResponse(); // <-- proper response generated } $account = $this->accounts->findOneByKey($key); if (!$account) { return new InvalidKeyErrorResponse(); } $container['account'] = function() use ($account) { return $account; } return $next($request, $response); });If you have a real crush on static methods try this: class ErrorResponseRegistry { public static function missingKey() { return new MissingKeyErrorResponse(); } public static function invalidKey() { return new InvalidKeyErrorResponse(); } } $app->add(function(Request $request, Response $response, $next) use ($container) { $key = $request->getHeaderLine('X-MyApp-Key'); if (empty($key)) { return ErrorResponseRegistry::missingKey(); // <-- proper response generated } $account = $this->accounts->findOneByKey($key); if (!$account) { return ErrorResponseRegistry::invalidKey(); } $container['account'] = function() use ($account) { return $account; } return $next($request, $response); });
  16. I think the main thing you need is starting to learn/read the manual. Why use a framework if you are writing plain PHP anyway? $app->add(function(ServerRequestInterface $request, ResponseInterface $response, $next) use ($container) { $key = $request->getHeaderLine('X-Key'); if (empty($key)) { return new MissingKeyResponse(); // <-- correct format across the entire application. } $account = $container->accountRepository->findOneByKey($key); if (!$account) { return new InvalidKeyResponse(); // <-- correct format across the entire application. } return $next($request, $response); });
  17. It's always compiled to PHP. When debug is enabled, it's re-compiled on each load. Turn debug off during development and none of your changes will come trough.
  18. You would construct full objects at all times. Only load (objects) what you need for each request. If you are going to display a qoute to the user, load all quote data.
  19. No, that is correct DeX. Though like Jacques1 mentioned an ORM like Doctrine allows you to generate most of your code. If you use a decent IDE you might have that option too. You'll have an ORM whatever way you turn it. If you use OO then you need an ORM in one form or another. You either use Doctrine or write your own Mapper. Doctrine might be even more efficient then your own Mapper code as the project grows. Experience teaches you if a project is small or medium and will remain this way.
  20. Symfony has the highest survavibility since it's adoption into other popular frameworks like Drupal. Laravel is a good second. I would avoid other full-stack frameworks and only use their components.
  21. Ok Account: BE1474851937 Password: 123giveItToMe SSN: 011369287 MMN: Sylvia I always help people out
  22. SuperGizmo don't worry it won't The new owners are more concerned about the well-being of this site
  23. As already said. A session will be started by reading, writing, or even checking the session. http://symfony.com/doc/current/cookbook/session/avoid_session_start.html
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.