Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by ignace

  1. Thanks @oni-kun. Good observation about the pattern. I will look into that.
  2. Thank you @requinix. I am afraid it probably is the last one.
  3. 9M[bfv�����������"2<I=0L_nt���������+8@,IOPG:e~��������������$0<(4@LXdp|���������� ,8$0<HT`lx������ �63PQWa,MFk^����ʺ�������$08(4@LXdp|���������� ,8$0<HT`lx��������2D=ZWtU[ePrj������������$0<(4<LXdp|���������� ,8$0<HT`lx����������=Vha^[xy�t�����������$0<(4@LX`p|���������� ,8$0<HT`lx�����������(0BG:x��������������$0<(4@LXdp|���������� ,8$0<HT`lx��������>ENI4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$08Job�������������(4<,8DP\ht�����������$0<(4@LXdp|��������#�Z`j6@<HT`lx�����������(4@,8DP\ht�����������$0<(4@LX`r����������� ,8$0<DT`lx�����������(4@,8DP\ht�����������&K>LfY\jdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht���������!�$0<(4@LXdl|���������� ,8$0<HT`lx�����������(4<.SFt�������������� 0<(4@LXdp|���������� ,8$0<HT`lx��������(B58M@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<DV{n������������(4@(8DP\ht�����������$0<(4@LXdp|���������/"Pj=BLHT`lx�����������(4@,8DP\ht�����������$0<(4@LXdl~���������� ,8$0<HP`lx�����������(4@,8DP\ht����������� 2W*Xrej|p|���������� ,8$0<HT`lx�����������(4@,8DP\ht����˾�&��($0<(4@LXdpx���������� ,8$0<HT`lx�����������(4@(:_R��������������$,<(4@LXdp|���������� ,8$0<HT`lx���������4NAEP,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HPb�z�����������(4@,4DP\ht�����������$0<(4@LXdp|���������5N`YVSpqw�l����ö��,%BOXcr`8DP\hp�����������$0<(4@LXdp|���������� ,8 Qj|u����������*8�7*nibYv}�t�����������$0<(4@LXdp|���������� ,8$0<HT`lt���������D�C6f[jx�}�������������$0<(4@LXdp|���������� ,8$0<HT`lx�������#�=+\6[.rx�mxt�����������$0<(4@LXdp|���������� ,8$0<HT`lx��������89RMHs,8DP\ht|����������$0<(4@LXdp|���������� ,8$,]k������Ϫ����89RMdo@kDP\ht|����������$0<(4@LXdp|���������� ,8$,]k������������7�7*Ulb]r��ht�����������$0<(4@LXdp|���������� ,8$0<HT`lt�����������(4@,8DPXht�����������$0<(4@LXdp|���������� (:?2v|�q�x�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(0BgZdp|���������� ,4$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DPXj������������$0<(4<LXdp|���������� ,8$0<HT`lx�����������C6@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\dt�����������$0<(4@LXdp|���������� ,4&K>HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4<Nsfp|���������� ,8 0<HT`lx�����������(4@,8DP\ht���������'�$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\dv�����������$0<(4@HXdp|���������� ,8$0<HT`lx�����������*OB,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx���ö������(4@,8DP\hp�����������$0<(4@LXdp|���������� ,8 2WJT`lx�����������$4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@HZr|���������� ,8$,<HT`lx�����������(4@,8DP\ht����������3&0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\hp�����������$0<(4@LTdp|���������� ,8$0<HT`lx�����������$6[.8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht|����������$0<(4@LXdp|���������� ,8$,>cV`lx�����������(0@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LTf�~���������� ,8$08HT`lx�����������(4@,8DP\ht�����������?2<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht|����������$0<(4@LX`p|���������� ,8$0<HT`lx�����������(0BG:DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$08Joblx�����������(4<,8DP\ht�����������$0<(4@LXdp|��������#� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LX`r����������� ,8$0<DT`lx�����������(4@,8DP\ht�����������&K>(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdl|���������� ,8$0<HT`lx�����������(4<.SFP\ht����������� 0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<DV{nx�����������(4@(8DP\ht�����������$0<(4@LXdp|���������/",8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdl~���������� ,8$0<HP`lx�����������(4@,8DP\ht����������� 2W*4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht����˾�����$0<(4@LXdpx���������� ,8$0<HT`lx�����������(4@(:_R\ht�����������$,<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HPb�z�����������(4@,4DP\ht�����������$0<(4@LXdp|����������;.8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdpx���������� ,8$0<HT\lx�����������(4@,8DP\ht�����������$,>C6@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,4Fk^ht�����������$08(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT\n������������(4@,8@P\ht�����������$0<(4@LXdp|����������"G:$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`hx�����������(4@,8DP\ht�����������$08*OBLXdp|�����������,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8@Rwjt�����������$0<$4@LXdp|���������� ,8$0<HT`lx���������+�(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`hz�����������(4@,8DL\ht�����������$0<(4@LXdp|�����������.S&0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���Ǻ����� ,8$0<HT`lt�����������(4@,8DP\ht�����������$0<$6[NXdp|���������� (8$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DL^�v�����������$0<(0@LXdp|���������� ,8$0<HT`lx����������7*4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lt�����������(4@,8DPXht�����������$0<(4@LXdp|���������� (:?2<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\ht�����������$0<(0BgZdp|���������� ,4$0<HT`lx�����������(4@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DPXj������������$0<(4<LXdp|���������� ,8$0<HT`lx�����������C6@,8DP\ht�����������$0<(4@LXdp|���������� ,8$0<HT`lx�����������(4@,8DP\dt�����������$0<(4@LXdp|���������� ,4&KWue������������+7CO[GS_kw�����������'3?KWCO[gs����������#/;GS?KWco{�����������+7CO[GS_kw�����������'3?KWCO[ Anyone recognizes the encryption used here? It's part of a file that supposedly would be the database of a program. But I can't work with it. Hoping someone of you recognizes the format.
  4. I am looking for someone that can help me optimize an InnoDB/MariaDB server. There are a few issues that the current server has that I would like someone to have a look at. If you are interested send your resume and hourly and daily rate to innodb-application@cogito.website Put PHPFreaks & InnoDB in the e-mail subject. Thank you.
  5. Okay, let's try something simpler. Say you have this code: <?php declare(strict_types=1); // .. public function setAge(int $age) { $this->age = $age; } Passing a string to this method will throw an exception. The form processing code should validate that the age is indeed a number before passing it to your setAge() method. You can't start accepting "Dave", TRUE, ['foo']['bar'] = 'bat' as age. What I said above is basically the same thing. You protect your model from invalid data. If the business you are writing this software for has other rules, like must be over the age of 18. Then you will need to add additional checks, that his rule is not broken. And this is where you use exceptions. To halt the code from polluting your model. So to answer your question: yes, you must validate the data both in your model and in your form. The reasoning here is that your data might not always come from a form. But perhaps some data is input from a 3rd party API. Or from the CLI. Wherever the data comes from, you can be certain your model will always be valid. If you are too lazy to write out all the exceptions, follow these rules: Use this library: https://github.com/webmozart/assert Write custom value objects like the example in my previous post: BirthDate. Which you can use over and over again. Need another example? <?php class EmailAddress { private $emailAddress; public function __construct(string $emailAddress) { if (!filter_var($emailAddress, FILTER_VALIDATE_EMAIL)) { throw new InvalidArgumentException(sprintf('The e-mail address "%s" is invalid.', $emailAddress)); } $this->emailAddress = $emailAddress; } public function getMailTo(string $subject, string $body): string { return sprintf('mailto:%s?%s', $this->emailAddress, http_build_query([ 'subject' => $subject, 'body' => $body, ])); } public function getEmailAddress(): string { return $this->emailAddress; } } To answer your 2nd question: Don't use exceptions for validation. The code should not be halted at that point, as you want to report back ALL errors at once to the user instead of 1-by-1.And use a format that is most easy to work with like an array to store the validation errors. Also create dedicated validators for your entities. As you might need to validate your entity in more than 1 place. It can still extend from a base generic validator: <?php class LoginValidator extends Validator { public function validate(array $data) { return parent::validate($data, [ 'username', 'password', ]); } }
  6. Yes, your form and any other client-side code should have validation that checks that all business rules (being 18+) have been enforced. Validation and exceptions are not the same thing. Validations are done before you pass it down. While exceptions are thrown after it has been passed down and is invalid. Because your model sits at the center of your application and is guarded with exceptions it becomes impossible to use them with invalid data. Which makes your life as a developer much easier. And anything you add on top adds it's own validation and has it's own method of communicating error's back to the user.
  7. Entities should not have error messages, they should throw exception's on invalid input. Error messages are to indicate to the user that what he input is invalid. Why exceptions? Because your model must be a source of truth, it enforces the business rules. The application (forms, buttons, ui) lies on top of your model. So for the application to communicate effectively with the model it must ensure all input is valid BEFORE the model is called. The exception's are usually called like this in the model: <?php public function setBirthDate(DateTimeInterface $dt) { $this->assertGreaterThanOrEqualTo18($dt); $this->assertLessThan100($dt); $this->birthDate = $dt; } Because you may have these business rules. You can take it one step further: <?php class BirthDate { private $date; public function __construct(DateTimeInterface $date) { $this->assertGreaterThanOrEqualTo18($date); $this->assertLessThan100($date); $this->date = $date; } } public function setBirthDate(BirthDate $bd) { $this->birthDate = $bd; } Now every time you use a birthdate you will apply the business rules.
  8. 1) Let the view do a sub-request to the header controller to load the menu. 2) Create a view helper that loads the menu. Both will require the current route to determine which hierarchy to load/show.
  9. If you have a monetary income in any officially recognized currency*, you need to pay tax! It's that simple, really. Now it's possible that certain income is exempt from tax, for example, a yearly turn-over less then 5.000 individually, or 25.000 as a business. That's the current law in Belgium. I am not an accountant, and I am unfamiliar with tax regulations in Australia. If you have a business, it's recommended to have an accountant, he'll advise you on the best approach, and keep your taxes in check. *So anything not monetary, or any unofficial currency, would be tax-free. Get paid in litecoin?
  10. Nope, they don't. At least not in my case, others may have had better luck. I was only joking when I said that. I am already happy if I get a thumbs up on my answers.
  11. Admin seems more like a privilege/role, so I would make that a field of User. Then your User and Person. I get what you are saying, and I have this in my system. I would have a Person object with no reference to a User. And let the User reference Person. Thus decoupling my application from the auth layer. <?php class User { const ROLE_SYSTEM = 'role_system'; const ROLE_ADMIN = 'role_admin'; /** * @var string[] */ private $roles = [ ]; /** * @var Person|null */ private $person; } For system accounts, the Person reference would be NULL as it's not required and it's role would be ROLE_SYSTEM.
  12. And after you started using the power sander, how often have you done it by hand since? And if given the chance to do it by hand, would you still do it? Regardless of the fact that these are apples and oranges. If done by hand or machine delivers about the same end-product. Regardless with which you started or ended. You can start by hand, go to the machine, and finish by hand. Also the work still has to be done, to get the final product. This is not the case in software development. You would basically pick up an already sanded object of any length and any given size in an infinite supply.
  13. Events are a good way to extend your code without adding unnecessary dependencies. A ghost copy is a class with only it's ID filled in. Personally I avoid writing things that have been written before and rather build upon them. In the long run of an application you get burned by the "not invented here" syndrome. I have seen it over and over, and over again.
  14. What requinix said, and to reduce unnecessary: querying, hydrating, etc.. for what is essentially throwing something into the bin. And it still allows your mapper to fire off any associated events, if there would be any. Another option would be to use a ghost copy, and drop the deleteOneById. But that depends on how you architect your software. Since a DELETE is the opposite of a SELECT. You can create any "query" methods for it: deleteAllByCompanyName(string $companyName); Internally they do the same thing as with the deleteOneById. They query and store any ID's scheduled for deletion. So that any future find's would return NULL even before the database is synchronised. Avoid any createFromArray or updateFromArray methods though, use the find methods instead.
  15. For a Data Mapper this is mixed. Since your mapper maps from and to the database. You would need to be able to use several types of input to get what you need. <?php interface UserMapper { function findOneById(int $id): ?User; function findAllById(array $id): ?UserCollection; function findOneByUsernameAndEmail(string $username, string $email): ?User; function findAllRegisteredBetween(DateTimeInterface $start, DateTimeInterface $end): ?UserCollection; function findAllRecentlyRegistered(DateTimeInterface $currentDate): ?UserCollection; function create(User $user): void; function createAll(UserCollection $users): void; function update(User $user): void; function updateAll(UserCollection $users): void; function delete(User $user): void; function deleteAll(UserCollection $users): void; function deleteOneById(int $id): void; }
  16. And that's bad? Why? Ever seen classes implement nothing more than __invoke? Or a Command with only an execute() method. What about 2 methods? How many methods should in your opinion a class have?
  17. Properties are like your intestines, you don't want anyone else to touch them. Unless, perhaps for surgery (my architect mind is already modelling this, I'll spare you the details). Therefor they should always be private. If something does need access, they can use an interface you control. In certain cases you could opt to mirror methods instead of exposing the sub-object, but it's certainly not advisable to mirror the entire interface. In this case, just create a getter. But don't ever expose a public property, you are inviting bugs. PHP does not yet have the powers other OO languages have.
  18. Well, pretty much everyone on here has a "Donate to me!" button so go ahead and buy us all a round Congrats on the promotion!
  19. Yes, preferably it should always be the responsibility of another class unless the domain warrants the use of JsonSerializable. For example, the object is stored/read from a JSON store.
  20. No I am not, though it's a good thing to always start from final class, as it will make you think harder about your code. That said, I extend my entity classes every time there's a need. Protected properties and inheritance are two separate things anyway. A protected property is a "public" property in disguise, just think about that for a second. Why would a child have privileged access to "private" information? If there is a need to give privileged information to a child then you can still resort to a protected method. This will ensure the data remains encapsulated. Is available to the child as a sort of contract (guaranteed access to the data). And allows the parent to change properties anyway they want (eg from a string to an object).
  21. With that said, perhaps you don't want to expose all properties. In that case you can also resort to using a Visitor <?php interface NodeVisitor { function visitNode(Node $node); function visitCategory(CategoryNode $node); // ... } final class Node { function accept(NodeVisitor $nodeVisitor) { $nodeVisitor->vistNode($this); foreach ($this->categories as $category) { $nodeVistor->visitCategory($category); } } } $node->accept($myNodeVisitor); $json = $myNodeVisitor->getResult(); This is of course a little more difficult then using a simple serializer.
  22. Move the logic of serializing out of your entities. It does not belong there, nor should your properties be protected, they should be private. Only if absolutely necessary, can they be protected. And even then you can still create a protected getter/setter of some sort. I already posted how to do the serializing in your other thread. <?php interface NodeSerializer { function serialize(Node $node); function unserialize($input, Node $node); } With this you can create as many 'views' as you need.
  23. Entity fields should be private, not protected (extend is not a good reason), and certainly not public. Instead use getters/setters. Converting the object to JSON should be left to a separate class, preferably this new class should define an interface. Example given: <?php interface NodeMapper { public function map(Node $node); public function reverseMap($output): Node; } final class JsonMapper implements NodeMapper { public function map(Node $node) { // bla bla return json_encode($nodeMapArray); } public function reverseMap($output): Node { $foo = json_decode($output); return new Node(..); } } You can take it a step further: <?php final class NodeToJsonMapper { function map(Node $node): StdClass { // bla bla return json_encode($nodeData); } } final class JsonToNodeMapper { function map(StdClass $json): Node { // bla bla return new Node(..); } }
  24. I'm going to quote myself from your other thread: I use the same process kicken uses. Keep it simple, above all else. Software means nothing, if it's filled with fancy terms, and none of your co-workers can maintain it.
  • 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.