
ignace
-
Posts
6,457 -
Joined
-
Last visited
-
Days Won
26
Posts posted by ignace
-
-
I understand from your topics and posts in this forum that you have a – how do I say this nicely – rather relaxed attitude towards code quality. OK. This neither surprises nor troubles me.
But the topic is about learning proper OOP, and that's definitely not the right place for your hacks.
Is hardly a technical discussion.
-
I used to use the *Interface suffix until I read this article:
-
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.
-
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; } // .. }
-
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: -
Cheers!
-
1
-
-
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.
-
1
-
-
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.
-
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.
-
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
-
@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.
-
I assume the TFTP server is the CentOS6 server on which you will also host the PHP code?
You can write files with:
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.
-
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.
-
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.
-
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); });
-
$app->add(function ($request, $response, $next) { if(empty($_SERVER['HTTP_X_KEY'])){ http_response_code(422); exit(json_encode(["status"=>"error","code"=>3,"message"=>"Missing key."])); } else { $stmt=$this->db->prepare('SELECT id, timestamp FROM accounts WHERE key=?'); $stmt->execute([$_SERVER['HTTP_X_KEY']]); if(!$this->account=$stmt->fetch(PDO::FETCH_OBJ)){ http_response_code(422); exit(json_encode(["status"=>"error","code"=>3,"message"=>"Invalid key."])); } } $response = $next($request, $response); return $response; });
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); });
-
-
Twig code is compiled into php code, at least when used in a symfony project.
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.
-
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.
-
I wasn't necessarily going to build setters and getters for every single database column. For example, if I have a quote I need to display on the page, I would build a customer object and set all the customer details in that so the getters can retrieve it to display on the page, it's only name, address and phone number. Then I would have a quote object which would set things like the quote price, the quote expiry date and a list of all the upgrade options to show on the quote, along with their attributes like width, height and quantity.
Then when doing purchase orders, I would build a bill of materials (BOM) object that would contain all individual building products and their attributes. Is this wrong? I'm mostly wondering how to separate the model into multiple models because I mainly just have one right now with all the methods in it.
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.
No not at all, I very much appreciate the guidance. If using an ORM library is the proper way to go for medium scaled PHP implementations, then that's what I will use. Just as long as it's better long term and not just short term. I want the best long term solution.
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.
-
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.
-
My understanding is that if you Like the site on Facebook and get your friends to like it, you will get $100 for each of the friends. Plus, you will get another $50 for each of their friends that they get to like the site. You can get up to $50,000 per person. I've checked this out and it's legit. I mean it - it's really real. Oh, wait a sec, maybe it was a free trip for four to Disney World. No that's not it. The truth is that I am a a Nigerian Price that masquerades as as hobbyist programmer and I have US 50,000,000 (fifty million) US dollars tied up in an account that I need assistance in retrieving since I no longer have residence in my home country. I just need you to provide my your bank account information, passwords, social security number and mother's maiden name so that we can transfer the funds into your account. For your trouble, I will give you 10% of the proceeds (five million US dollars). Please keep this confidential and please hurry as time is of the essence.
Ok
Account: BE1474851937
Password: 123giveItToMe
SSN: 011369287
MMN: Sylvia
I always help people out
-
SuperGizmo don't worry it won't
The new owners are more concerned about the well-being of this site
-
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
-
1
-
Naming standards for interfaces
in PHP Coding Help
Posted · Edited by ignace
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.