Giter VIP home page Giter VIP logo

silverstripe-populate's Introduction

Populate Module

Build Status

This module provides a way to populate a database from YAML fixtures and custom classes. For instance, when a building a web application the pages and default objects can be defined in YAML and shared around developers. This extends the requireDefaultRecords concept in SilverStripe's DataModel.

Requirements

Installation Instructions

This module must only ever be used in your development environment, and should never be used on production. While there is code to prevent it from being run in production, it is not fool-proof and therefore you must never run this module in production. Install it as a dev dependency in composer like so:

composer require --dev dnadesign/silverstripe-populate

Setup

First create a new yml config file in your config directory app/_config/populate.yml (or add it to an existing config.yml file if you prefer).

DNADesign\Populate\Populate:
  include_yaml_fixtures:
    - 'app/fixtures/populate.yml'

If you're sharing test setup with populate, you can specify any number of paths to load fixtures from.

An example app/fixtures/populate.yml might look like the following:

Page:
  home:
    Title: "Home"
    Content: "My Home Page"
    ParentID: 0
SilverStripe\Security\Member:
  admin:
    ID: 1
    Email: "[email protected]"
    PopulateMergeMatch:
      - 'ID'
      - 'Email'

Out of the box, the records will be created on when you run the PopulateTask through /dev/tasks/PopulateTask/. To make it completely transparent to developers during the application build, you can also include this to hook in on requireDefaultRecords as part of dev/build by including the following in one of your application models requireDefaultRecords methods:

use DNADesign\Populate\Populate;

class Page extends SiteTree
{
    public function requireDefaultRecords()
    {
        parent::requireDefaultRecords();
        Populate::requireRecords();
    }
}

Configuration options

include_yaml_fixtures

An array of YAML files to parse.

mysite/_config/app.yml

DNADesign\Populate\Populate:
  include_yaml_fixtures:
    - 'app/fixtures/populate.yml'

truncate_objects

An array of ClassName's whose instances are to be removed from the database prior to importing. Useful to prevent multiple copies of populated content from being imported. It's recommended to truncate any objects you create, to ensure you can re-run PopulateTask as often as you want during development and get a consistent database state. This supports Versioned objects (like SiteTree) and Fluent (if the module is installed).

DNADesign\Populate\Populate:
  truncate_objects:
    - Page
    - SilverStripe\Assets\Image

truncate_tables

An array of tables to be truncated. Useful when there's no relation between your populated classes and the table you want truncated

DNADesign\Populate\Populate:
  truncate_tables:
    - Image_Special_Table

See Updating Records if you wish to merge new and old records rather than clearing all of them.

YAML Format

Populate uses the same FixtureFactory setup as SilverStripe's unit testing framework. The basic structure of which is:

ClassName:
  somereference:
    FieldName: "Value"

Relations are handled by referring to them by their reference value:

SilverStripe\Security\Member:
    admin:
      Email: "[email protected]"

Page:
  homepage:
    AuthorID: =>SilverStripe\Security\Member.admin

See SilverStripe's fixture documentation for more advanced examples, including $many_many and $many_many_extraFields.

Any object which implements the Versioned extension will be automatically published.

Basic PHP operations can also be included in the YAML file. Any line that is wrapped in a ` character and ends with a semi colon will be evaled in the current scope of the importer.

Page:
  mythankyoupage:
    ThankYouText: "`Page::config()->thank_you_text`;"
    LinkedPage: "`sprintf(\"[Page](%s)\", App\\Page\\HelpPage::get()->first()->Link())`;"

Updating Records

If you do not truncate the entire table, the module will attempt to first look up an existing record and update that existing record. For this to happen the YAML must declare the fields to match in the look up. You can use several options for this.

PopulateMergeWhen

Contains a WHERE clause to match e.g "URLSegment = 'home' AND ParentID = 0".

Mysite\PageTypes\HomePage:
  home:
    Title: "My awesome homepage"
    PopulateMergeWhen: "URLSegment = 'home' AND ParentID = 0"

PopulateMergeMatch

Takes a list of fields defined in the YAML and matches them based on the database to avoid repeating content

Mysite\PageTypes\HomePage:
  home:
    Title: "My awesome homepage"
    URLSegment: 'home'
    ParentID: 0
    PopulateMergeMatch:
      - URLSegment
      - ParentID

PopulateMergeAny

Takes the first record in the database and merges with that. This option is suitable for things like SiteConfig where you normally only contain a single record.

SilverStripe\SiteConfig\SiteConfig:
  mysiteconfig:
    Tagline: "SilverStripe is awesome"
    PopulateMergeAny: true

If the criteria meets more than 1 instance, all instances bar the first are removed from the database so ensure you criteria is specific enough to get the unique field value.

Default Assets

The script also handles creating default File and image records through the PopulateFileFrom flag. This copies the file from another path (say mysite) and puts the file inside your assets folder.

SilverStripe\Assets\Image:
  lgoptimusl3ii:
    Filename: assets/shop/lgoptimusl3ii.png
    PopulateFileFrom: app/images/demo/large.png

Mysite\PageTypes\Product:
  lgoptimus:
    ProductImage: =>SilverStripe\Assets\Image.lgoptimusl3ii

Extensions

The module also provides extensions that can be opted into depending on your project needs

PopulateMySQLExport

This extension outputs the result of the Populate::requireDefaultRecords() as a SQL Dump on your local machine. This speeds up the process if using Populate as part of a test suite or some other CI service as instead of manually calling the task (which will use the ORM) your test case can be fed raw MySQL to import and hopefully speed up execution times.

To apply the extension add it to Populate, configure the path, flush, then run dev/tasks/PopulateTask

DNADesign\Populate\PopulateMySQLExportExtension:
  export_db_path: ~/path.sql

DNADesign\Populate\Populate:
  extensions
    - DNADesign\Populate\PopulateMySQLExportExtension

Publish configuration

By default the module uses publishSingle() to publish records. If, for whatever reason, you would prefer to that the module uses publishRecursive(), you can enable this by settings the following configuration:

DNADesign\Populate\Populate:
  enable_publish_recursive: true

Allow Populate to run on "live" environments

DANGER ZONE: Please understand that you are about to provide admins with the ability to run Populate on your production environment. Before setting this configuration you should understand and accept the risks related to the loss of production data.

DNADesign\Populate\Populate:
  allow_build_on_live: true

Credits

silverstripe-populate was originally created by wilr and DNA Design.

silverstripe-populate's People

Contributors

anselmdk avatar catharsisjelly avatar chrispenny avatar dhensby avatar emteknetnz avatar madmatt avatar michalkleiner avatar satrun77 avatar scott1702 avatar silverstripe-elliot avatar wernerkrauss avatar wilr avatar zauberfisch avatar

Stargazers

 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

Watchers

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

silverstripe-populate's Issues

How can i create a translation?

How can i create a translation with Translatable using populate? I mean, that it also generates the right entry in the translation_groups table...

Images cause error when repeatedly running populate task.

Version 2.1.0

Relevant portion of my yml

SilverStripe\Assets\Image:
  imageOne:
    Created: "1970-01-02 03:04:05"
    Filename: assets/TestContent/imageBlockOne.jpg
    PopulateFileFrom: app/fixtures/assets/546-900x600.jpg
    PopulateMergeMatch:
      - Created

App\Elements\ImageElement:
  imageBlockOne:
    Title: Image Element
    ShowTitle: true
    Created: "1970-01-02 03:04:05"
    ImageID: =>SilverStripe\Assets\Image.imageOne
    ParentID: =>DNADesign\Elemental\Models\ElementalArea.imageArea
    PopulateMergeMatch:
      - Created

This runs fine the first time, but on the second pass creating the image results in the following:

[Notice] Trying to get property 'ID' of non-object
Line 72 in /var/www/html/vendor/dnadesign/silverstripe-populate/code/PopulateFactory.php

And then attempting to reference the image results in:

[Emergency] Uncaught InvalidArgumentException: No fixture definitions found for "=>SilverStripe\Assets\Image.imageOne"
Line 332 in /var/www/html/vendor/silverstripe/framework/src/Dev/FixtureBlueprint.php

Populate $many_many_extraFields

Hey,

Just wondering if this is possible...

class MyPage extends Page
{
    private static $many_many = [
        'MyDataObjects' => 'MyDataObject',
    ];

    private static $many_many_extraFields = [
        'MyDataObjects' => [
            'MyField' => 'Int',
        ],
    ];
}

Given the above, is there a way to populate MyField using a fixture?

increas Maximum execution time

Fatal error: Maximum execution time of 30 seconds exceeded in /vagrant/www/framework/model/Database.php on line 870

How about increasing the execution time using set_time_limit() ?

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/9947550-increas-maximum-execution-time?utm_campaign=plugin&utm_content=tracker%2F668165&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F668165&utm_medium=issues&utm_source=github).

PopulateMergeMatch does not work as expected

I expected to be able to update/merge existing records using PopulateMergeMatch as described in the documentation based. I've written a simple example like follows:

_config/config.yml

Member:
  test:
    Email: "[email protected]"
    Password: "password"
    PopulateMergeMatch:
      - Email

I expected the Populate task to merge with the existing record on consecutive runs of the populate task but it throws a validation error:

ERROR [User Error]: Uncaught ValidationException: Can't overwrite existing member #1 with identical identifier (Email = [email protected]))
IN GET /dev/tasks/PopulateTask
Line 852 in framework/security/Member.php

I've posted the sample-project here https://github.com/nebucaz/sspopulate


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

PopulateMergeMatch with HasOne?

Might be this might be more of a feature request than an issue: I tried to define a PopulateMergeMatch using ForeignKey Fields, but it did not work. I tried the following yams-code (Mandant & Plan are separate Objects)

Contract:
  bronze:
    Start: '2016-01-01 00:00:00'
    End: '9999-12-31 23:59:59'
    Mandant: =>Mandant.default
    Plan: =>Plan.test
    PopulateMergeMatch:
      - Plan
      - Mandant

This throws a n SQL-Error Unknown column 'Plan' in 'where clause' because there is no such column in the Database. Changing the merge-fields to database-Columns like this:

PopulateMergeMatch:
  - PlanID
  - MandantID

yields a php runtime error of ERROR [Notice]: Undefined index: MandantIDbecause this field is not found in the yams definition. I can not use
PopulateMergeWhen: "MandantID = =>Mandant.default AND PlanID = =>Plan.test"
because the yaml -references will not be replaced with the real values.

Any idea how to achieve this?


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

Add a note that 3.1.3 is required

I've run into this on 2 projects.
When creating new pages, the module expects getversionedstages to exist, which was only added in 3.1.3. Might be a good idea to add it to the docs?

Subsites compatibility

Hey,

I've run into an issue using populate with subsites.

Each subsite is able to have pages with the same URL segment, for example:

mainsite.com/home
mysubsite.com/home

Populate handles URL segment collisions like the CMS does, by prefixing the page id, so you get home-2 on the subsite URL segment.

Here's a example populate.yml

Subsite:
  MySubsite:
    Title: 'My Subsite'
    Theme: 'mysubsite'

SubsiteDomain:
  MySubsiteDomain:
    Domain: 'mysubsite.com'
    Protocol: 'automatic'
    Subsite: =>Subsite.MySubsite

Page:
  Home:
    ParentID: 0
    ShowInMenus: false
    Title: 'Home'
    URLSegment: 'home'
  SubsiteHome:
    ParentID: 0
    ShowInMenus: false
    Title: 'Home'
    URLSegment: 'home'
   Subsite: =>Subsite.MySubsite

I'm currently working around this by creating an DataExtension on Populate and updating the records manually.

class PopulateExtension extends DataExtension
{
    public function onAfterPopulateRecords()
    {
        // Do stuff
    }
}

Is there a way I can populate pages across subsites without having to use the onAfterPopulateRecords hook?

Thanks


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

Release/Tag for SS4

Please, please, can the latest master be tagged with a new release tag, e.g. 2.0.0? :-)

Locations of populated images are not recognized by the CMS

I've started using the "Default assets". I love the concept, though it seems images that are placed in a directory are not properly picked up by the CMS.

It takes for me to sync assets via the cms for this to happen. See screenshots of the issue:

Image appears in the root of assets - with no title:
screenshot 2014-03-11 22 08 10

Even though it should have appeared in this directory (that's also where it's placed):
screenshot 2014-03-11 22 08 23

Initially I thought I could fix this by adding the following to PopulateFactory.php before returning the object, as to my knowledge that's what needs to be triggered, it's not working though, so I'm a little lost:

//making sure to update file system after adding/editing files and images
if(isset($data['PopulateFileFrom'])) {
    $obj->updateFilesystem();
}

This is my yml:

Image:
  demo3a:
    Filename: assets/immodb/demos/demo3a.jpg
    PopulateFileFrom: immodb/images/demos/demo3/3761870901_953b1c54c9_b.jpg
    PopulateMergeMatch:
      - Filename

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/8466846-locations-of-populated-images-are-not-recognized-by-the-cms?utm_campaign=plugin&utm_content=tracker%2F668165&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F668165&utm_medium=issues&utm_source=github).

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.