Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dependency injection to MySqlDatabase, and MySqlProperties #924

Merged
merged 39 commits into from
Dec 13, 2020

Conversation

XaeroDegreaz
Copy link
Collaborator

closes #922

…t for retrieving accounts via account id using a mock mysql object
…ields when retrieving account. initial attempt at getting travis to run unit tests
… integration tests with database.

added travis config for launching test test mysql instance in order to run integration tests. no clue if it's gonna work yet, though
…s a test, and fails with a warning that there are no test functions in the file.
…hould get rid of any type hinting warnings from scrutinizer.
# Conflicts:
#	.travis.yml
#	composer.json
#	docker-compose.yml
#	lib/Default/MySqlDatabase.class.php
#	phpunit.xml
#	test/SmrTest/BaseIntegrationSpec.php
# Conflicts:
#	.env.sample
#	.travis.yml
#	composer.json
#	docker-compose.yml
#	engine/Default/game_play.php
#	engine/Default/history_alliance_detail.php
#	engine/Default/history_games.php
#	engine/Default/history_games_detail.php
#	engine/Default/history_games_hof.php
#	engine/Default/history_games_news.php
#	lib/Default/MySqlDatabase.class.php
#	lib/Default/SmrMySqlDatabase.class.php
#	phpunit.xml
#	test/SmrTest/BaseIntegrationSpec.php
tools/irc/server.php Outdated Show resolved Hide resolved
Copy link
Member

@hemberger hemberger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks okay in general so far, though the benefits are not manifestly obvious to me yet. I see how the containers are being used in the tests, and that is nice, but I feel like I've done the same sort of mocking in python, for example, without needing IoC/DI (since these techniques are sometimes too heavyweight for simple programs).

Practically speaking, the MySqlDatabase class is now certainly more "pure", but it is also less clear to me how it interacts with the rest of the codebase. The static mysqli attribute in comparison is quite straightforward.

The design looks solid though. Happy to continue with this effort and see what we look like on the other side!

htdocs/login.php Outdated Show resolved Hide resolved
lib/Default/MySqlDatabase.class.php Outdated Show resolved Hide resolved
lib/Default/SmrSession.class.php Outdated Show resolved Hide resolved
lib/Smr/Container/DiContainer.php Outdated Show resolved Hide resolved
lib/Smr/Container/DiContainer.php Show resolved Hide resolved
lib/Smr/Container/DiContainer.php Show resolved Hide resolved
lib/Smr/Container/DiContainer.php Show resolved Hide resolved
lib/Smr/Container/DiContainer.php Show resolved Hide resolved
@XaeroDegreaz XaeroDegreaz force-pushed the 922-php-di-mysqldatabase branch from c47cefd to 50c6b56 Compare November 22, 2020 19:49
@XaeroDegreaz XaeroDegreaz force-pushed the 922-php-di-mysqldatabase branch from 50c6b56 to 42b6535 Compare November 22, 2020 21:08
@codecov
Copy link

codecov bot commented Nov 22, 2020

Codecov Report

Merging #924 (bb5d38c) into master (613786e) will increase coverage by 0.74%.
The diff coverage is 39.08%.

Impacted file tree graph

@@             Coverage Diff             @@
##             master    #924      +/-   ##
===========================================
+ Coverage      1.58%   2.33%   +0.74%     
- Complexity     4061    4074      +13     
===========================================
  Files            60      60              
  Lines         10157   10196      +39     
===========================================
+ Hits            161     238      +77     
+ Misses         9996    9958      -38     
Impacted Files Coverage Δ Complexity Δ
lib/Album/album_functions.php 0.00% <0.00%> (ø) 0.00 <0.00> (ø)
lib/Default/AbstractSmrLocation.class.php 0.00% <0.00%> (ø) 112.00 <0.00> (ø)
lib/Default/AbstractSmrPlayer.class.php 0.00% <0.00%> (ø) 658.00 <0.00> (ø)
lib/Default/AbstractSmrPort.class.php 0.00% <0.00%> (ø) 277.00 <0.00> (ø)
lib/Default/AbstractSmrShip.class.php 0.00% <0.00%> (ø) 261.00 <0.00> (ø)
lib/Default/ChessGame.class.php 0.00% <0.00%> (ø) 247.00 <0.00> (ø)
lib/Default/Council.class.php 0.00% <0.00%> (ø) 10.00 <0.00> (ø)
lib/Default/DummyPlayer.class.php 0.00% <0.00%> (ø) 11.00 <0.00> (ø)
lib/Default/DummyShip.class.php 0.00% <0.00%> (ø) 13.00 <0.00> (ø)
lib/Default/Globals.class.php 0.00% <0.00%> (ø) 117.00 <0.00> (ø)
... and 21 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 613786e...bb5d38c. Read the comment docs.

Copy link
Member

@hemberger hemberger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking great! I have some minor suggestions & requests, but I think there's also one bug that needs to be sorted out. Please see my comments below, and let me know if you have any questions. Thanks!

lib/Default/MySqlDatabase.class.php Outdated Show resolved Hide resolved
lib/Default/MySqlDatabase.class.php Show resolved Hide resolved
docker-compose.yml Outdated Show resolved Hide resolved
lib/Default/MySqlDatabase.class.php Show resolved Hide resolved
lib/Default/MySqlDatabase.class.php Show resolved Hide resolved
lib/Smr/Container/DiContainer.php Show resolved Hide resolved
lib/Smr/Container/DiContainer.php Outdated Show resolved Hide resolved
* @throws \DI\NotFoundException
*/
private static function ensureConnected(MySqlDatabase $mysqlDatabase): MySqlDatabase {
if (!isset($mysqlDatabase->dbConn)) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that I'm thinking about this, I can probably just get away with calling DiContainer::initialize() to reset the whole container. If not, then in the future after things are retrieving services through the container, they could end up with a defucnt transient MySqlDatabase instance if the connection is ever closed. That would be a lot of manual checks everywhere to make sure reconnect logic is triggered.

I think it's not a big deal since only those CLI apps are using the close method, but once the migration starts happening where they don't access db directly, but through domain services, this could be a problem. Maybe just reset the entire DI container for those CLI apps instead of having this reconnect logic.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What you have set up now looks like it reproduces the existing behavior. But I agree that avoiding a defunct MySqlDatabase instance is probably more robust (especially if future abstraction layers would make misuse easier). However, a few questions I don't have answers for off the top of my head:

What would DiContainer::initialize() do to the existing connection? Would it try to close it (if so, might this throw if the connection has timed out)? Or would it leave it open (if so, might this result in a proliferation of open database connections)?

Also, it's important to keep in mind that not all CLI events even need a connection to the database, so I'm not exactly sure where a DiContainer::initialize() would go (if we're trying to be as efficient as possible). There are plenty of "reasonable" places to put it, though!

So I'm happy to leave this as-is for now, but if you want to look for a better solution, that's fine with me too.

@XaeroDegreaz XaeroDegreaz marked this pull request as ready for review December 13, 2020 10:53
@hemberger hemberger merged commit fc4bd93 into smrealms:master Dec 13, 2020
hemberger added a commit that referenced this pull request Dec 13, 2020
The `SmrShip::checkPowerLevel` function was erroneously re-added
during merge conflict resolution. It is now removed again.
@hemberger
Copy link
Member

This is merged now. Thanks for your contribution (and your patience)!

@XaeroDegreaz XaeroDegreaz deleted the 922-php-di-mysqldatabase branch December 13, 2020 21:46
hemberger added a commit that referenced this pull request Dec 18, 2020
Fixes a bug with overlapping queries clobbering previous results.

The old SmrMySqlDatabase had a non-static `$dbResult`, so any call to
`new SmrMySqlDatabase()` would have a new `$dbResult`. However, the
original design of `MySqlDatabase::getInstance` from #924 shared a
`$dbResult` (due to the shared MySqlDatabase from the DI container),
which caused query results to be overwritten if another query was made
while processing the results of the first query. The global variable
`$db` is kind of what `MySqlDatabase::getInstance` was supposed to be.

We now only use `getNewInstance` (which has been renamed `getInstance`
to reduce the footprint of the diff). To handle the reconnection logic
for CLI programs, we set the `mysqli` instance in the DI container to
null, and then reconnect in the MySqlDatabase ctor if it is passed a
null `$dbConn` (since there is no known way to "unset" an entry in the
DI container so that it is regenerated on-demand the next time it is
requested).

Co-authored-by: Dan Hemberger <[email protected]>
hemberger added a commit that referenced this pull request Dec 18, 2020
hemberger added a commit to hemberger/smr that referenced this pull request Mar 20, 2021
In smrealms#924, the `$dbConn` property was changed so that it is unset when
`close()` is called instead of being set to `false`. Therefore, when
we call `close()` on an already closed MySqlDatabase instance, we need
to perform an `isset` check on `$dbConn` instead of a boolean check.

This fix allows us to make repeated calls to `close()` again, and we
add a test to ensure this functionality.

Note that this impacted the IRC bot, which will make repeated calls to
close without reconnecting to the database if it processes an event
that doesn't require the database.
hemberger added a commit that referenced this pull request Mar 20, 2021
In #924, the `$dbConn` property was changed so that it is unset when
`close()` is called instead of being set to `false`. Therefore, when
we call `close()` on an already closed MySqlDatabase instance, we need
to perform an `isset` check on `$dbConn` instead of a boolean check.

This fix allows us to make repeated calls to `close()` again, and we
add a test to ensure this functionality.

Note that this impacted the IRC bot, which will make repeated calls to
close without reconnecting to the database if it processes an event
that doesn't require the database.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Start using PHP-DI to manage class dependencies starting with MySqlDatabase class
2 participants