Coder Social home page Coder Social logo

synapse-base's Introduction

Synapse Base

Build Status

Overview

Synapse Base is a bootstrapping library for PHP applications build in the Silex microframework. It's intended for REST APIs that serve and consume JSON.

This library provides an opinionated, secure starting point for your REST API using the following tools and libraries:

Setting up your Project

Quick Start

For new projects, just clone the API Template as a starting point and composer install.

Expectations of the Library

Architectural Expectations

  1. A MySQL server for app data
  2. A Redis server for job queues

Project Codebase Expectations

(If you just use API Template, you don't need to know most of this.)

  1. Some named constants are expected to exist.
  2. The APP_ENV environment variable should be set. (To development, production, or staging.)
  3. Specific config files should be set up in [APPDIR]/config/. To set up environment-specific configuration overrides, put identical config files in [APPDIR]/config/development/, etc. See API Template for examples.

Setting Up Required Config Files

The default config files contain sufficient documentation in DocBlocks. Just read those.

Database Interaction

Database Installs and Migrations

Use the console utility in API Template to perform DB installs and migrations.

  • Install a clean copy of the database: ./console install:run --drop-tables
  • Create a migration: ./console migrations:create "Add inventory table"
  • Install any migrations that haven't been applied: ./console migrations:run (Or just ./console install:run)
  • Generate a new database install file from the current state of the database: ./console install:generate

When you create a new migration, it's created in [APPDIR]/src/Application/Migrations/. Use the Zend DB Adapter to perform queries like this.

Note about Generating a Database Install File: When you run ./console install:generate, it generates 2 files -- (1) a DbStructure.sql file with the table structure based on the current snapshot of your database, and (2) a DbData.sql file with data from specific tables. Specify which tables in the install config.

How to Read/Write from the Database

Use Mappers like this to perform database queries. Database results are returned as Entities.

Authentication / Login System

bshaffer's OAuth2 server is used for authentication. The user POSTs to /oauth/token with their email/password and receives an access token which can be used to make requests. (Per the OAuth2 specification.)

In order to secure endpoints, the Symfony Security module is used. Firewalls are used to constrain an endpoint to logged in users or to make it public. Access Rules are used to make an endpoint accessible only to users with certain roles. Read the Symfony Security docs for more details.

Notes:

  1. When you specify a listener in a firewall ('anonymous' => true, 'oauth-optional' => true), the code that runs is in the Listeners. (These are added in the OAuth2\SecurityServiceProvider.)
  2. There is a catch-all firewall that constrains all endpoints to be protected by OAuth (non-public) unless specified otherwise. More details here.

Utility Classes

$people = [
    ['name' => 'Linus',   'age' => 10],
    ['name' => 'Brendan', 'age' => 11],
    ['name' => 'Rasmus',  'age' => 12, 'colors' => ['Red', 'Green', 'Blue']],
];

Arr::get($people[0], 'name');     // Linus
Arr::get($people[3], 'name');     // null
Arr::pluck($people, 'name');      // ['Linux', 'Brendan', 'Rasmus'];
Arr::path($people, '2.colors.1'); // Green

Use these to encapsulate concepts and typehint them in your app.

class Car extends DataObject
{
    protected $object = [
        'make'    => null,
        'model'   => null,
        'year'    => null,
        'totaled' => false,
    ];
}

$car = new Car(['make' => 'Toyota']);
$car->setModel('Corolla');
$car->getMake();    // Toyota
$car->getModel();   // Corolla
$car->getYear();    // null
$car->getTotaled(); // false

// These are helpful for typehinting purposes to make your code more robust
function purchaseCar(Car $car) {
    // Do stuff
}

Test Helpers

Various abstract PHPUnit test cases are available for controllers, mappers, etc., to make it easier to test them.

synapse-base's People

Contributors

agerbens avatar areida avatar baohx2000 avatar bjyoungblood avatar bobeagan avatar chrisshiplet avatar dmmcinty avatar paulstatezny avatar pcavagna avatar spruce-bruce avatar tdboone avatar zpchavez avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

synapse-base's Issues

v2: Move Mapper Traits Into AbstractMapper

v2: Move Mapper Traits Into AbstractMapper because they don't provide any extra value by being separated

Acceptance Criteria

  1. All normal mapper traits are moved into AbstractMapper.
  2. Pivot traits are moved into AbstractPivotMapper, which is a child of AbstractMapper.

Tasks

  • Move trait code into AbstractMapper.
  • Move pivot traits into AbstractPivotMapper but find a better name for it. (Tables without an auto-incrementing ID aren't always pivot tables.)
  • Remove use [trait] code from mappers

Additional Notes

  • The original idea for these traits was this: By segmenting them into separate traits, it makes it more difficult to "accidentally" perform an insert/update/delete on tables that our app should never insert/update/delete. The reality: If a developer is going to do something stupid, segmenting the mapper isn't going to stop them.
  • This is a Backwards Compatibility Breaking Change. When it is released into master, major version should be bumped to 2. Dependents must remove use [mapper trait] code from mappers.

Convert existing int timestamp fields to datetimes

Convert existing int timestamp fields to datetimes

Acceptance Criteria

  1. The following columns are auto-updated datetimes
    1. users.created is an auto-updated datetime.
    2. user_tokens.created is an auto-updated datetime.
    3. emails.created is an auto-updated datetime.
    4. emails.updated is an auto-updated datetime.
    5. Anything I may have missed
  2. Task exists for updating the database

Tasks

  • Write upgrade task to change data types (doing so non-destructively will require creating a temporary column, converting existing int timestamps over to it, dropping the original column, and then renaming the temp column to the original name).
  • Change updatedTimestampColumn to updatedDatetimeColumn
  • Change createdTimestampColumn to updatedDatetimeColumn

Additional Notes

  • {{list additional notes here, remove if not applicable}}

Prepend Table Name to Column Names in FinderTrait::findBy() Where Clauses

Prepend Table Name to Column Names in FinderTrait::findBy() Where Clauses

Acceptance Criteria

  1. The findBy() method will prepend the table name to column names in the where clause
  2. If an alias or table name is already included in the column argument (ie, if there is a . character) then do not prepend the table name

Notes

  • Result of a discussion between @paulstatezny, @zpchavez and Aaron. The issue came up because of some joins added to a overwritten mapper. One of the tables joined had a column with an identical name as a column in the base table. Any findBy calls using that column would now fail due to name ambiguity.

Extract Mappers and Entities into separate repo

Extract Mappers and Entities into separate repo

This is an exploratory, "for discussion" issue. The vision for why this may be a good idea can be summed up in a list of pros and cons.

Pros:

  • Changes in the abstract mapper/entity/data-object do not require new releases of Synapse Base.
  • Community members might actually be interested in this as a lightweight database abstraction layer. (More dev community visibility for Synapse.)
  • It is perhaps the only "fully-featured" abstraction in Synapse Base that could logically exist as its own library. Extracting it would make synapse-base more cohesive. It's meant to be a project bootstrapper, not a library in and of itself.
  • Improvements in the Mapper/Entity abstraction could be immediately used in projects without having to update Synapse base. (e.g. Synapse Base master could use MapperAbstraction v1.0, but the Project could separately require MapperAbstraction v1.1 and the latest Synapse Base.)

Cons:

  • "Another repo to manage."

Acceptance Criteria

  1. Mappers, Entities, and the base Data Object are extracted into their own repo.
  2. synapse-base requires them via composer.

Tasks

  • Remove classes/traits and tests from this repo.
  • Create separate repo for it.

Additional Notes

  • Any discussion is encouraged! Drop a note, leave a criticism.

Better error output for migrations

Currently error output in migrations are lacking

Especially for foreign key issues, the error is next to useless.

Acceptance Criteria

  1. Migration errors should output the name of the migration (unless the starting migration log issue gets merged first)
  2. Error should output the actual query being performed to easily find it inside the migration.

Tasks

  • try/catch in RunMigrationsCommand
  • perform output in catch by getting query from PDOException

Additional Notes

  • {{list additional notes here, remove if not applicable}}

Ensure DB set up correctly to use configured charset (which should be utf8mb4)

This wasn't working on another project. The fix specified below did the trick.

Acceptance Criteria

  1. DB should be able to input and output anything you can throw at it.

Tasks

  1. Set up a service provider that does this
$charset = $app['config']->load('db')['charset'];

$app['db']->query("set names {$charset}", DbAdapter::QUERY_MODE_EXECUTE);
$app['db']->query("set character_set_client={$charset}", DbAdapter::QUERY_MODE_EXECUTE);
$app['db']->query("set character_set_connection={$charset}", DbAdapter::QUERY_MODE_EXECUTE);
$app['db']->query("set character_set_results={$charset}", DbAdapter::QUERY_MODE_EXECUTE);
$app['db']->query("set character_set_server={$charset}", DbAdapter::QUERY_MODE_EXECUTE);

Additional Notes

AbstractConsoleWork calls protected function

Description

Synapse\Work\AbstractConsoleWork has a call to a protected property on line 39. Trying to execute a class that extends AbstractConsoleWork causes PHP Fatal error: Call to protected method Synapse\Command\CommandProxy::execute() from context 'Synapse\Work\AbstractConsoleWork' in /vagrant/vendor/synapsestudios/synapse-base/src/Synapse/Work/AbstractConsoleWork.php on line 39

It should be calling run here instead.

Details

  • Expected Result:
  • Actual Result:
  • Steps to Reproduce:
    1. STEPS

Update EmailService to use mapper's getPrototype() method

Update EmailService to use mapper's getPrototype() method

Acceptance Criteria

  1. createFromArray() method will use the entity returned from the mapper's getPrototype() method instead of EmailEntity
  2. The prototype for enqueueSendEmailJob() will require AbstractEntity instead of EmailEntity

Add Token and User ID methods to VerifyRegistration view

Add Token and User ID methods to VerifyRegistration view

Acceptance Criteria

  1. View contains token and userId methods that return the associated data.

Tasks

  • Add methods

Additional Notes

  • This will allow templates to include those variables separately from the URL.

FinderTrait performs table prefixing on findById() calls automatically

As a developer, I don't have to override findById() to explicitly prefix the table name when using JOINs.

Acceptance Criteria

  1. Tests all pass
  2. Doesn't break backwards compatibility
  3. No column name conflicts when using FinderTrait after JOINing two tables with id columns.

Additional Notes

When using a JOIN on two tables that have id columns, using findById can cause errors when trying to look up records by ID. This can be fixed by overriding findById and specifying the table prefix manually. However, since the mapper is aware of the table name already, I don't see a reason it can't add this to the queries automatically. It shouldn't break any existing queries, and it may prevent unexpected behavior.

Any user can get any user's email

Any user can get any user's email

UserController allows any user to make a get request with an ID and get that user's email. Instead, the URI should just be /user and it should return data for the logged in user.

Modify CORS to allow single "Methods" header

Description

Currently, our CORS service injects 2 Access-Control-Allow-Methods headers if there are multiple methods for an endpoint. Hipache inconveniently throws one of them away.

Add a CorsServiceProvider based on the current package, but where it adds the above header, just implode the allowed methods with a comma.

Details

  • Credentials: {{username / password (remove if not applicable)}}
  • URL: {{url where problem occurs, remove if not applicable}}
  • Note: {{relevant information like related issues, remove if not applicable}}
  • Console Error: {{expand and copy from the console (include line error too), remove if not applicable}}

Update connection to use utf8mb4

Update connection to use utf8mb4

Acceptance Criteria

  1. {{list ACs here}}

Tasks

  • {{list developer tasks here}}

Additional Notes

  • {{list additional notes here, remove if not applicable}}

Convenience Function for Mocking Methods

Convenience Function for Mocking Methods

Acceptance Criteria

  1. TestCase::mockMethod exists, and takes the following parameters:
    • Name of mock object (Must be a key in $this->mocks)
    • Name of method (Must be a method of that mock object)
    • Callback to provide to returnCallback

This will transform:

$this->mocks['roleService']->expects($this->any())
    ->method('addRoleForUser')
    ->will($this->returnCallback(function ($user, $role) {
        // Code here
    }));

Into this:

$this->mockMethod('roleService', 'addRoleForUser', function ($user, $role) {
    // Code here
});

Tasks

  • Add method to TestCase

Additional Notes

  • None

Allow creating requests containing file uploads

Allow creating requests containing file uploads

There is currently no readable way of creating requests containing files. We should add a createUploadRequest method to ControllerTestCase.

Additionally, the current createJsonRequest does not allow specifying cookie or server params. Might want to update that while we're at it.

Acceptance Criteria

  1. Dev tested

Tasks

  • Add createRequest method to ControllerTestCase
  • Add createUploadRequest method to ControllerTestCase
  • Probably refactor createJsonRequest to call createRequest

Additional Notes

  • {{list additional notes here, remove if not applicable}}

Command to list routes

It can be useful to easily be able to list all routes in an application

Acceptance Criteria

  1. Command route:list exist
    1. Lists all existing routes in the current application

Tasks

  • {{list developer tasks here}}

Additional Notes

Port api logging into synapse-base

Port api logging into synapse-base

Acceptance Criteria

  1. Service providers can register their endpoints for restricted access logging. Restricted access logging will log events for failed access attempts due to firewall restricts or due to not being logged in.
    • Consider extending the $app->match() function to register endpoints with the logger.
  2. Applications will have a way to register their logging namespaces
  3. A logging service will be available to allow controllers to log using registered namespaces. The service should also allow for a custom message and for passing in context information

Stop Doing SELECT Queries Twice

Stop Doing SELECT Queries Twice

Acceptance Criteria

  1. The FinderTrait is able to get the total result count of a query without re-running it.

Tasks

  • Figure out a way to do this.

Additional Notes

  • Look at FinderTrait::getQueryResultCount. It literally does the SELECT... and then does a separate SELECT count(*). This is way deoptimized.

"Remember Me" Login Feature

As a USER, I can log in with a "remember me" option, and the site will remember that I'm logged in.

Acceptance Criteria

  1. As a USER, I can log in with a "remember me" option, and the site will remember that I'm logged in.

Additional Notes

  • Implement on the front-end with a checkbox to test.

Only accept Response return values in AbstractRestController::execute()

Only accept Response return values in AbstractRestController::execute()

Acceptance Criteria

  1. Exception thrown if return value of a rest method is not a Response object.
  2. Works otherwise.

Tasks

  • Update AbstractRestController.php

Additional Notes

  • {{list additional notes here, remove if not applicable}}

V2: Remove deprecated features

V2: Remove deprecated features

Acceptance Criteria

  1. Deprecated features removed

Tasks

  • Remove createdTimestampColumn and updatedTimestampColumn.

Additional Notes

  • {{list additional notes here, remove if not applicable}}

Port EncryptedMapper into synapse-base

Port EncryptedMapper into synapse-base

Acceptance Criteria

  1. The EncryptionService class and tests will be available in synapse-base
  2. The EncryptedMapper class and tests will be available in synapse-base
  3. The KeyManagement namespace classes will be ported into synapse-base

Notes

  • Review the AwsKeyManagementService and the way AWS credentials are handled. Consider porting the AwsCredentialsService that will check the env for aws credentials. Also consider updating the credentials service to use the Request object instead of the $_SERVER super global.

Extend Symfony & existing synapse constraints

For consistency, all constraints should return a constant-like string for use with i18n

Acceptance Criteria

  1. Extensions of all Symfony constraints exist at \Synapse\Validation\NewConstraints\*
  2. Copies of existing \Synapse\Validator\Constraints\* classes exist in above namespace with constant messages.
  3. Existing \Synapse\Validator\Constraints\* classes marked as deprecated via docblock, with the explanation that upon the next major revision to synapse-base, NewConstraints will become Constraints and the legacy Constraints classes would go away.

Tasks

  • Create synapse-base copies of all the Symfony validator classes with constant-y validation messages
  • Create NewConstraints copies of all synapse-base constraints with constant-y validation messages

Update CHANGELOG

Changelog should reflect versions past 0.2.6

Acceptance Criteria

  1. {{list ACs here}}

Tasks

  • {{list developer tasks here}}

Additional Notes

  • {{list additional notes here, remove if not applicable}}

Fatal Error: Call to undefined method ExecutionContext::getValidator()

Description

I am receiving an error that states Fatal Error (E_ERROR): Call to undefined method Symfony\Component\Validator\ExecutionContext::getValidator() {"file":"/vagrant/vendor/symfony/validator/Symfony/Component/Validator/Constraints/CollectionValidator.php","line":53} []

This may be due to inconsistencies in the way that the different Symfony components are versioned in composer.json.

Details

  • URL / Location:
  • Browser:
  • Credentials:
  • Expected Result:
  • Actual Result:
  • Steps to Reproduce:
    1. STEPS

Fix potential DB dump encoding issue

Fix potential DB dump encoding issue

Currently GenerateInstallCommand creates files by using the > operator to redirect the output of mysqldump to a file. Doing so does not ensure that the file will have the desired encoding. We should instead use the option --result-file=filename.sql to ensure that the file has the correct encoding.

http://makandracards.com/makandra/595-dumping-and-importing-from-to-mysql-in-an-utf-8-safe-way
http://nathan.rambeck.org/blog/1-preventing-encoding-issues-mysqldump

DataObject:getArrayCopy should be recursive

Issue: currently entity responses do not render child objects

Acceptance Criteria

  1. entities with child entities render the child entities (and child's children, ad infinatum)

Tasks

  • {{list developer tasks here}}

Additional Notes

  • {{list additional notes here, remove if not applicable}}

Error thrown when access rules are violated

Description

When a request violates the access rules (set in the service provider), an AccessDeniedHttpException is thrown and the request is cancelled. This should return some kind of 403 response instead, maybe with some kind of message.

FinderTrait addWheres() assumes 'IS' and 'IS NOT' operators will be followed by null

Description

In the FinderTrait's addWheres() function, if the operator is either IS or IS NOT it automatically creates IsNull or IsNotNull predicates, assuming that the user wants to check for null.

IS and IS NOT can also be used to check boolean values.
https://dev.mysql.com/doc/refman/5.1/en/comparison-operators.html#operator_is

Details

https://github.com/synapsestudios/synapse-base/blob/master/src/Synapse/Mapper/FinderTrait.php#L298

Add File-based functionality (service & controllers)

Applications need a way to upload, save, and retrieve files

Acceptance Criteria

  1. Services exist to save to either S3 or local filesystem based on configuration
  2. Unit tested
  3. Optional integration unit tests
  4. Abstract controller
  5. Abstract mapper (concrete mapper & controllers will be created for specific file types)
  6. Schema stub or cli command to create table

Tasks

  • {{list developer tasks here}}

Additional Notes

  • {{list additional notes here, remove if not applicable}}

Refactor AbstractMapper to eliminate object instantiation

Refactor AbstractMapper to eliminate object instantiation

The sql() method instantiates a Zend\Db\Sql\Sql object. For testability, perhaps use an inject factory class instead with a getSqlObject method on it.

While it's true we'll only be moving the instantiation from the mapper to the factory, the factory will be very simple and won't need testing, whereas mappers are more complicated

Acceptance Criteria

  1. None

Tasks

  • None

Additional Notes

  • None

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.