Skip to content

Commit c2a5330

Browse files
Merge pull request #77 from josephmancuso/serviceprovider
added better service container support. Performed MAJOR architectural changes
2 parents 4ed1e16 + f127320 commit c2a5330

19 files changed

+249
-242
lines changed

.env-example

+11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ APP_DEBUG=true
44
APP_LOG_LEVEL=debug
55
KEY=your-secret-key
66

7+
MAIL_DRIVER=smtp
8+
MAIL_FROM_ADDRESS=
9+
MAIL_FROM_NAME=
10+
MAIL_HOST=
11+
MAIL_PORT=
12+
MAIL_USERNAME=
13+
MAIL_PASSWORD=
14+
15+
MAILGUN_SECRET=
16+
MAILGUN_DOMAIN=
17+
718
DB_DRIVER=mysql
819
DB_HOST=127.0.0.1
920
DB_PORT=3306

ISSUE_TEMPLATE.md

-2
This file was deleted.
+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
''' A Module Description '''
22
from masonite.view import view
3-
from config import application
3+
from masonite.request import Request
44

55
class WelcomeController(object):
66
''' Controller for welcoming the user '''
77

88
def __init__(self):
99
pass
1010

11-
def show(self):
11+
def show(self, Application, request: Request):
1212
''' Show Welcome Template '''
13-
return view('welcome', {'app': application})
13+
return view('welcome', {'app': Application})

app/http/middleware/LoadUserMiddleware.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
11
''' Class for the authentication middleware '''
22
from masonite.facades.Auth import Auth
3+
from masonite.request import Request
34

45
class LoadUserMiddleware(object):
56
''' Middleware class which loads the current user into the request '''
67

7-
def __init__(self, request):
8-
self.request = request
8+
def __init__(self):
9+
pass
910

10-
def before(self):
11+
def before(self, request: Request):
1112
''' Register as a before middleware to be ran before the request '''
12-
self.load_user(self.request)
13-
return self.request
13+
self.load_user(request)
14+
return request
1415

1516
def after(self):
1617
''' Register as an after middleware to be ran after the request '''

app/providers/MiddlewareProvider.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
''' A MiddlewareProvider Service Provider '''
2+
from masonite.provider import ServiceProvider
3+
from config import middleware
4+
5+
class MiddlewareProvider(ServiceProvider):
6+
7+
wsgi = False
8+
9+
def register(self):
10+
self.app.bind('HttpMiddleware', middleware.HTTP_MIDDLEWARE)
11+
12+
def boot(self):
13+
pass

app/providers/UserModelProvider.py

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
class UserModelProvider(ServiceProvider):
55
''' Binds the User model into the Service Container '''
66

7+
wsgi = False
8+
79
def register(self):
810
self.app.bind('User', User)
911

bootstrap/start.py

+54-164
Original file line numberDiff line numberDiff line change
@@ -1,168 +1,58 @@
11
''' Start of Application. This function is the gunicorn server '''
2-
import os
3-
import re
4-
5-
# Load environment variable from .env file
6-
from dotenv import find_dotenv, load_dotenv
7-
load_dotenv(find_dotenv())
8-
9-
from masonite.request import Request
10-
from masonite.routes import Route
11-
from masonite.storage import Storage
12-
from masonite.app import App
13-
from config import middleware, application
142
from pydoc import locate
153

16-
17-
# Run once and only once the server is ran
18-
# This will not actually compile if the libsass module in not installed
19-
Storage().compile_sass()
20-
214
def app(environ, start_response):
22-
''' Framework Engine '''
23-
os.environ.setdefault('REQUEST_METHOD', environ['REQUEST_METHOD'])
24-
os.environ.setdefault('URI_PATH', environ['PATH_INFO'])
25-
26-
# Instantiate the Service Container
27-
app = App()
28-
29-
# Instantiate the Request object.
30-
# This is the `request` object passed into controller methods
31-
request = Request(environ)
32-
33-
# Bind the Request object into the container
34-
app.bind('Request', request)
35-
36-
# Execute all the register methods in all containers
37-
for provider in application.PROVIDERS:
38-
locate(provider)().load_app(app).register()
39-
40-
# Execute all the boot methods in all containers
41-
for provider in application.PROVIDERS:
42-
app.resolve(locate(provider)().boot)
43-
44-
# Load the container into the request
45-
app.make('Request').load_app(app)
46-
47-
router = Route(environ)
48-
49-
if router.is_post():
50-
# Set POST parameters given into the query string to centralize parsing and retrieval.
51-
# This was made to directly support the Request.input() method.
52-
# There is no known reason to differentiate between GET and POST when retrieving
53-
# form paramters. This line below simply puts both POST form params in the
54-
# same query_string as GET params.
55-
environ['QUERY_STRING'] = router.set_post_params()
56-
57-
# Get all routes from the routes/web.py file
58-
import routes.web
59-
routes = routes.web.ROUTES
60-
61-
# Check all http routes
62-
for route in routes:
63-
# Compiles the given route to regex
64-
regex = router.compile_route_to_regex(route)
65-
66-
# Make a better match trailing slashes `/` at the end of routes
67-
# Sometimes a user will end with a trailing slash. Because the
68-
# user may create routes like `/url/route` and `/url/route/`
69-
# and how the regex is compiled down, we may need to adjust for
70-
# urls that end or dont end with a trailing slash. This is sort
71-
# of a quirk and could possibly be fixed.
72-
if route.route_url.endswith('/'):
73-
matchurl = re.compile(regex.replace(r'\/\/$', r'\/$'))
74-
else:
75-
matchurl = re.compile(regex.replace(r'\/$', r'$'))
76-
77-
# This will create a dictionary of paramters given. This is a sort of a short
78-
# but complex way to retrieve the url paramters. This is the code used to
79-
# convert /url/@firstname/@lastname to {'firstmane': 'joseph', 'lastname': 'mancuso'}
80-
try:
81-
parameter_dict = {}
82-
for index, value in enumerate(matchurl.match(router.url).groups()):
83-
parameter_dict[router.generated_url_list()[index]] = value
84-
request.set_params(parameter_dict)
85-
except AttributeError:
86-
pass
87-
88-
# If the route url matches the regex and the method type and the route can continue
89-
# (will be used with middleware later)
90-
if matchurl.match(router.url) and route.method_type == environ['REQUEST_METHOD'] and route.continueroute is True:
91-
92-
# Execute HTTP Before Middleware
93-
for http_middleware in middleware.HTTP_MIDDLEWARE:
94-
located_middleware = locate(http_middleware)
95-
if hasattr(located_middleware, 'before'):
96-
located_middleware(request).before()
97-
98-
# Show a helper in the terminal of which route has been visited
99-
print(route.method_type + ' Route: ' + router.url)
100-
101-
# Loads the request in so the middleware specified is able to use the
102-
# request object. This is before middleware and is ran before the request
103-
route.load_request(request).run_middleware('before')
104-
105-
# Get the data from the route. This data is typically the output
106-
# of the controller method
107-
if not request.redirect_url:
108-
data = router.get(route.route, app.resolve(route.output))
109-
110-
# Loads the request in so the middleware specified is able to use the
111-
# request object. This is after middleware and is ran after the request
112-
route.load_request(request).run_middleware('after')
113-
114-
# Execute HTTP After Middleware
115-
for http_middleware in middleware.HTTP_MIDDLEWARE:
116-
located_middleware = locate(http_middleware)
117-
if hasattr(located_middleware, 'after'):
118-
located_middleware(request).after()
119-
break
120-
else:
121-
data = 'Route not found. Error 404'
122-
123-
## Check all API Routes
124-
if data == 'Route not found. Error 404':
125-
# Look at the API routes files
126-
import routes.api
127-
routes = routes.api.ROUTES
128-
129-
for route in routes:
130-
131-
# If the base url matches
132-
if route.url in router.url:
133-
data = route.fetch(request).output
134-
if data:
135-
break
136-
else:
137-
data = 'Route not found. Error 404'
138-
else:
139-
data = 'Route not found. Error 404'
140-
141-
# Set redirection if a route has been called to redirect to.
142-
# redirect_route is a property set on the request object when
143-
# methods like request.redirectTo('nameRoute') are called
144-
if request.redirect_route:
145-
for route in routes:
146-
if route.named_route == request.redirect_route:
147-
print(route.method_type + ' Named Route: ' + router.url)
148-
data = router.get(route.route, route.output(request))
149-
request.redirect_url = route.route_url
150-
151-
if not request.redirect_url:
152-
# Convert the data that is retrieved above to bytes so the wsgi server can handle it.
153-
data = bytes(data, 'utf-8')
154-
155-
# Normal HTTP response.
156-
start_response("200 OK", [
157-
("Content-Type", "text/html; charset=utf-8"),
158-
("Content-Length", str(len(data)))
159-
] + request.get_cookies())
160-
else:
161-
data = bytes('redirecting ..', 'utf-8')
162-
# Redirection. In order to redirect the response types need to be 302 instead of 200
163-
start_response("302 OK", [
164-
('Location', request.compile_route_to_url())
165-
] + request.get_cookies())
166-
167-
# This will output the data to the browser.
168-
return iter([data])
5+
from wsgi import container
6+
7+
'''
8+
|--------------------------------------------------------------------------
9+
| Startup the Service Container
10+
|--------------------------------------------------------------------------
11+
|
12+
| Instantiate the Service Container so we can bind classes into it and
13+
| bind the environ variable that is created by the WSGI server into
14+
| the container.
15+
|
16+
'''
17+
18+
container.bind('Environ', environ)
19+
20+
'''
21+
|--------------------------------------------------------------------------
22+
| Execute All Service Providers
23+
|--------------------------------------------------------------------------
24+
|
25+
| Run all service provider boot methods if the wsgi attribute is true.
26+
|
27+
'''
28+
29+
for provider in container.make('Application').PROVIDERS:
30+
located_provider = locate(provider)().load_app(container)
31+
if located_provider.wsgi is True:
32+
container.resolve(located_provider.boot)
33+
34+
'''
35+
|--------------------------------------------------------------------------
36+
| We Are Ready For Launch
37+
|--------------------------------------------------------------------------
38+
|
39+
| If we have a solid response and not redirecting then we need to return
40+
| a 200 status code along with the data. If we don't, then we'll have
41+
| to return a 302 and redirect to where the developer would like to
42+
| go next.
43+
|
44+
'''
45+
46+
start_response(container.make('StatusCode'), container.make('Headers'))
47+
48+
'''
49+
|--------------------------------------------------------------------------
50+
| Final Step
51+
|--------------------------------------------------------------------------
52+
|
53+
| This will take the data variable from above and return it to the WSGI
54+
| server.
55+
|
56+
'''
57+
58+
return iter([bytes(container.make('Response'), 'utf-8')])

config/application.py

+24-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import os
2+
13
'''
24
|--------------------------------------------------------------------------
35
| Application Name
@@ -8,7 +10,6 @@
810
| any other location as required by the application or its packages.
911
|
1012
'''
11-
import os
1213

1314
NAME = 'Masonite'
1415

@@ -19,7 +20,7 @@
1920
|
2021
| When your application is in debug mode, detailed error messages with
2122
| stack traces will be shown on every error that occurs within your
22-
| application. If disabled, a simple generic error page is shown.
23+
| application. If disabled, a simple generic error page is shown
2324
|
2425
'''
2526

@@ -31,7 +32,7 @@
3132
|--------------------------------------------------------------------------
3233
|
3334
| This key is used to encrypt and decrypt various values. Out of the box
34-
| Masonite uses this key to encrypt and decrypt cookies but you can use
35+
| Masonite uses this key to encrypt or decrypt cookies so you can use
3536
| it to encrypt and decrypt various values using the Masonite Sign
3637
| class. Read the documentation on Encryption to find out how.
3738
|
@@ -55,17 +56,29 @@
5556
| Providers List
5657
|--------------------------------------------------------------------------
5758
|
58-
| This providers list is used to add functionality to this project. You
59-
| can add modules to this list which will import them when the command
60-
| line is ran. Add modules here with a function which can be picked up
61-
| by the command line. For example: when you add a module with the
62-
| function 'auth' then that function will become available when
63-
| you run: python craft auth
59+
| Providers are a simple way to remove or add functionality for Masonite
60+
| The providers in this list are either ran on server start or when a
61+
| request is made depending on the provider. Take some time to can
62+
| learn more more about Service Providers in our documentation
6463
|
6564
'''
6665

6766
PROVIDERS = [
68-
'app.providers.UserModelProvider.UserModelProvider'
67+
# Framework Providers
68+
'masonite.providers.AppProvider.AppProvider',
69+
'masonite.providers.RouteProvider.RouteProvider',
70+
'masonite.providers.ApiProvider.ApiProvider',
71+
'masonite.providers.RedirectionProvider.RedirectionProvider',
72+
'masonite.providers.StartResponseProvider.StartResponseProvider',
73+
'masonite.providers.SassProvider.SassProvider',
74+
'masonite.providers.WhitenoiseProvider.WhitenoiseProvider',
75+
'masonite.providers.MailProvider.MailProvider',
76+
77+
# Third Party Providers
78+
79+
# Application Providers
80+
'app.providers.UserModelProvider.UserModelProvider',
81+
'app.providers.MiddlewareProvider.MiddlewareProvider',
6982
]
7083

7184
'''
@@ -84,7 +97,7 @@
8497
| Static Root
8598
|--------------------------------------------------------------------------
8699
|
87-
| TODO
100+
| Set the static root of your application that you wil use to store assets
88101
|
89102
'''
90103

config/auth.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
''' Where authentication settings should be'''
1+
''' Authentication Settings '''
2+
23
from app.User import User
34

45
'''

0 commit comments

Comments
 (0)